UNPKG

babel-helper-decorate-react

Version:
194 lines (193 loc) 7.52 kB
var __rest = (this && this.__rest) || function (s, e) { var t = {}; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) t[p] = s[p]; if (s != null && typeof Object.getOwnPropertySymbols === "function") for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) { if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) t[p[i]] = s[p[i]]; } return t; }; import * as types from '@babel/types'; import tpl from '@babel/template'; import { addDefault, addNamespace } from '@babel/helper-module-imports'; import parseCommentsRanges from './parseCommentsRanges'; import { isScopeDepthPassed } from './utils'; export class RangesHelper { constructor(opts) { this.opts = opts; this.cache = new Map(); } getLocation(path) { var _a; let loc = path.node.loc; let tmp = path; while (!loc && tmp) { // @ts-ignore tmp = tmp.getPrevSibling(); if (!(tmp === null || tmp === void 0 ? void 0 : tmp.node)) { tmp = tmp.parentPath; } loc = (_a = tmp === null || tmp === void 0 ? void 0 : tmp.node) === null || _a === void 0 ? void 0 : _a.loc; } return loc; } eval(content) { return `__$$EVAL%%${content}%%__`; } matched(path) { return this.getEnableOptions(this.getLocation(path).start.line); } inject(path, transformData) { let { matched, data } = this.matched(path); if (!matched) { return false; } if (!this.cache.get(path.node)) { this.cache.set(path.node, []); } const decorated = this.cache.get(path.node); if (decorated.includes(this.opts.libPath)) { return path.skip(); } decorated.push(this.opts.libPath); let importName = this.importName; if (!importName) { const moduleInteropPath = this.opts.moduleInteropPath; if (this.opts.importType === 'namespace') { this.importName = addNamespace(path, this.opts.libPath, { nameHint: 'decorate' }); } else { this.importName = addDefault(path, this.opts.libPath, { nameHint: 'decorate' }); } if (moduleInteropPath) { const moduleInterop = addDefault(path, moduleInteropPath); this.importName = types.callExpression(moduleInterop, [this.importName]); } importName = this.importName; } else { importName = types.cloneDeep(this.importName); } // this.importName if (transformData) { data = transformData(data, path, this); } let dataExp = tpl.expression(JSON.stringify(data || null).replace(/"__\$\$EVAL%%(.*?)%%__"/g, '$1'))(); if ('ClassDeclaration' === path.node.type) { path.node.decorators = path.node.decorators || []; path.node.decorators.push(types.decorator(types.callExpression(importName, [dataExp]))); } else { // @ts-ignore path.replaceWith(types.callExpression(types.callExpression(importName, [dataExp]), [path.node])); } } getEnableOptions(line) { for (const r of this.ranges) { if (r.type === 'disable') { if (r.has(line)) { return { matched: false, data: null }; } } if (r.has(line)) { return { matched: true, data: r.data }; } } return { matched: this.opts.defaultEnable, data: null }; } } class WalkApi { constructor() { this.statusList = new Set(); } addStatus(s) { return this.statusList.add(s); } removeStatus(s) { return this.statusList.delete(s); } hasStatus(s) { return this.statusList.has(s); } noSkip(f = true) { f ? this.addStatus('noSkip') : this.removeStatus('noSkip'); } wrap(f = true) { f ? this.addStatus('wrap') : this.removeStatus('wrap'); } } function createDecorateVisitor(_a = {}) { var { prefix = 'decorate', decorateLibPath, moduleInteropPath = require.resolve('module-interop'), visitorTypes = ['FunctionExpression', 'ArrowFunctionExpression', 'ClassExpression', 'ClassDeclaration'], deepVisitorTypes = visitorTypes, exportVisitorTypes = ['ExportDefaultDeclaration', 'ExportNamedDeclaration'], defaultEnable = true, transformData, importType = 'default', detectScopeDepth = -1 } = _a, opts = __rest(_a, ["prefix", "decorateLibPath", "moduleInteropPath", "visitorTypes", "deepVisitorTypes", "exportVisitorTypes", "defaultEnable", "transformData", "importType", "detectScopeDepth"]); if (!prefix) { throw new Error('`prefix` is required'); } if (!decorateLibPath) { throw new Error('`decorateLibPath` is required'); } const reduceVisitors = (types) => types.reduce((acc, name) => { if (typeof name === 'string') { acc[name] = function (path, { helper }) { if (isScopeDepthPassed(path, detectScopeDepth)) { helper.inject(path); } path.skip(); }; } else { acc[name.type] = function (path, { helper }) { var _a; const transform = name.transformData || transformData; const walkApi = new WalkApi(); let rlt; if (isScopeDepthPassed(path, detectScopeDepth)) { if (!name.condition) { helper.inject(path, (data) => (transform ? transform(data, path, helper.babelPass, helper) : data)); } else if (((_a = helper.matched(path)) === null || _a === void 0 ? void 0 : _a.matched) && (rlt = name.condition(path, helper.babelPass, helper, walkApi)) && rlt === true) { helper.inject(walkApi.hasStatus('wrap') ? path.parentPath : path, (data) => transform ? transform(data, path, helper.babelPass, helper) : data); } } if (!walkApi.hasStatus('noSkip')) { path.skip(); } }; } return acc; }, {}); const deepVisitors = reduceVisitors(deepVisitorTypes); const _visitors = reduceVisitors(visitorTypes); let exportVisitors = exportVisitorTypes.reduce((acc, name) => { acc[name] = function (path, state) { path.traverse(deepVisitors, state); path.skip(); }; return acc; }, {}); return { Program(path) { const helper = new RangesHelper({ importType, moduleInteropPath, libPath: decorateLibPath, defaultEnable }); helper.babelPass = this; helper.ranges = parseCommentsRanges(path.container.comments, Object.assign({ prefix }, opts)); path.traverse(Object.assign(Object.assign({}, _visitors), exportVisitors), { helper }); } }; } export default createDecorateVisitor;