babel-plugin-mobx-observer-on-every-react-component
Advanced tools
Comparing version
"use strict"; | ||
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { | ||
if (k2 === undefined) k2 = k; | ||
var desc = Object.getOwnPropertyDescriptor(m, k); | ||
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { | ||
desc = { enumerable: true, get: function() { return m[k]; } }; | ||
} | ||
Object.defineProperty(o, k2, desc); | ||
}) : (function(o, m, k, k2) { | ||
if (k2 === undefined) k2 = k; | ||
o[k2] = m[k]; | ||
})); | ||
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { | ||
Object.defineProperty(o, "default", { enumerable: true, value: v }); | ||
}) : function(o, v) { | ||
o["default"] = v; | ||
}); | ||
var __importStar = (this && this.__importStar) || function (mod) { | ||
if (mod && mod.__esModule) return mod; | ||
var result = {}; | ||
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); | ||
__setModuleDefault(result, mod); | ||
return result; | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const helper_plugin_utils_1 = require("@babel/helper-plugin-utils"); | ||
const t = __importStar(require("@babel/types")); | ||
exports.default = (0, helper_plugin_utils_1.declare)((api, options) => { | ||
@@ -21,5 +45,4 @@ var _a; | ||
const specifiers = path.node.specifiers; | ||
observerImported = specifiers.some(spec => | ||
// @ts-expect-error | ||
t.isImportSpecifier(spec) && spec.imported.name === 'observer'); | ||
observerImported = specifiers.some(spec => t.isImportSpecifier(spec) && | ||
(spec.imported.type === 'Identifier' && spec.imported.name === 'observer')); | ||
} | ||
@@ -35,4 +58,3 @@ }, | ||
const existingImport = path.node.body.find(node => t.isImportDeclaration(node) && node.source.value === 'mobx-react'); | ||
if (existingImport) { | ||
// @ts-expect-error | ||
if (existingImport && t.isImportDeclaration(existingImport)) { | ||
existingImport.specifiers.push(t.importSpecifier(t.identifier('observer'), t.identifier('observer'))); | ||
@@ -46,5 +68,3 @@ } | ||
if (!hasReactComponent) { | ||
debug( | ||
// @ts-expect-error | ||
`no react components in this file ${path.hub.file.opts.filename}`, debugEnabled); | ||
debug(`no react components in this file ${state.filename}`, debugEnabled); | ||
} | ||
@@ -56,4 +76,3 @@ }, | ||
} | ||
// @ts-expect-error | ||
debug(`arrow function expression ${path.hub.file.opts.filename}`, debugEnabled); | ||
debug(`arrow function expression ${state.filename}`, debugEnabled); | ||
if (isReactComponent(path)) { | ||
@@ -181,25 +200,23 @@ debug("is react component", debugEnabled); | ||
function isInNodeModules(state) { | ||
const filename = state.file.opts.filename; | ||
return filename && filename.includes("node_modules"); | ||
const filename = state.filename; | ||
return !!(filename && filename.includes("node_modules")); | ||
} | ||
function isWrappedInObserver(path) { | ||
// If this class is on the right hand side of an assignment expression, | ||
// check to see if that assignment expression is a call expression to observer | ||
// which we can know from the parent of the parentPath | ||
if (path.parentPath.node.type === "AssignmentExpression") { | ||
if (path.parentPath.parentPath.node.type === "CallExpression" && path.parentPath.parentPath.node.callee.name === "observer") { | ||
const parent = path.parentPath; | ||
if (parent && t.isAssignmentExpression(parent.node)) { | ||
const grandParent = parent.parentPath; | ||
if (grandParent && t.isCallExpression(grandParent.node) && t.isIdentifier(grandParent.node.callee) && grandParent.node.callee.name === 'observer') { | ||
return true; | ||
} | ||
} | ||
return (path.parentPath.node.type === "CallExpression" && | ||
path.parentPath.node.callee.name === "observer"); | ||
return (t.isCallExpression(parent === null || parent === void 0 ? void 0 : parent.node) && | ||
t.isIdentifier(parent.node.callee) && | ||
parent.node.callee.name === 'observer'); | ||
} | ||
function isDecoratedWithObserver(path) { | ||
return (path.node.decorators && | ||
return !!(path.node.decorators && | ||
path.node.decorators.length > 0 && | ||
// @ts-expect-errork | ||
path.node.decorators.some(decorator => decorator.expression.type === 'Identifier' && | ||
path.node.decorators.some((decorator) => decorator.expression.type === 'Identifier' && | ||
decorator.expression.name === 'observer')); | ||
} | ||
// @ts-expect-error | ||
function wrapClassDeclarationInObserver(path, t) { | ||
@@ -216,3 +233,2 @@ const classExpression = t.classExpression(path.node.id, path.node.superClass, path.node.body, path.node.decorators); | ||
} | ||
// @ts-expect-error | ||
function wrapClassExpressionInObserver(path, t) { | ||
@@ -222,10 +238,5 @@ const classExpression = t.classExpression(path.node.id, path.node.superClass, path.node.body, path.node.decorators); | ||
const observerFunction = t.callExpression(t.identifier("observer"), [classExpression]); | ||
// Create a variable declaration with the observer-wrapped class | ||
const variableDeclaration = t.variableDeclaration("const", [ | ||
t.variableDeclarator(path.node.id, observerFunction) | ||
]); | ||
// Replace the ClassDeclaration with the observer() wrapped version | ||
path.replaceWith(observerFunction); | ||
} | ||
// @ts-expect-error | ||
function isReactComponent(path) { | ||
@@ -249,15 +260,15 @@ if (path.node.type === "ArrowFunctionExpression") { | ||
} | ||
// @ts-expect-error | ||
function doesReturnJSX(body) { | ||
if (!body) | ||
return false; | ||
if (body.type === "JSXElement" || body.type === "JSXFragment") { | ||
if (t.isJSXElement(body) || t.isJSXFragment(body)) { | ||
return true; | ||
} | ||
var block = body.body; | ||
if (block && block.length) { | ||
var lastBlock = block.slice(0).pop(); | ||
if (lastBlock.type === "ReturnStatement") { | ||
return (lastBlock.argument !== null && | ||
(lastBlock.argument.type === "JSXElement" || lastBlock.argument.type === "JSXFragment")); | ||
if (t.isBlockStatement(body)) { | ||
const statements = body.body; | ||
if (statements.length > 0) { | ||
const lastStatement = statements[statements.length - 1]; | ||
if (t.isReturnStatement(lastStatement) && lastStatement.argument) { | ||
return t.isJSXElement(lastStatement.argument) || t.isJSXFragment(lastStatement.argument); | ||
} | ||
} | ||
@@ -267,3 +278,2 @@ } | ||
} | ||
// @ts-expect-error | ||
function classHasRenderMethod(path) { | ||
@@ -273,5 +283,5 @@ if (!path.node.body) { | ||
} | ||
var members = path.node.body.body; | ||
for (var i = 0; i < members.length; i++) { | ||
if (members[i].type === "ClassMethod" && members[i].key.name === "render") { | ||
const members = path.node.body.body; | ||
for (const member of members) { | ||
if (t.isClassMethod(member) && t.isIdentifier(member.key) && member.key.name === "render") { | ||
return true; | ||
@@ -278,0 +288,0 @@ } |
import { declare } from "@babel/helper-plugin-utils"; | ||
import * as t from '@babel/types'; | ||
export default declare((api, options) => { | ||
@@ -19,5 +20,4 @@ var _a; | ||
const specifiers = path.node.specifiers; | ||
observerImported = specifiers.some(spec => | ||
// @ts-expect-error | ||
t.isImportSpecifier(spec) && spec.imported.name === 'observer'); | ||
observerImported = specifiers.some(spec => t.isImportSpecifier(spec) && | ||
(spec.imported.type === 'Identifier' && spec.imported.name === 'observer')); | ||
} | ||
@@ -33,4 +33,3 @@ }, | ||
const existingImport = path.node.body.find(node => t.isImportDeclaration(node) && node.source.value === 'mobx-react'); | ||
if (existingImport) { | ||
// @ts-expect-error | ||
if (existingImport && t.isImportDeclaration(existingImport)) { | ||
existingImport.specifiers.push(t.importSpecifier(t.identifier('observer'), t.identifier('observer'))); | ||
@@ -44,5 +43,3 @@ } | ||
if (!hasReactComponent) { | ||
debug( | ||
// @ts-expect-error | ||
`no react components in this file ${path.hub.file.opts.filename}`, debugEnabled); | ||
debug(`no react components in this file ${state.filename}`, debugEnabled); | ||
} | ||
@@ -54,4 +51,3 @@ }, | ||
} | ||
// @ts-expect-error | ||
debug(`arrow function expression ${path.hub.file.opts.filename}`, debugEnabled); | ||
debug(`arrow function expression ${state.filename}`, debugEnabled); | ||
if (isReactComponent(path)) { | ||
@@ -179,25 +175,23 @@ debug("is react component", debugEnabled); | ||
function isInNodeModules(state) { | ||
const filename = state.file.opts.filename; | ||
return filename && filename.includes("node_modules"); | ||
const filename = state.filename; | ||
return !!(filename && filename.includes("node_modules")); | ||
} | ||
function isWrappedInObserver(path) { | ||
// If this class is on the right hand side of an assignment expression, | ||
// check to see if that assignment expression is a call expression to observer | ||
// which we can know from the parent of the parentPath | ||
if (path.parentPath.node.type === "AssignmentExpression") { | ||
if (path.parentPath.parentPath.node.type === "CallExpression" && path.parentPath.parentPath.node.callee.name === "observer") { | ||
const parent = path.parentPath; | ||
if (parent && t.isAssignmentExpression(parent.node)) { | ||
const grandParent = parent.parentPath; | ||
if (grandParent && t.isCallExpression(grandParent.node) && t.isIdentifier(grandParent.node.callee) && grandParent.node.callee.name === 'observer') { | ||
return true; | ||
} | ||
} | ||
return (path.parentPath.node.type === "CallExpression" && | ||
path.parentPath.node.callee.name === "observer"); | ||
return (t.isCallExpression(parent === null || parent === void 0 ? void 0 : parent.node) && | ||
t.isIdentifier(parent.node.callee) && | ||
parent.node.callee.name === 'observer'); | ||
} | ||
function isDecoratedWithObserver(path) { | ||
return (path.node.decorators && | ||
return !!(path.node.decorators && | ||
path.node.decorators.length > 0 && | ||
// @ts-expect-errork | ||
path.node.decorators.some(decorator => decorator.expression.type === 'Identifier' && | ||
path.node.decorators.some((decorator) => decorator.expression.type === 'Identifier' && | ||
decorator.expression.name === 'observer')); | ||
} | ||
// @ts-expect-error | ||
function wrapClassDeclarationInObserver(path, t) { | ||
@@ -214,3 +208,2 @@ const classExpression = t.classExpression(path.node.id, path.node.superClass, path.node.body, path.node.decorators); | ||
} | ||
// @ts-expect-error | ||
function wrapClassExpressionInObserver(path, t) { | ||
@@ -220,10 +213,5 @@ const classExpression = t.classExpression(path.node.id, path.node.superClass, path.node.body, path.node.decorators); | ||
const observerFunction = t.callExpression(t.identifier("observer"), [classExpression]); | ||
// Create a variable declaration with the observer-wrapped class | ||
const variableDeclaration = t.variableDeclaration("const", [ | ||
t.variableDeclarator(path.node.id, observerFunction) | ||
]); | ||
// Replace the ClassDeclaration with the observer() wrapped version | ||
path.replaceWith(observerFunction); | ||
} | ||
// @ts-expect-error | ||
function isReactComponent(path) { | ||
@@ -247,15 +235,15 @@ if (path.node.type === "ArrowFunctionExpression") { | ||
} | ||
// @ts-expect-error | ||
function doesReturnJSX(body) { | ||
if (!body) | ||
return false; | ||
if (body.type === "JSXElement" || body.type === "JSXFragment") { | ||
if (t.isJSXElement(body) || t.isJSXFragment(body)) { | ||
return true; | ||
} | ||
var block = body.body; | ||
if (block && block.length) { | ||
var lastBlock = block.slice(0).pop(); | ||
if (lastBlock.type === "ReturnStatement") { | ||
return (lastBlock.argument !== null && | ||
(lastBlock.argument.type === "JSXElement" || lastBlock.argument.type === "JSXFragment")); | ||
if (t.isBlockStatement(body)) { | ||
const statements = body.body; | ||
if (statements.length > 0) { | ||
const lastStatement = statements[statements.length - 1]; | ||
if (t.isReturnStatement(lastStatement) && lastStatement.argument) { | ||
return t.isJSXElement(lastStatement.argument) || t.isJSXFragment(lastStatement.argument); | ||
} | ||
} | ||
@@ -265,3 +253,2 @@ } | ||
} | ||
// @ts-expect-error | ||
function classHasRenderMethod(path) { | ||
@@ -271,5 +258,5 @@ if (!path.node.body) { | ||
} | ||
var members = path.node.body.body; | ||
for (var i = 0; i < members.length; i++) { | ||
if (members[i].type === "ClassMethod" && members[i].key.name === "render") { | ||
const members = path.node.body.body; | ||
for (const member of members) { | ||
if (t.isClassMethod(member) && t.isIdentifier(member.key) && member.key.name === "render") { | ||
return true; | ||
@@ -276,0 +263,0 @@ } |
{ | ||
"name": "babel-plugin-mobx-observer-on-every-react-component", | ||
"version": "0.1.11", | ||
"version": "0.1.12", | ||
"description": "Wrap literally every React component in an MobX observer higher order component.", | ||
"keywords": [ | ||
"babel-plugin", | ||
"mobx" | ||
"mobx", | ||
"mobx-react", | ||
"react", | ||
"observer", | ||
"babel" | ||
], | ||
@@ -44,3 +48,3 @@ "homepage": "https://github.com/coolsoftwaretyler/babel-plugin-mobx-observer-on-every-react-component", | ||
"clean": "rimraf dist", | ||
"build": "npm run clean && npm run build:cjs && npm run build:esm", | ||
"build": "bun run clean && bun run build:cjs && bun run build:esm", | ||
"build:cjs": "tsc --module commonjs --outDir dist && mv dist/index.js dist/index.cjs.js", | ||
@@ -47,0 +51,0 @@ "build:esm": "tsc --module es2015 --outDir dist && mv dist/index.js dist/index.esm.js" |
116
src/index.ts
import { declare } from "@babel/helper-plugin-utils"; | ||
import { Decorator } from '@babel/types'; | ||
import { NodePath } from '@babel/core'; | ||
import * as t from '@babel/types'; | ||
import { PluginPass } from '@babel/core'; | ||
@@ -7,6 +11,8 @@ interface PluginOptions { | ||
type BabelTypes = typeof import('@babel/types'); | ||
export default declare((api, options?: PluginOptions ) => { | ||
const debugEnabled = options?.debugEnabled ?? false; | ||
const t = api.types; | ||
return { | ||
@@ -28,4 +34,4 @@ name: "babel-plugin-mobx-observer-on-every-react-component", | ||
observerImported = specifiers.some(spec => | ||
// @ts-expect-error | ||
t.isImportSpecifier(spec) && spec.imported.name === 'observer' | ||
t.isImportSpecifier(spec) && | ||
(spec.imported.type === 'Identifier' && spec.imported.name === 'observer') | ||
); | ||
@@ -37,3 +43,3 @@ } | ||
) { | ||
if (isReactComponent(path)) { | ||
if (isReactComponent(path as NodePath<t.ArrowFunctionExpression | t.FunctionDeclaration | t.FunctionExpression | t.ClassDeclaration | t.ClassExpression>)) { | ||
hasReactComponent = true; | ||
@@ -48,5 +54,3 @@ } | ||
); | ||
if (existingImport) { | ||
// @ts-expect-error | ||
if (existingImport && t.isImportDeclaration(existingImport)) { | ||
existingImport.specifiers.push( | ||
@@ -66,4 +70,3 @@ t.importSpecifier(t.identifier('observer'), t.identifier('observer')) | ||
debug( | ||
// @ts-expect-error | ||
`no react components in this file ${path.hub.file.opts.filename}`, | ||
`no react components in this file ${state.filename}`, | ||
debugEnabled | ||
@@ -79,4 +82,3 @@ ); | ||
// @ts-expect-error | ||
debug(`arrow function expression ${path.hub.file.opts.filename}`, debugEnabled); | ||
debug(`arrow function expression ${state.filename}`, debugEnabled); | ||
@@ -86,3 +88,3 @@ if (isReactComponent(path)) { | ||
// Check to see if this is already wrapped in observer | ||
if (isWrappedInObserver(path)) { | ||
if (isWrappedInObserver(path as NodePath<t.ArrowFunctionExpression>)) { | ||
debug("already wrapped in observer", debugEnabled); | ||
@@ -116,3 +118,3 @@ return; | ||
// Check to see if this is already wrapped in observer | ||
if (isWrappedInObserver(path)) { | ||
if (isWrappedInObserver(path as NodePath<t.ClassDeclaration>)) { | ||
debug( | ||
@@ -158,3 +160,3 @@ `already wrapped in observer ${path.node.id?.name ?? "Anonymous"}`, | ||
// Check to see if this is already wrapped in observer | ||
if (isWrappedInObserver(path)) { | ||
if (isWrappedInObserver(path as NodePath<t.ClassExpression>)) { | ||
debug( | ||
@@ -280,31 +282,28 @@ `already wrapped in observer ${path.node.id?.name ?? "Anonymous"}`, | ||
function isInNodeModules(state: any) { | ||
const filename = state.file.opts.filename; | ||
return filename && filename.includes("node_modules"); | ||
function isInNodeModules(state: PluginPass): boolean { | ||
const filename = state.filename; | ||
return !!(filename && filename.includes("node_modules")) | ||
} | ||
function isWrappedInObserver(path: any) { | ||
// If this class is on the right hand side of an assignment expression, | ||
// check to see if that assignment expression is a call expression to observer | ||
// which we can know from the parent of the parentPath | ||
if (path.parentPath.node.type === "AssignmentExpression") { | ||
if (path.parentPath.parentPath.node.type === "CallExpression" && path.parentPath.parentPath.node.callee.name === "observer") { | ||
return true | ||
function isWrappedInObserver(path: NodePath<t.ArrowFunctionExpression | t.FunctionDeclaration | t.FunctionExpression | t.ClassDeclaration | t.ClassExpression>): boolean { | ||
const parent = path.parentPath; | ||
if (parent && t.isAssignmentExpression(parent.node)) { | ||
const grandParent = parent.parentPath; | ||
if (grandParent && t.isCallExpression(grandParent.node) && t.isIdentifier(grandParent.node.callee) && grandParent.node.callee.name === 'observer') { | ||
return true; | ||
} | ||
} | ||
return ( | ||
path.parentPath.node.type === "CallExpression" && | ||
path.parentPath.node.callee.name === "observer" | ||
t.isCallExpression(parent?.node) && | ||
t.isIdentifier(parent.node.callee) && | ||
parent.node.callee.name === 'observer' | ||
); | ||
} | ||
function isDecoratedWithObserver(path: any) { | ||
return ( | ||
function isDecoratedWithObserver(path: NodePath<t.ClassDeclaration | t.ClassExpression>): boolean { | ||
return !!( | ||
path.node.decorators && | ||
path.node.decorators.length > 0 && | ||
// @ts-expect-errork | ||
path.node.decorators.some(decorator => | ||
path.node.decorators.some((decorator: Decorator) => | ||
decorator.expression.type === 'Identifier' && | ||
@@ -316,4 +315,3 @@ decorator.expression.name === 'observer' | ||
// @ts-expect-error | ||
function wrapClassDeclarationInObserver(path, t) { | ||
function wrapClassDeclarationInObserver(path: NodePath<t.ClassDeclaration>, t: BabelTypes) { | ||
const classExpression = t.classExpression( | ||
@@ -334,3 +332,3 @@ path.node.id, | ||
const variableDeclaration = t.variableDeclaration("const", [ | ||
t.variableDeclarator(path.node.id, observerFunction) | ||
t.variableDeclarator(path.node.id as t.Identifier, observerFunction) | ||
]); | ||
@@ -343,4 +341,3 @@ | ||
// @ts-expect-error | ||
function wrapClassExpressionInObserver(path, t) { | ||
function wrapClassExpressionInObserver(path: NodePath<t.ClassExpression>, t: BabelTypes) { | ||
const classExpression = t.classExpression( | ||
@@ -359,8 +356,2 @@ path.node.id, | ||
// Create a variable declaration with the observer-wrapped class | ||
const variableDeclaration = t.variableDeclaration("const", [ | ||
t.variableDeclarator(path.node.id, observerFunction) | ||
]); | ||
// Replace the ClassDeclaration with the observer() wrapped version | ||
@@ -371,4 +362,3 @@ path.replaceWith(observerFunction); | ||
// @ts-expect-error | ||
function isReactComponent(path ) { | ||
function isReactComponent(path: NodePath<t.ArrowFunctionExpression | t.FunctionDeclaration | t.FunctionExpression | t.ClassDeclaration | t.ClassExpression>): boolean { | ||
if (path.node.type === "ArrowFunctionExpression") { | ||
@@ -384,6 +374,6 @@ return doesReturnJSX(path.node.body); | ||
if (path.node.type === "ClassDeclaration") { | ||
return classHasRenderMethod(path); | ||
return classHasRenderMethod(path as NodePath<t.ClassDeclaration>); | ||
} | ||
if (path.node.type === "ClassExpression") { | ||
return classHasRenderMethod(path); | ||
return classHasRenderMethod(path as NodePath<t.ClassExpression>); | ||
} | ||
@@ -394,18 +384,15 @@ | ||
// @ts-expect-error | ||
function doesReturnJSX(body) { | ||
function doesReturnJSX(body: t.BlockStatement | t.Expression): boolean { | ||
if (!body) return false; | ||
if (body.type === "JSXElement" || body.type === "JSXFragment") { | ||
if (t.isJSXElement(body) || t.isJSXFragment(body)) { | ||
return true; | ||
} | ||
var block = body.body; | ||
if (block && block.length) { | ||
var lastBlock = block.slice(0).pop(); | ||
if (lastBlock.type === "ReturnStatement") { | ||
return ( | ||
lastBlock.argument !== null && | ||
(lastBlock.argument.type === "JSXElement" || lastBlock.argument.type === "JSXFragment") | ||
); | ||
if (t.isBlockStatement(body)) { | ||
const statements = body.body; | ||
if (statements.length > 0) { | ||
const lastStatement = statements[statements.length - 1]; | ||
if (t.isReturnStatement(lastStatement) && lastStatement.argument) { | ||
return t.isJSXElement(lastStatement.argument) || t.isJSXFragment(lastStatement.argument); | ||
} | ||
} | ||
@@ -417,10 +404,9 @@ } | ||
// @ts-expect-error | ||
function classHasRenderMethod(path) { | ||
function classHasRenderMethod(path: NodePath<t.ClassDeclaration | t.ClassExpression>): boolean { | ||
if (!path.node.body) { | ||
return false; | ||
} | ||
var members = path.node.body.body; | ||
for (var i = 0; i < members.length; i++) { | ||
if (members[i].type === "ClassMethod" && members[i].key.name === "render") { | ||
const members = path.node.body.body; | ||
for (const member of members) { | ||
if (t.isClassMethod(member) && t.isIdentifier(member.key) && member.key.name === "render") { | ||
return true; | ||
@@ -433,3 +419,3 @@ } | ||
function debug(message: string, debugEnabled: boolean) { | ||
function debug(message: string, debugEnabled: boolean): void { | ||
if (debugEnabled) { | ||
@@ -436,0 +422,0 @@ console.log(message); |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
No README
QualityPackage does not have a README. This may indicate a failed publish or a low quality package.
Found 1 instance in 1 package
45806
5.63%6
50%1
-50%35
Infinity%0
-100%901
-1.31%