babel-preset-dlight
Advanced tools
Comparing version 1.0.0-alpha.0 to 1.0.0-alpha.1
1353
dist/index.js
@@ -1,1353 +0,2 @@ | ||
var __defProp = Object.defineProperty; | ||
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; | ||
var __publicField = (obj, key, value) => { | ||
__defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value); | ||
return value; | ||
}; | ||
// src/index.ts | ||
import syntaxTypescript from "babel-plugin-syntax-typescript-new"; | ||
import syntaxDecorators from "@babel/plugin-syntax-decorators"; | ||
// src/pluginProvider.ts | ||
import { minimatch } from "minimatch"; | ||
import { parseView } from "@dlightjs/view-parser"; | ||
import { parseReactivity } from "@dlightjs/reactivity-parser"; | ||
import { generateSubView, generateView } from "@dlightjs/view-generator"; | ||
var devMode = process.env.NODE_ENV === "development"; | ||
var _PluginProvider = class { | ||
dlightPackageName = _PluginProvider.dlightDefaultPackageName; | ||
// ---- Plugin Level | ||
babelApi; | ||
t; | ||
traverse; | ||
enableDevTools; | ||
includes; | ||
excludes; | ||
htmlTags; | ||
constructor(babelApi, types, includes, excludes, enableDevTools, htmlTags) { | ||
this.babelApi = babelApi; | ||
this.t = types; | ||
this.traverse = babelApi.traverse; | ||
this.includes = includes; | ||
this.excludes = excludes; | ||
this.enableDevTools = devMode && enableDevTools; | ||
this.htmlTags = typeof htmlTags === "function" ? htmlTags(_PluginProvider.defaultHTMLTags) : htmlTags.includes("*") ? [ | ||
.../* @__PURE__ */ new Set([..._PluginProvider.defaultHTMLTags, ...htmlTags]) | ||
].filter((tag) => tag !== "*") : htmlTags; | ||
} | ||
// ---- DLight class Level | ||
classRootPath; | ||
classDeclarationNode; | ||
classBodyNode; | ||
constructorNode; | ||
propertiesContainer = {}; | ||
dependencyMap = {}; | ||
enter = true; | ||
enterClassNode = false; | ||
className; | ||
// ---- File Level | ||
programNode; | ||
allImports = []; | ||
didAlterImports = false; | ||
/* ---- DLight Class Level Hooks ---- */ | ||
/** | ||
* @brief Clear all DLight Node Level variables after a class is transformed | ||
*/ | ||
clearNode() { | ||
this.classRootPath = void 0; | ||
this.classDeclarationNode = void 0; | ||
this.classBodyNode = void 0; | ||
this.constructorNode = void 0; | ||
this.propertiesContainer = {}; | ||
this.dependencyMap = {}; | ||
this.enter = true; | ||
this.enterClassNode = false; | ||
this.allImports = []; | ||
this.didAlterImports = false; | ||
this.className = void 0; | ||
} | ||
get availableProperties() { | ||
return Object.entries(this.propertiesContainer).filter( | ||
([key, { isWatcher, isStatic, isChildren }]) => key !== "_$compName" && !isWatcher && !isStatic && !isChildren | ||
).map(([key]) => key); | ||
} | ||
/** | ||
* @brief Initialize DLight Node Level variables when entering a class | ||
* @param path | ||
*/ | ||
initNode(path) { | ||
this.classRootPath = path; | ||
const node = path.node; | ||
this.classDeclarationNode = node; | ||
this.classBodyNode = node.body; | ||
this.propertiesContainer = {}; | ||
if (!node.id?.name) { | ||
node.id = this.t.identifier(`Anonymous_${_PluginProvider.uid()}`); | ||
} | ||
this.className = node.id?.name; | ||
this.handleClassCustomDecorators(); | ||
if (this.enableDevTools) { | ||
this.classBodyNode.body.unshift( | ||
this.t.classProperty( | ||
this.t.identifier("_$compName"), | ||
this.t.stringLiteral(this.className) | ||
) | ||
); | ||
} | ||
this.addConstructor(); | ||
if (!this.didAlterImports) { | ||
const dlightImports = this.allImports.filter( | ||
(n) => n.source.value === _PluginProvider.dlightDefaultPackageName | ||
); | ||
if (this.dlightPackageName !== _PluginProvider.dlightDefaultPackageName) { | ||
dlightImports.forEach((i) => { | ||
i.source.value = this.dlightPackageName; | ||
}); | ||
} | ||
this.programNode.body.unshift( | ||
this.t.importDeclaration( | ||
Object.entries(_PluginProvider.importMap).map( | ||
([key, value]) => this.t.importSpecifier( | ||
this.t.identifier(value), | ||
this.t.identifier(key) | ||
) | ||
), | ||
this.t.stringLiteral(this.dlightPackageName) | ||
) | ||
); | ||
this.didAlterImports = true; | ||
} | ||
} | ||
handleClassCustomDecorators() { | ||
if (!this.classBodyNode) | ||
return; | ||
const decorators = this.classDeclarationNode?.decorators; | ||
if (!decorators) | ||
return; | ||
const forwardPropDeco = this.findDecoratorByName(decorators, "ForwardProps"); | ||
if (forwardPropDeco) { | ||
this.classBodyNode.body.unshift( | ||
this.t.classProperty(this.t.identifier("_$forwardProps")), | ||
this.t.classProperty( | ||
this.t.identifier("_$forwardPropsSet"), | ||
this.t.newExpression(this.t.identifier("Set"), []) | ||
), | ||
this.t.classProperty( | ||
this.t.identifier("_$forwardPropsId"), | ||
this.t.arrayExpression([]) | ||
) | ||
); | ||
this.classDeclarationNode.decorators = this.removeDecorators( | ||
decorators, | ||
["ForwardProps"] | ||
); | ||
} | ||
} | ||
/** | ||
* @brief Transform the whole DLight class when exiting the class | ||
* 1. Alter all the state properties | ||
* 2. Transform MainView and SubViews with DLight syntax | ||
*/ | ||
transformDLightClass() { | ||
const usedProperties = this.handleView(); | ||
const propertyArr = Object.entries(this.propertiesContainer).reverse(); | ||
const depReversedMap = this.dependencyMapReversed(); | ||
for (const [ | ||
key, | ||
{ node, deps, isStatic, isChildren, isPropOrEnv, isWatcher, isContent } | ||
] of propertyArr) { | ||
if (isChildren) { | ||
this.resolveChildrenDecorator(node); | ||
continue; | ||
} | ||
if (deps.length > 0) { | ||
usedProperties.push(...deps); | ||
if (isWatcher) | ||
this.resolveWatcherDecorator(node); | ||
else | ||
this.handleDerivedProperty(node); | ||
} | ||
if (isPropOrEnv) { | ||
this.resolvePropDecorator(node, isPropOrEnv); | ||
} | ||
if (isContent) { | ||
this.resolvePropDecorator(node, "Prop"); | ||
this.resolveContentDecorator(node); | ||
} | ||
if (isStatic) | ||
continue; | ||
if (usedProperties.includes(key)) { | ||
this.resolveStateDecorator( | ||
node, | ||
this.availableProperties.indexOf(key), | ||
depReversedMap[key] | ||
); | ||
} | ||
} | ||
} | ||
/* ---- DLight Class View Handlers ---- */ | ||
/** | ||
* @brief Transform Body and SubViews with DLight syntax | ||
* @returns used properties | ||
*/ | ||
handleView() { | ||
if (!this.classBodyNode) | ||
return []; | ||
const usedPropertySet = /* @__PURE__ */ new Set(); | ||
let mainView; | ||
const subViewNodes = []; | ||
for (let viewNode of this.classBodyNode.body) { | ||
if (!this.t.isClassProperty(viewNode) && !this.t.isClassMethod(viewNode)) | ||
continue; | ||
if (!this.t.isIdentifier(viewNode.key)) | ||
continue; | ||
const isSubView = this.findDecoratorByName(viewNode.decorators, "View"); | ||
const isMainView = viewNode.key.name === "View"; | ||
if (!isSubView && !isMainView) | ||
continue; | ||
if (this.t.isClassProperty(viewNode)) { | ||
let exp = viewNode.value; | ||
while (this.t.isTSAsExpression(exp)) | ||
exp = exp.expression; | ||
if (!this.t.isArrowFunctionExpression(viewNode.value)) | ||
continue; | ||
viewNode.value = exp; | ||
const newViewNode = this.arrowFunctionPropertyToMethod(viewNode); | ||
if (!newViewNode) | ||
continue; | ||
viewNode = newViewNode; | ||
} | ||
if (isSubView) { | ||
viewNode.decorators = null; | ||
subViewNodes.push(viewNode); | ||
} else { | ||
mainView = viewNode; | ||
} | ||
} | ||
const subViewNames = subViewNodes.map((v) => v.key.name); | ||
const subViewPropSubDepMap = Object.fromEntries( | ||
subViewNodes.map((v) => { | ||
const prop = v.params[0]; | ||
if (!prop || !this.t.isObjectPattern(prop)) | ||
return ["-", null]; | ||
const props = Object.fromEntries( | ||
prop.properties.map((p) => { | ||
if (!this.t.isObjectProperty(p)) | ||
return ["-", null]; | ||
const key = p.key.name; | ||
const subDeps = this.getIdentifiers( | ||
this.t.assignmentExpression( | ||
"=", | ||
this.t.objectPattern([ | ||
this.t.objectProperty(this.t.numericLiteral(0), p.value) | ||
]), | ||
this.t.numericLiteral(0) | ||
) | ||
).filter((v2) => v2 !== key); | ||
return [key, subDeps]; | ||
}).filter(([_, props2]) => props2) | ||
); | ||
return [v.key.name, props]; | ||
}).filter(([_, props]) => props) | ||
); | ||
let templateIdx = -1; | ||
if (mainView) { | ||
let usedProperties2; | ||
[usedProperties2, templateIdx] = this.alterMainView( | ||
mainView, | ||
subViewNames, | ||
subViewPropSubDepMap | ||
); | ||
usedProperties2.forEach(usedPropertySet.add.bind(usedPropertySet)); | ||
} | ||
subViewNodes.forEach((viewNode) => { | ||
let usedProperties2; | ||
[usedProperties2, templateIdx] = this.alterSubView( | ||
viewNode, | ||
subViewNames, | ||
subViewPropSubDepMap, | ||
templateIdx | ||
); | ||
usedProperties2.forEach(usedPropertySet.add.bind(usedPropertySet)); | ||
}); | ||
const usedProperties = []; | ||
this.availableProperties.forEach((p) => { | ||
if (usedPropertySet.has(p)) | ||
usedProperties.push(p); | ||
}); | ||
return usedProperties; | ||
} | ||
/** | ||
* @brief Transform Views with DLight syntax | ||
* @param viewNode | ||
* @param subViewNames | ||
* @param isSubView | ||
* @returns Used properties | ||
*/ | ||
alterMainView(viewNode, subViewNames, subViewPropSubDepMap) { | ||
const viewUnits = parseView(viewNode.body, { | ||
babelApi: this.babelApi, | ||
subviewNames: subViewNames, | ||
htmlTags: this.htmlTags | ||
}); | ||
const [viewParticles, usedPropertySet] = parseReactivity(viewUnits, { | ||
babelApi: this.babelApi, | ||
availableProperties: this.availableProperties, | ||
dependencyMap: this.dependencyMap | ||
}); | ||
const [body, classProperties, templateIdx] = generateView(viewParticles, { | ||
babelApi: this.babelApi, | ||
className: this.className, | ||
importMap: _PluginProvider.importMap, | ||
subViewPropMap: Object.fromEntries( | ||
Object.entries(subViewPropSubDepMap).map(([key, props]) => [ | ||
key, | ||
Object.keys(props) | ||
]) | ||
), | ||
templateIdx: -1 | ||
}); | ||
viewNode.body = body; | ||
this.classBodyNode?.body.push(...classProperties); | ||
return [usedPropertySet, templateIdx]; | ||
} | ||
alterSubView(viewNode, subViewNames, subViewPropSubDepMap, templateIdx) { | ||
const viewUnits = parseView(viewNode.body, { | ||
babelApi: this.babelApi, | ||
subviewNames: subViewNames, | ||
htmlTags: this.htmlTags | ||
}); | ||
const [viewParticlesProperty, usedPropertySet] = parseReactivity( | ||
viewUnits, | ||
{ | ||
babelApi: this.babelApi, | ||
availableProperties: this.availableProperties, | ||
dependencyMap: this.dependencyMap | ||
} | ||
); | ||
const subViewProp = subViewPropSubDepMap[viewNode.key.name] ?? []; | ||
const identifierDepMap = {}; | ||
Object.entries(subViewProp).forEach(([key, subDeps]) => { | ||
subDeps.forEach((dep) => { | ||
identifierDepMap[dep] = [key]; | ||
}); | ||
}); | ||
const [viewParticlesIdentifier] = parseReactivity(viewUnits, { | ||
babelApi: this.babelApi, | ||
availableProperties: Object.keys(subViewProp), | ||
dependencyMap: this.dependencyMap, | ||
dependencyParseType: "identifier", | ||
identifierDepMap | ||
}); | ||
const subViewPropMap = Object.fromEntries( | ||
Object.entries(subViewPropSubDepMap).map(([key, props]) => [ | ||
key, | ||
Object.keys(props) | ||
]) | ||
); | ||
const [body, classProperties, newTemplateIdx] = generateSubView( | ||
viewParticlesProperty, | ||
viewParticlesIdentifier, | ||
viewNode.params[0], | ||
{ | ||
babelApi: this.babelApi, | ||
className: this.className, | ||
importMap: _PluginProvider.importMap, | ||
subViewPropMap, | ||
templateIdx | ||
} | ||
); | ||
viewNode.body = body; | ||
this.classBodyNode?.body.push(...classProperties); | ||
return [usedPropertySet, newTemplateIdx]; | ||
} | ||
/* ---- Babel Visitors ---- */ | ||
visitProgram(_path) { | ||
} | ||
programVisitor(path, filename) { | ||
this.enter = this.fileAllowed(filename); | ||
if (!this.enter) | ||
return; | ||
this.allImports = path.node.body.filter( | ||
(n) => this.t.isImportDeclaration(n) | ||
); | ||
const dlightImports = this.allImports.filter( | ||
(n) => n.source.value === _PluginProvider.dlightDefaultPackageName | ||
); | ||
if (dlightImports.length === 0) { | ||
this.enter = false; | ||
return; | ||
} | ||
this.programNode = path.node; | ||
this.visitProgram(path); | ||
} | ||
enterClass(_path) { | ||
} | ||
classEnter(path) { | ||
if (!this.enter) | ||
return; | ||
this.enterClassNode = this.isDLightView(path); | ||
if (!this.enterClass) | ||
return; | ||
this.initNode(path); | ||
this.enterClass(path); | ||
} | ||
exitClass(_path) { | ||
} | ||
classExit(path) { | ||
if (!this.enter) | ||
return; | ||
if (!this.enterClassNode) | ||
return; | ||
this.transformDLightClass(); | ||
this.addInit(); | ||
this.exitClass(path); | ||
this.clearNode(); | ||
this.enterClassNode = false; | ||
} | ||
visitClassMethod(_path) { | ||
} | ||
classMethodVisitor(path) { | ||
if (!this.enterClassNode) | ||
return; | ||
if (!this.t.isIdentifier(path.node.key)) | ||
return; | ||
const key = path.node.key.name; | ||
if (key === "View") | ||
return; | ||
const isSubView = this.findDecoratorByName(path.node.decorators, "View"); | ||
if (isSubView) | ||
return; | ||
const node = path.node; | ||
const watchDeco = this.findDecoratorByName(node.decorators, "Watch"); | ||
if (!watchDeco) { | ||
if (this.t.isIdentifier(node.key, { name: "constructor" })) | ||
return; | ||
this.autoBindMethods(node); | ||
return; | ||
} | ||
let deps = []; | ||
if (this.t.isIdentifier(watchDeco)) { | ||
deps = this.getDependencies(path); | ||
} else { | ||
const listenDeps = watchDeco.arguments[0]; | ||
if (this.t.isArrayExpression(listenDeps)) { | ||
deps = listenDeps.elements.filter((arg) => this.t.isStringLiteral(arg)).map((arg) => arg.value); | ||
deps = [...new Set(deps)]; | ||
} | ||
} | ||
this.propertiesContainer[key] = { | ||
node, | ||
deps, | ||
isWatcher: true | ||
}; | ||
node.decorators = this.removeDecorators(node.decorators, ["Watch"]); | ||
this.visitClassMethod(path); | ||
} | ||
visitClassProperty(_path) { | ||
} | ||
classPropertyVisitor(path) { | ||
if (!this.enterClassNode) | ||
return; | ||
const node = path.node; | ||
if (!this.t.isIdentifier(node.key)) | ||
return; | ||
const key = node.key.name; | ||
if (key === "View") | ||
return; | ||
const decorators = node.decorators; | ||
const isSubView = this.findDecoratorByName(decorators, "View"); | ||
if (isSubView) | ||
return; | ||
const isProp = !!this.findDecoratorByName(decorators, "Prop"); | ||
const isEnv = !!this.findDecoratorByName(decorators, "Env"); | ||
const isChildren = !!this.findDecoratorByName(node.decorators, "Children"); | ||
const deps = !isChildren ? this.getDependencies(path) : []; | ||
this.propertiesContainer[key] = { | ||
node, | ||
deps, | ||
isStatic: !!this.findDecoratorByName(decorators, "Static"), | ||
isContent: !!this.findDecoratorByName(decorators, "Content"), | ||
isChildren, | ||
isPropOrEnv: isProp ? "Prop" : isEnv ? "Env" : void 0 | ||
}; | ||
node.decorators = this.removeDecorators( | ||
decorators, | ||
_PluginProvider.availableDecoNames | ||
); | ||
this.visitClassProperty(path); | ||
} | ||
/* ---- Decorator Resolvers ---- */ | ||
/** | ||
* @brief Decorator resolver: Watcher | ||
* Add: | ||
* $wW${key} | ||
* @param node | ||
*/ | ||
resolveWatcherDecorator(node) { | ||
if (!this.t.isIdentifier(node.key)) | ||
return; | ||
const key = node.key.name; | ||
const propertyIdx = this.classBodyNode.body.indexOf(node); | ||
const watcherNode = this.t.classProperty(this.t.identifier(`$w$${key}`)); | ||
this.classBodyNode.body.splice(propertyIdx, 0, watcherNode); | ||
} | ||
/** | ||
* @brief Decorator resolver: Children | ||
* Add: | ||
* get ${key}() { | ||
* return this._$children | ||
* } | ||
* @param node | ||
*/ | ||
resolveChildrenDecorator(node) { | ||
if (!this.classBodyNode) | ||
return; | ||
if (!this.t.isIdentifier(node.key)) | ||
return; | ||
const key = node.key.name; | ||
const propertyIdx = this.classBodyNode.body.indexOf(node); | ||
const childrenFuncCallNode = this.t.memberExpression( | ||
this.t.thisExpression(), | ||
this.t.identifier("_$children") | ||
); | ||
const getterNode = this.t.classMethod( | ||
"get", | ||
this.t.identifier(key), | ||
[], | ||
this.t.blockStatement([this.t.returnStatement(childrenFuncCallNode)]) | ||
); | ||
this.classBodyNode.body.splice(propertyIdx, 1, getterNode); | ||
} | ||
/** | ||
* @brief Decorator resolver: Content | ||
* Add: | ||
* _$contentKey = "key" | ||
* @param node | ||
*/ | ||
resolveContentDecorator(node) { | ||
if (!this.classBodyNode) | ||
return; | ||
if (!this.t.isIdentifier(node.key)) | ||
return; | ||
if (this.classBodyNode.body.some( | ||
(n) => this.t.isClassProperty(n) && n.key.name === "_$contentKey" | ||
)) | ||
return; | ||
const key = node.key.name; | ||
const propertyIdx = this.classBodyNode.body.indexOf(node); | ||
const derivedStatusKey = this.t.classProperty( | ||
this.t.identifier("_$contentKey"), | ||
this.t.stringLiteral(key) | ||
); | ||
this.classBodyNode.body.splice(propertyIdx, 0, derivedStatusKey); | ||
} | ||
/** | ||
* @brief Decorator resolver: Prop/Env | ||
* Add: | ||
* $p/e$${key} | ||
* @param node | ||
*/ | ||
resolvePropDecorator(node, decoratorName) { | ||
if (!this.classBodyNode) | ||
return; | ||
if (!this.t.isIdentifier(node.key)) | ||
return; | ||
const key = node.key.name; | ||
const propertyIdx = this.classBodyNode.body.indexOf(node); | ||
const tag = decoratorName.toLowerCase() === "prop" ? "p" : "e"; | ||
const derivedStatusKey = this.t.classProperty( | ||
this.t.identifier(`$${tag}$${key}`) | ||
); | ||
this.classBodyNode.body.splice(propertyIdx, 0, derivedStatusKey); | ||
} | ||
/** | ||
* @brief Decorator resolver: State | ||
* Add: | ||
* $${key} = ${value} | ||
* $$${key} = ${depIdx} | ||
* $sub$${key} = [${reversedDeps}] | ||
* get ${key}() { | ||
* return this.$${key} | ||
* } | ||
* set ${key}(value) { | ||
* this._$updateProp("${key}", value) | ||
* } | ||
* @param node | ||
*/ | ||
resolveStateDecorator(node, idx, reverseDeps) { | ||
if (!this.classBodyNode) | ||
return; | ||
if (!this.t.isIdentifier(node.key)) | ||
return; | ||
const key = node.key.name; | ||
node.key.name = `$${key}`; | ||
const propertyIdx = this.classBodyNode.body.indexOf(node); | ||
const idxNode = this.t.classProperty( | ||
this.t.identifier(`$$${key}`), | ||
this.t.numericLiteral(1 << idx) | ||
); | ||
const depsNode = reverseDeps ? [ | ||
this.t.classProperty( | ||
this.t.identifier(`$s$${key}`), | ||
this.t.arrayExpression( | ||
[...reverseDeps].map((d) => this.t.stringLiteral(d)) | ||
) | ||
) | ||
] : []; | ||
const getterNode = this.t.classMethod( | ||
"get", | ||
this.t.identifier(key), | ||
[], | ||
this.t.blockStatement([ | ||
this.t.returnStatement( | ||
this.t.memberExpression( | ||
this.t.thisExpression(), | ||
this.t.identifier(`$${key}`) | ||
) | ||
) | ||
]) | ||
); | ||
const setterNode = this.t.classMethod( | ||
"set", | ||
this.t.identifier(key), | ||
[this.t.identifier("value")], | ||
this.t.blockStatement([ | ||
this.t.expressionStatement( | ||
this.t.callExpression( | ||
this.t.memberExpression( | ||
this.t.thisExpression(), | ||
this.t.identifier("_$updateProp") | ||
), | ||
[this.t.stringLiteral(key), this.t.identifier("value")] | ||
) | ||
) | ||
]) | ||
); | ||
this.classBodyNode.body.splice( | ||
propertyIdx + 1, | ||
0, | ||
idxNode, | ||
...depsNode, | ||
getterNode, | ||
setterNode | ||
); | ||
} | ||
/* ---- Helper Functions ---- */ | ||
/** | ||
* @brief Test if the file is allowed to be transformed | ||
* @param fileName | ||
* @returns is file allowed | ||
*/ | ||
fileAllowed(fileName) { | ||
if (this.includes.includes("*")) | ||
return true; | ||
if (!fileName) | ||
return false; | ||
if (this.excludes.some((pattern) => minimatch(fileName, pattern))) | ||
return false; | ||
if (!this.includes.some((pattern) => minimatch(fileName, pattern))) | ||
return false; | ||
return true; | ||
} | ||
/** | ||
* @brief Test if the class is a dlight view | ||
* @param path | ||
* @returns | ||
*/ | ||
isDLightView(path) { | ||
const node = path.node; | ||
const decorators = node.decorators ?? []; | ||
const isDecorator = decorators.find( | ||
(deco) => this.t.isIdentifier(deco.expression, { name: "View" }) | ||
); | ||
if (isDecorator) { | ||
node.superClass = this.t.identifier("View"); | ||
node.decorators = node.decorators?.filter( | ||
(deco) => !this.t.isIdentifier(deco.expression, { name: "View" }) | ||
); | ||
} | ||
return this.t.isIdentifier(node.superClass, { name: "View" }); | ||
} | ||
/** | ||
* @brief Remove decorators by name | ||
* Only search for Identifier and CallExpression, e.g, @Ok, @Ok() | ||
* @param decorators | ||
* @param names | ||
* @returns new decorators | ||
*/ | ||
removeDecorators(decorators, names) { | ||
if (!decorators) | ||
return []; | ||
return decorators.filter( | ||
(d) => !(this.t.isIdentifier(d.expression) && names.includes(d.expression.name) || this.t.isCallExpression(d.expression) && this.t.isIdentifier(d.expression.callee) && names.includes(d.expression.callee.name)) | ||
); | ||
} | ||
/** | ||
* @brief Find decorator by name, | ||
* Only search for Identifier and CallExpression, e.g, @Ok, @Ok() | ||
* @param decorators | ||
* @param name | ||
* @returns Identifier or CallExpression or nothing | ||
*/ | ||
findDecoratorByName(decorators, name) { | ||
if (!decorators) | ||
return; | ||
return decorators.find( | ||
(deco) => this.t.isIdentifier(deco.expression, { name }) || this.t.isCallExpression(deco.expression) && this.t.isIdentifier(deco.expression.callee, { name }) | ||
)?.expression; | ||
} | ||
/** | ||
* constructor(props, content, children, forwardPropsScope) { | ||
* super() | ||
* } | ||
*/ | ||
addConstructor() { | ||
if (!this.classBodyNode) | ||
return; | ||
let constructor = this.classBodyNode.body.find( | ||
(n) => this.t.isClassMethod(n, { kind: "constructor" }) | ||
); | ||
if (constructor) | ||
throw new Error("DLight class should not have constructor"); | ||
constructor = this.t.classMethod( | ||
"constructor", | ||
this.t.identifier("constructor"), | ||
[ | ||
this.t.identifier("props"), | ||
this.t.identifier("content"), | ||
this.t.identifier("children"), | ||
this.t.identifier("forwardPropsScope") | ||
], | ||
this.t.blockStatement([ | ||
this.t.expressionStatement(this.t.callExpression(this.t.super(), [])) | ||
]) | ||
); | ||
this.constructorNode = constructor; | ||
this.classBodyNode.body.unshift(constructor); | ||
} | ||
addInit() { | ||
this.constructorNode.body.body.push( | ||
this.t.expressionStatement( | ||
this.t.callExpression( | ||
this.t.memberExpression( | ||
this.t.thisExpression(), | ||
this.t.identifier("_$init") | ||
), | ||
[ | ||
this.t.identifier("props"), | ||
this.t.identifier("content"), | ||
this.t.identifier("children"), | ||
this.t.identifier("forwardPropsScope") | ||
] | ||
) | ||
) | ||
); | ||
} | ||
autoBindMethods(node) { | ||
this.constructorNode.body.body.push( | ||
this.t.expressionStatement( | ||
this.t.assignmentExpression( | ||
"=", | ||
this.t.memberExpression(this.t.thisExpression(), node.key), | ||
this.t.callExpression( | ||
this.t.memberExpression( | ||
this.t.memberExpression(this.t.thisExpression(), node.key), | ||
this.t.identifier("bind") | ||
), | ||
[this.t.thisExpression()] | ||
) | ||
) | ||
) | ||
); | ||
} | ||
/** | ||
* ${key} = ${value} | ||
* get $f$${key}() { | ||
* return ${value} | ||
* } | ||
*/ | ||
handleDerivedProperty(node) { | ||
if (!this.t.isIdentifier(node.key)) | ||
return; | ||
const key = node.key.name; | ||
const value = node.value; | ||
const propertyIdx = this.classBodyNode.body.indexOf(node); | ||
const getterNode = this.t.classMethod( | ||
"get", | ||
this.t.identifier(`$f$${key}`), | ||
[], | ||
this.t.blockStatement([this.t.returnStatement(value)]) | ||
); | ||
this.classBodyNode.body.splice(propertyIdx + 1, 0, getterNode); | ||
} | ||
/** | ||
* @brief Get all valid dependencies of a babel path | ||
* @param path | ||
* @returns dependencies | ||
*/ | ||
getDependencies(path) { | ||
const node = path.node; | ||
if (!this.t.isIdentifier(node.key)) | ||
return []; | ||
const deps = /* @__PURE__ */ new Set(); | ||
const assignDeps = /* @__PURE__ */ new Set(); | ||
path.scope.traverse(node, { | ||
MemberExpression: (innerPath) => { | ||
if (!this.t.isIdentifier(innerPath.node.property)) | ||
return; | ||
const propertyKey2 = innerPath.node.property.name; | ||
if (this.isAssignmentExpressionLeft(innerPath)) { | ||
assignDeps.add(propertyKey2); | ||
} else if (this.availableProperties.includes(propertyKey2) && this.t.isThisExpression(innerPath.node.object) && !this.isMemberInEscapeFunction( | ||
innerPath, | ||
this.classDeclarationNode | ||
) && !this.isMemberInManualFunction( | ||
innerPath, | ||
this.classDeclarationNode | ||
) && !this.isAssignmentExpressionRight( | ||
innerPath, | ||
this.classDeclarationNode | ||
)) { | ||
deps.add(propertyKey2); | ||
this.dependencyMap[propertyKey2]?.forEach(deps.add.bind(deps)); | ||
} | ||
} | ||
}); | ||
assignDeps.forEach(deps.delete.bind(deps)); | ||
const propertyKey = node.key.name; | ||
const depArr = [...deps]; | ||
if (deps.size > 0) { | ||
this.dependencyMap[propertyKey] = depArr; | ||
} | ||
return depArr; | ||
} | ||
dependencyMapReversed() { | ||
const reversedMap = {}; | ||
Object.entries(this.dependencyMap).forEach(([key, deps]) => { | ||
deps.forEach((dep) => { | ||
if (!reversedMap[dep]) | ||
reversedMap[dep] = /* @__PURE__ */ new Set(); | ||
reversedMap[dep].add(key); | ||
}); | ||
}); | ||
return reversedMap; | ||
} | ||
/** | ||
* @brief Transform arrow function property to method | ||
* @param propertyNode | ||
* @returns new method node | ||
*/ | ||
arrowFunctionPropertyToMethod(propertyNode) { | ||
if (this.t.isArrowFunctionExpression(propertyNode.value)) | ||
return; | ||
let newNode; | ||
this.classRootPath.scope.traverse(this.classBodyNode, { | ||
ClassProperty: (innerPath) => { | ||
if (innerPath.node !== propertyNode) | ||
return; | ||
const propertyBody = propertyNode.value.body; | ||
const body = this.t.isExpression(propertyBody) ? this.t.blockStatement([this.t.returnStatement(propertyBody)]) : propertyBody; | ||
const methodNode = this.t.classMethod( | ||
"method", | ||
propertyNode.key, | ||
propertyNode.value.params, | ||
body | ||
); | ||
newNode = methodNode; | ||
innerPath.replaceWith(methodNode); | ||
} | ||
}); | ||
return newNode; | ||
} | ||
/** | ||
* @brief Check if a member expression is a property of a member expression | ||
* @param parentNode | ||
* @param currentNode | ||
* @returns is a property of a member expression | ||
*/ | ||
isMemberExpressionProperty(parentNode, currentNode) { | ||
return this.t.isMemberExpression(parentNode) && !parentNode.computed && parentNode.property === currentNode; | ||
} | ||
/** | ||
* @brief Check if a member expression is a key of an object | ||
* @param parentNode | ||
* @param currentNode | ||
* @returns is a key of an object | ||
*/ | ||
isObjectKey(parentNode, currentNode) { | ||
return this.t.isObjectProperty(parentNode) && parentNode.key === currentNode; | ||
} | ||
/** | ||
* @brief Add arrow function to property value | ||
* @param node | ||
*/ | ||
valueWithArrowFunc(node) { | ||
if (!node.value) { | ||
node.value = this.t.identifier("undefined"); | ||
} | ||
node.value = this.t.arrowFunctionExpression([], node.value); | ||
} | ||
/** | ||
* @brief Wrap the value in a file | ||
* @param node | ||
* @returns wrapped value | ||
*/ | ||
valueWrapper(node) { | ||
return this.t.file( | ||
this.t.program([ | ||
this.t.isStatement(node) ? node : this.t.expressionStatement(node) | ||
]) | ||
); | ||
} | ||
/** | ||
* @brief check if the identifier is from a function param till the stopNode | ||
* e.g: | ||
* function myFunc1(ok) { // stopNode = functionBody | ||
* const myFunc2 = ok => ok // from function param | ||
* console.log(ok) // not from function param | ||
* } | ||
* @param path | ||
* @param idName | ||
*/ | ||
isAttrFromFunction(path, idName) { | ||
let reversePath = path.parentPath; | ||
const checkParam = (param) => { | ||
if (this.t.isIdentifier(param)) | ||
return param.name === idName; | ||
if (this.t.isAssignmentPattern(param)) | ||
return checkParam(param.left); | ||
if (this.t.isArrayPattern(param)) { | ||
return param.elements.filter(Boolean).map((el) => checkParam(el)).includes(true); | ||
} | ||
if (this.t.isObjectPattern(param)) { | ||
return param.properties.filter( | ||
(prop) => this.t.isObjectProperty(prop) && this.t.isIdentifier(prop.key) | ||
).map((prop) => prop.key.name).includes(idName); | ||
} | ||
if (this.t.isRestElement(param)) | ||
return checkParam(param.argument); | ||
return false; | ||
}; | ||
while (reversePath) { | ||
const node = reversePath.node; | ||
if (this.t.isArrowFunctionExpression(node) || this.t.isFunctionDeclaration(node)) { | ||
for (const param of node.params) { | ||
if (checkParam(param)) | ||
return true; | ||
} | ||
} | ||
reversePath = reversePath.parentPath; | ||
} | ||
return false; | ||
} | ||
/** | ||
* @brief Check if an identifier is a simple identifier, i.e., not a member expression, or a function param | ||
* @param path | ||
* 1. not a member expression | ||
* 2. not a function param | ||
* 3. not in a declaration | ||
* 4. not as object property's not computed key | ||
*/ | ||
isStandAloneIdentifier(path) { | ||
const node = path.node; | ||
const parentNode = path.parentPath?.node; | ||
const isMemberExpression = this.t.isMemberExpression(parentNode) && parentNode.property === node; | ||
if (isMemberExpression) | ||
return false; | ||
const isFunctionParam = this.isAttrFromFunction(path, node.name); | ||
if (isFunctionParam) | ||
return false; | ||
while (path.parentPath) { | ||
if (this.t.isVariableDeclarator(path.parentPath.node)) | ||
return false; | ||
if (this.t.isObjectProperty(path.parentPath.node) && path.parentPath.node.key === path.node && !path.parentPath.node.computed) | ||
return false; | ||
path = path.parentPath; | ||
} | ||
return true; | ||
} | ||
/** | ||
* @brief Get all identifiers as strings in a node | ||
* @param node | ||
* @returns identifiers | ||
*/ | ||
getIdentifiers(node) { | ||
if (this.t.isIdentifier(node)) | ||
return [node.name]; | ||
const identifierKeys = /* @__PURE__ */ new Set(); | ||
this.traverse(this.valueWrapper(node), { | ||
Identifier: (innerPath) => { | ||
if (!this.isStandAloneIdentifier(innerPath)) | ||
return; | ||
identifierKeys.add(innerPath.node.name); | ||
} | ||
}); | ||
return [...identifierKeys]; | ||
} | ||
/** | ||
* @brief Check if it's the left side of an assignment expression, e.g. this.count = 1 | ||
* @param innerPath | ||
* @returns is left side of an assignment expression | ||
*/ | ||
isAssignmentExpressionLeft(innerPath) { | ||
const parentNode = innerPath.parentPath?.node; | ||
return this.t.isAssignmentExpression(parentNode) && parentNode.left === innerPath.node || this.t.isUpdateExpression(parentNode); | ||
} | ||
/** | ||
* @brief Check if a member expression is the right side of an assignment expression | ||
* e.g. this.count = this.count + 1 | ||
* @param innerPath | ||
* @returns is the right side of an assignment expression | ||
*/ | ||
isAssignmentExpressionRight(innerPath, stopNode) { | ||
const currNode = innerPath.node; | ||
let isRightExp = false; | ||
let reversePath = innerPath.parentPath; | ||
while (reversePath && reversePath.node !== stopNode) { | ||
if (this.t.isAssignmentExpression(reversePath.node)) { | ||
const leftNode = reversePath.node.left; | ||
const typeEqual = currNode.type === leftNode.type; | ||
const identifierEqual = currNode.property.name === leftNode.property.name; | ||
isRightExp = typeEqual && identifierEqual; | ||
} | ||
reversePath = reversePath.parentPath; | ||
} | ||
return isRightExp; | ||
} | ||
/** | ||
* @brief Check if it's in an "escape" function, | ||
* e.g. escape(() => { console.log(this.count) }) | ||
* deps will be empty instead of ["count"] | ||
* @param innerPath | ||
* @param classDeclarationNode | ||
* @returns is in escape function | ||
*/ | ||
isMemberInEscapeFunction(innerPath, stopNode) { | ||
let isInFunction = false; | ||
let reversePath = innerPath.parentPath; | ||
while (reversePath && reversePath.node !== stopNode) { | ||
const node = reversePath.node; | ||
if (this.t.isCallExpression(node) && this.t.isIdentifier(node.callee) && _PluginProvider.escapeNamings.includes(node.callee.name)) { | ||
isInFunction = true; | ||
break; | ||
} | ||
reversePath = reversePath.parentPath; | ||
} | ||
return isInFunction; | ||
} | ||
/** | ||
* @brief Check if it's in a "manual" function, | ||
* e.g. manual(() => { console.log(this.count) }, ["flag"]) | ||
* deps will be ["flag"] instead of ["count"] | ||
* @param innerPath | ||
* @param classDeclarationNode | ||
* @returns is in manual function | ||
*/ | ||
isMemberInManualFunction(innerPath, stopNode) { | ||
let isInFunction = false; | ||
let reversePath = innerPath.parentPath; | ||
while (reversePath && reversePath.node !== stopNode) { | ||
const node = reversePath.node; | ||
const parentNode = reversePath.parentPath?.node; | ||
const isFunction = this.t.isFunctionExpression(node) || this.t.isArrowFunctionExpression(node); | ||
const isManual = this.t.isCallExpression(parentNode) && this.t.isIdentifier(parentNode.callee) && parentNode.callee.name === "manual"; | ||
if (isFunction && isManual) { | ||
isInFunction = true; | ||
break; | ||
} | ||
reversePath = reversePath.parentPath; | ||
} | ||
return isInFunction; | ||
} | ||
/** | ||
* @brief Generate a random string | ||
* @param length | ||
* @returns random string | ||
*/ | ||
static uid(length = 4) { | ||
return Math.random().toString(32).slice(2, length + 2); | ||
} | ||
}; | ||
var PluginProvider = _PluginProvider; | ||
// ---- Const Level | ||
__publicField(PluginProvider, "defaultHTMLTags", [ | ||
"a", | ||
"abbr", | ||
"address", | ||
"area", | ||
"article", | ||
"aside", | ||
"audio", | ||
"b", | ||
"base", | ||
"bdi", | ||
"bdo", | ||
"blockquote", | ||
"body", | ||
"br", | ||
"button", | ||
"canvas", | ||
"caption", | ||
"cite", | ||
"code", | ||
"col", | ||
"colgroup", | ||
"data", | ||
"datalist", | ||
"dd", | ||
"del", | ||
"details", | ||
"dfn", | ||
"dialog", | ||
"div", | ||
"dl", | ||
"dt", | ||
"em", | ||
"embed", | ||
"fieldset", | ||
"figcaption", | ||
"figure", | ||
"footer", | ||
"form", | ||
"h1", | ||
"h2", | ||
"h3", | ||
"h4", | ||
"h5", | ||
"h6", | ||
"head", | ||
"header", | ||
"hgroup", | ||
"hr", | ||
"html", | ||
"i", | ||
"iframe", | ||
"img", | ||
"input", | ||
"ins", | ||
"kbd", | ||
"label", | ||
"legend", | ||
"li", | ||
"link", | ||
"main", | ||
"map", | ||
"mark", | ||
"menu", | ||
"meta", | ||
"meter", | ||
"nav", | ||
"noscript", | ||
"object", | ||
"ol", | ||
"optgroup", | ||
"option", | ||
"output", | ||
"p", | ||
"picture", | ||
"pre", | ||
"progress", | ||
"q", | ||
"rp", | ||
"rt", | ||
"ruby", | ||
"s", | ||
"samp", | ||
"script", | ||
"section", | ||
"select", | ||
"slot", | ||
"small", | ||
"source", | ||
"span", | ||
"strong", | ||
"style", | ||
"sub", | ||
"summary", | ||
"sup", | ||
"table", | ||
"tbody", | ||
"td", | ||
"template", | ||
"textarea", | ||
"tfoot", | ||
"th", | ||
"thead", | ||
"time", | ||
"title", | ||
"tr", | ||
"track", | ||
"u", | ||
"ul", | ||
"var", | ||
"video", | ||
"wbr", | ||
"acronym", | ||
"applet", | ||
"basefont", | ||
"bgsound", | ||
"big", | ||
"blink", | ||
"center", | ||
"dir", | ||
"font", | ||
"frame", | ||
"frameset", | ||
"isindex", | ||
"keygen", | ||
"listing", | ||
"marquee", | ||
"menuitem", | ||
"multicol", | ||
"nextid", | ||
"nobr", | ||
"noembed", | ||
"noframes", | ||
"param", | ||
"plaintext", | ||
"rb", | ||
"rtc", | ||
"spacer", | ||
"strike", | ||
"tt", | ||
"xmp", | ||
"animate", | ||
"animateMotion", | ||
"animateTransform", | ||
"circle", | ||
"clipPath", | ||
"defs", | ||
"desc", | ||
"ellipse", | ||
"feBlend", | ||
"feColorMatrix", | ||
"feComponentTransfer", | ||
"feComposite", | ||
"feConvolveMatrix", | ||
"feDiffuseLighting", | ||
"feDisplacementMap", | ||
"feDistantLight", | ||
"feDropShadow", | ||
"feFlood", | ||
"feFuncA", | ||
"feFuncB", | ||
"feFuncG", | ||
"feFuncR", | ||
"feGaussianBlur", | ||
"feImage", | ||
"feMerge", | ||
"feMergeNode", | ||
"feMorphology", | ||
"feOffset", | ||
"fePointLight", | ||
"feSpecularLighting", | ||
"feSpotLight", | ||
"feTile", | ||
"feTurbulence", | ||
"filter", | ||
"foreignObject", | ||
"g", | ||
"image", | ||
"line", | ||
"linearGradient", | ||
"marker", | ||
"mask", | ||
"metadata", | ||
"mpath", | ||
"path", | ||
"pattern", | ||
"polygon", | ||
"polyline", | ||
"radialGradient", | ||
"rect", | ||
"set", | ||
"stop", | ||
"svg", | ||
"switch", | ||
"symbol", | ||
"text", | ||
"textPath", | ||
"tspan", | ||
"use", | ||
"view" | ||
]); | ||
__publicField(PluginProvider, "availableDecoNames", ["Static", "Prop", "Env", "Content", "Children"]); | ||
__publicField(PluginProvider, "dlightDefaultPackageName", "@dlightjs/dlight"); | ||
__publicField(PluginProvider, "importMap", Object.fromEntries( | ||
[ | ||
"createTemplate", | ||
"setStyle", | ||
"setDataset", | ||
"setMemorizedEvent", | ||
"setHTMLProp", | ||
"setHTMLAttr", | ||
"setHTMLProps", | ||
"setHTMLAttrs", | ||
"insertNode", | ||
"createElement", | ||
"ForNode", | ||
"IfNode", | ||
"EnvNode", | ||
"createTextNode", | ||
"updateText", | ||
"ExpNode", | ||
"PropView" | ||
].map( | ||
(funcName, idx) => devMode ? [funcName, funcName] : [funcName, `$${idx}$`] | ||
) | ||
)); | ||
__publicField(PluginProvider, "escapeNamings", ["escape", "$"]); | ||
var PluginProviderClass = PluginProvider; | ||
// src/plugin.ts | ||
function plugin_default(api, options) { | ||
const { types } = api; | ||
const { | ||
files = "**/*.{js,jsx,ts,tsx}", | ||
excludeFiles = "**/{dist,node_modules,lib}/*.{js,ts}", | ||
enableDevTools = false, | ||
htmlTags = (defaultHtmlTags) => defaultHtmlTags | ||
} = options; | ||
const pluginProvider = new PluginProviderClass( | ||
api, | ||
types, | ||
Array.isArray(files) ? files : [files], | ||
Array.isArray(excludeFiles) ? excludeFiles : [excludeFiles], | ||
enableDevTools, | ||
htmlTags | ||
); | ||
return { | ||
visitor: { | ||
Program(path, { filename }) { | ||
return pluginProvider.programVisitor(path, filename); | ||
}, | ||
ClassDeclaration: { | ||
enter: pluginProvider.classEnter.bind(pluginProvider), | ||
exit: pluginProvider.classExit.bind(pluginProvider) | ||
}, | ||
ClassExpression: { | ||
enter: pluginProvider.classEnter.bind(pluginProvider), | ||
exit: pluginProvider.classExit.bind(pluginProvider) | ||
}, | ||
ClassMethod: pluginProvider.classMethodVisitor.bind(pluginProvider), | ||
ClassProperty: pluginProvider.classPropertyVisitor.bind(pluginProvider) | ||
} | ||
}; | ||
} | ||
// src/index.ts | ||
function src_default(_, options) { | ||
return { | ||
plugins: [ | ||
syntaxTypescript, | ||
[syntaxDecorators.default ?? syntaxDecorators, { legacy: true }], | ||
[plugin_default, options] | ||
] | ||
}; | ||
} | ||
export { | ||
src_default as default | ||
}; | ||
var I=Object.defineProperty;var k=(h,e,t)=>e in h?I(h,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):h[e]=t;var m=(h,e,t)=>(k(h,typeof e!="symbol"?e+"":e,t),t);import B from"babel-plugin-syntax-typescript-new";import M from"@babel/plugin-syntax-decorators";import{minimatch as x}from"minimatch";import{parseView as N}from"@dlightjs/view-parser";import{parseReactivity as v}from"@dlightjs/reactivity-parser";import{generateSubView as S,generateView as A}from"@dlightjs/view-generator";var C=process.env.NODE_ENV==="development",p=class{dlightPackageName=p.dlightDefaultPackageName;babelApi;t;traverse;enableDevTools;includes;excludes;htmlTags;constructor(e,t,i,s,r,n){this.babelApi=e,this.t=t,this.traverse=e.traverse,this.includes=i,this.excludes=s,this.enableDevTools=C&&r,this.htmlTags=typeof n=="function"?n(p.defaultHTMLTags):n.includes("*")?[...new Set([...p.defaultHTMLTags,...n])].filter(a=>a!=="*"):n}classRootPath;classDeclarationNode;classBodyNode;constructorNode;propertiesContainer={};dependencyMap={};enter=!0;enterClassNode=!1;className;programNode;allImports=[];didAlterImports=!1;clearNode(){this.classRootPath=void 0,this.classDeclarationNode=void 0,this.classBodyNode=void 0,this.constructorNode=void 0,this.propertiesContainer={},this.dependencyMap={},this.enter=!0,this.enterClassNode=!1,this.className=void 0}get availableProperties(){return Object.entries(this.propertiesContainer).filter(([e,{isWatcher:t,isStatic:i,isChildren:s}])=>e!=="_$compName"&&!t&&!i&&!s).map(([e])=>e)}initNode(e){this.classRootPath=e;let t=e.node;if(this.classDeclarationNode=t,this.classBodyNode=t.body,this.propertiesContainer={},t.id?.name||(t.id=this.t.identifier(`Anonymous_${p.uid()}`)),this.className=t.id?.name,this.handleClassCustomDecorators(),this.enableDevTools&&this.classBodyNode.body.unshift(this.t.classProperty(this.t.identifier("_$compName"),this.t.stringLiteral(this.className))),this.addConstructor(),!this.didAlterImports){let i=this.allImports.filter(s=>s.source.value===p.dlightDefaultPackageName);this.dlightPackageName!==p.dlightDefaultPackageName&&i.forEach(s=>{s.source.value=this.dlightPackageName}),this.programNode.body.unshift(this.t.importDeclaration(Object.entries(p.importMap).map(([s,r])=>this.t.importSpecifier(this.t.identifier(r),this.t.identifier(s))),this.t.stringLiteral(this.dlightPackageName))),this.didAlterImports=!0}}handleClassCustomDecorators(){if(!this.classBodyNode)return;let e=this.classDeclarationNode?.decorators;if(!e)return;this.findDecoratorByName(e,"ForwardProps")&&(this.classBodyNode.body.unshift(this.t.classProperty(this.t.identifier("_$forwardProps")),this.t.classProperty(this.t.identifier("_$forwardPropsSet"),this.t.newExpression(this.t.identifier("Set"),[])),this.t.classProperty(this.t.identifier("_$forwardPropsId"),this.t.arrayExpression([]))),this.classDeclarationNode.decorators=this.removeDecorators(e,["ForwardProps"]))}transformDLightClass(){let e=this.handleView(),t=Object.entries(this.propertiesContainer).reverse(),i=this.dependencyMapReversed();for(let[s,{node:r,deps:n,isStatic:a,isChildren:o,isPropOrEnv:d,isWatcher:c,isContent:l}]of t){if(o){this.resolveChildrenDecorator(r);continue}n.length>0&&(e.push(...n),c?this.resolveWatcherDecorator(r):this.handleDerivedProperty(r)),d&&this.resolvePropDecorator(r,d),l&&(this.resolvePropDecorator(r,"Prop"),this.resolveContentDecorator(r)),!a&&e.includes(s)&&this.resolveStateDecorator(r,this.availableProperties.indexOf(s),i[s])}}handleView(){if(!this.classBodyNode)return[];let e=new Set,t,i=[];for(let o of this.classBodyNode.body){if(!this.t.isClassProperty(o)&&!this.t.isClassMethod(o)||!this.t.isIdentifier(o.key))continue;let d=this.findDecoratorByName(o.decorators,"View"),c=o.key.name==="View";if(!(!d&&!c)){if(this.t.isClassProperty(o)){let l=o.value;for(;this.t.isTSAsExpression(l);)l=l.expression;if(!this.t.isArrowFunctionExpression(o.value))continue;o.value=l;let f=this.arrowFunctionPropertyToMethod(o);if(!f)continue;o=f}d?(o.decorators=null,i.push(o)):t=o}}let s=i.map(o=>o.key.name),r=Object.fromEntries(i.map(o=>{let d=o.params[0];if(!d||!this.t.isObjectPattern(d))return["-",null];let c=Object.fromEntries(d.properties.map(l=>{if(!this.t.isObjectProperty(l))return["-",null];let f=l.key.name,y=this.getIdentifiers(this.t.assignmentExpression("=",this.t.objectPattern([this.t.objectProperty(this.t.numericLiteral(0),l.value)]),this.t.numericLiteral(0))).filter(b=>b!==f);return[f,y]}).filter(([l,f])=>f));return[o.key.name,c]}).filter(([o,d])=>d)),n=-1;if(t){let o;[o,n]=this.alterMainView(t,s,r),o.forEach(e.add.bind(e))}i.forEach(o=>{let d;[d,n]=this.alterSubView(o,s,r,n),d.forEach(e.add.bind(e))});let a=[];return this.availableProperties.forEach(o=>{e.has(o)&&a.push(o)}),a}alterMainView(e,t,i){let s=N(e.body,{babelApi:this.babelApi,subviewNames:t,htmlTags:this.htmlTags}),[r,n]=v(s,{babelApi:this.babelApi,availableProperties:this.availableProperties,dependencyMap:this.dependencyMap}),[a,o,d]=A(r,{babelApi:this.babelApi,className:this.className,importMap:p.importMap,subViewPropMap:Object.fromEntries(Object.entries(i).map(([c,l])=>[c,Object.keys(l)])),templateIdx:-1});return e.body=a,this.classBodyNode?.body.push(...o),[n,d]}alterSubView(e,t,i,s){let r=N(e.body,{babelApi:this.babelApi,subviewNames:t,htmlTags:this.htmlTags}),[n,a]=v(r,{babelApi:this.babelApi,availableProperties:this.availableProperties,dependencyMap:this.dependencyMap}),o=i[e.key.name]??[],d={};Object.entries(o).forEach(([g,P])=>{P.forEach(w=>{d[w]=[g]})});let[c]=v(r,{babelApi:this.babelApi,availableProperties:Object.keys(o),dependencyMap:this.dependencyMap,dependencyParseType:"identifier",identifierDepMap:d}),l=Object.fromEntries(Object.entries(i).map(([g,P])=>[g,Object.keys(P)])),[f,y,b]=S(n,c,e.params[0],{babelApi:this.babelApi,className:this.className,importMap:p.importMap,subViewPropMap:l,templateIdx:s});return e.body=f,this.classBodyNode?.body.push(...y),[a,b]}enterProgram(e){}programEnterVisitor(e,t){if(this.enter=this.fileAllowed(t),!this.enter)return;if(this.allImports=e.node.body.filter(s=>this.t.isImportDeclaration(s)),this.allImports.filter(s=>s.source.value===p.dlightDefaultPackageName).length===0){this.enter=!1;return}this.programNode=e.node,this.enterProgram(e)}exitProgram(e){}programExitVisitor(e){this.enter&&(this.didAlterImports=!1,this.allImports=[],this.programNode=void 0,this.exitProgram(e))}enterClass(e){}classEnter(e){this.enter&&(this.enterClassNode=this.isDLightView(e),this.enterClass&&(this.initNode(e),this.enterClass(e)))}exitClass(e){}classExit(e){this.enter&&this.enterClassNode&&(this.transformDLightClass(),this.addInit(),this.exitClass(e),this.clearNode(),this.enterClassNode=!1)}visitClassMethod(e){}classMethodVisitor(e){if(!this.enterClassNode||!this.t.isIdentifier(e.node.key))return;let t=e.node.key.name;if(t==="View"||this.findDecoratorByName(e.node.decorators,"View"))return;let s=e.node,r=this.findDecoratorByName(s.decorators,"Watch");if(!r){if(this.t.isIdentifier(s.key,{name:"constructor"}))return;this.autoBindMethods(s);return}let n=[];if(this.t.isIdentifier(r))n=this.getDependencies(e);else{let a=r.arguments[0];this.t.isArrayExpression(a)&&(n=a.elements.filter(o=>this.t.isStringLiteral(o)).map(o=>o.value),n=[...new Set(n)])}this.propertiesContainer[t]={node:s,deps:n,isWatcher:!0},s.decorators=this.removeDecorators(s.decorators,["Watch"]),this.visitClassMethod(e)}visitClassProperty(e){}classPropertyVisitor(e){if(!this.enterClassNode)return;let t=e.node;if(!this.t.isIdentifier(t.key))return;let i=t.key.name;if(i==="View")return;let s=t.decorators;if(this.findDecoratorByName(s,"View"))return;let n=!!this.findDecoratorByName(s,"Prop"),a=!!this.findDecoratorByName(s,"Env"),o=!!this.findDecoratorByName(t.decorators,"Children"),d=o?[]:this.getDependencies(e);this.propertiesContainer[i]={node:t,deps:d,isStatic:!!this.findDecoratorByName(s,"Static"),isContent:!!this.findDecoratorByName(s,"Content"),isChildren:o,isPropOrEnv:n?"Prop":a?"Env":void 0},t.decorators=this.removeDecorators(s,p.availableDecoNames),this.visitClassProperty(e)}resolveWatcherDecorator(e){if(!this.t.isIdentifier(e.key))return;let t=e.key.name,i=this.classBodyNode.body.indexOf(e),s=this.t.classProperty(this.t.identifier(`$w$${t}`));this.classBodyNode.body.splice(i,0,s)}resolveChildrenDecorator(e){if(!this.classBodyNode||!this.t.isIdentifier(e.key))return;let t=e.key.name,i=this.classBodyNode.body.indexOf(e),s=this.t.memberExpression(this.t.thisExpression(),this.t.identifier("_$children")),r=this.t.classMethod("get",this.t.identifier(t),[],this.t.blockStatement([this.t.returnStatement(s)]));this.classBodyNode.body.splice(i,1,r)}resolveContentDecorator(e){if(!this.classBodyNode||!this.t.isIdentifier(e.key)||this.classBodyNode.body.some(r=>this.t.isClassProperty(r)&&r.key.name==="_$contentKey"))return;let t=e.key.name,i=this.classBodyNode.body.indexOf(e),s=this.t.classProperty(this.t.identifier("_$contentKey"),this.t.stringLiteral(t));this.classBodyNode.body.splice(i,0,s)}resolvePropDecorator(e,t){if(!this.classBodyNode||!this.t.isIdentifier(e.key))return;let i=e.key.name,s=this.classBodyNode.body.indexOf(e),r=t.toLowerCase()==="prop"?"p":"e",n=this.t.classProperty(this.t.identifier(`$${r}$${i}`));this.classBodyNode.body.splice(s,0,n)}resolveStateDecorator(e,t,i){if(!this.classBodyNode||!this.t.isIdentifier(e.key))return;let s=e.key.name;e.key.name=`$${s}`;let r=this.classBodyNode.body.indexOf(e),n=this.t.classProperty(this.t.identifier(`$$${s}`),this.t.numericLiteral(1<<t)),a=i?[this.t.classProperty(this.t.identifier(`$s$${s}`),this.t.arrayExpression([...i].map(c=>this.t.stringLiteral(c))))]:[],o=this.t.classMethod("get",this.t.identifier(s),[],this.t.blockStatement([this.t.returnStatement(this.t.memberExpression(this.t.thisExpression(),this.t.identifier(`$${s}`)))])),d=this.t.classMethod("set",this.t.identifier(s),[this.t.identifier("value")],this.t.blockStatement([this.t.expressionStatement(this.t.callExpression(this.t.memberExpression(this.t.thisExpression(),this.t.identifier("_$updateProp")),[this.t.stringLiteral(s),this.t.identifier("value")]))]));this.classBodyNode.body.splice(r+1,0,n,...a,o,d)}fileAllowed(e){return this.includes.includes("*")?!0:!(!e||this.excludes.some(t=>x(e,t))||!this.includes.some(t=>x(e,t)))}isDLightView(e){let t=e.node;return(t.decorators??[]).find(r=>this.t.isIdentifier(r.expression,{name:"View"}))&&(t.superClass=this.t.identifier("View"),t.decorators=t.decorators?.filter(r=>!this.t.isIdentifier(r.expression,{name:"View"}))),this.t.isIdentifier(t.superClass,{name:"View"})}removeDecorators(e,t){return e?e.filter(i=>!(this.t.isIdentifier(i.expression)&&t.includes(i.expression.name)||this.t.isCallExpression(i.expression)&&this.t.isIdentifier(i.expression.callee)&&t.includes(i.expression.callee.name))):[]}findDecoratorByName(e,t){if(e)return e.find(i=>this.t.isIdentifier(i.expression,{name:t})||this.t.isCallExpression(i.expression)&&this.t.isIdentifier(i.expression.callee,{name:t}))?.expression}addConstructor(){if(!this.classBodyNode)return;let e=this.classBodyNode.body.find(t=>this.t.isClassMethod(t,{kind:"constructor"}));if(e)throw new Error("DLight class should not have constructor");e=this.t.classMethod("constructor",this.t.identifier("constructor"),[this.t.identifier("props"),this.t.identifier("content"),this.t.identifier("children"),this.t.identifier("forwardPropsScope")],this.t.blockStatement([this.t.expressionStatement(this.t.callExpression(this.t.super(),[]))])),this.constructorNode=e,this.classBodyNode.body.unshift(e)}addInit(){this.constructorNode.body.body.push(this.t.expressionStatement(this.t.callExpression(this.t.memberExpression(this.t.thisExpression(),this.t.identifier("_$init")),[this.t.identifier("props"),this.t.identifier("content"),this.t.identifier("children"),this.t.identifier("forwardPropsScope")])))}autoBindMethods(e){this.constructorNode.body.body.push(this.t.expressionStatement(this.t.assignmentExpression("=",this.t.memberExpression(this.t.thisExpression(),e.key),this.t.callExpression(this.t.memberExpression(this.t.memberExpression(this.t.thisExpression(),e.key),this.t.identifier("bind")),[this.t.thisExpression()]))))}handleDerivedProperty(e){if(!this.t.isIdentifier(e.key))return;let t=e.key.name,i=e.value,s=this.classBodyNode.body.indexOf(e),r=this.t.classMethod("get",this.t.identifier(`$f$${t}`),[],this.t.blockStatement([this.t.returnStatement(i)]));this.classBodyNode.body.splice(s+1,0,r)}getDependencies(e){let t=e.node;if(!this.t.isIdentifier(t.key))return[];let i=new Set,s=new Set;e.scope.traverse(t,{MemberExpression:a=>{if(!this.t.isIdentifier(a.node.property))return;let o=a.node.property.name;this.isAssignmentExpressionLeft(a)?s.add(o):this.availableProperties.includes(o)&&this.t.isThisExpression(a.node.object)&&!this.isMemberInEscapeFunction(a,this.classDeclarationNode)&&!this.isMemberInManualFunction(a,this.classDeclarationNode)&&!this.isAssignmentExpressionRight(a,this.classDeclarationNode)&&(i.add(o),this.dependencyMap[o]?.forEach(i.add.bind(i)))}}),s.forEach(i.delete.bind(i));let r=t.key.name,n=[...i];return i.size>0&&(this.dependencyMap[r]=n),n}dependencyMapReversed(){let e={};return Object.entries(this.dependencyMap).forEach(([t,i])=>{i.forEach(s=>{e[s]||(e[s]=new Set),e[s].add(t)})}),e}arrowFunctionPropertyToMethod(e){if(this.t.isArrowFunctionExpression(e.value))return;let t;return this.classRootPath.scope.traverse(this.classBodyNode,{ClassProperty:i=>{if(i.node!==e)return;let s=e.value.body,r=this.t.isExpression(s)?this.t.blockStatement([this.t.returnStatement(s)]):s,n=this.t.classMethod("method",e.key,e.value.params,r);t=n,i.replaceWith(n)}}),t}isMemberExpressionProperty(e,t){return this.t.isMemberExpression(e)&&!e.computed&&e.property===t}isObjectKey(e,t){return this.t.isObjectProperty(e)&&e.key===t}valueWithArrowFunc(e){e.value||(e.value=this.t.identifier("undefined")),e.value=this.t.arrowFunctionExpression([],e.value)}valueWrapper(e){return this.t.file(this.t.program([this.t.isStatement(e)?e:this.t.expressionStatement(e)]))}isAttrFromFunction(e,t){let i=e.parentPath,s=r=>this.t.isIdentifier(r)?r.name===t:this.t.isAssignmentPattern(r)?s(r.left):this.t.isArrayPattern(r)?r.elements.filter(Boolean).map(n=>s(n)).includes(!0):this.t.isObjectPattern(r)?r.properties.filter(n=>this.t.isObjectProperty(n)&&this.t.isIdentifier(n.key)).map(n=>n.key.name).includes(t):this.t.isRestElement(r)?s(r.argument):!1;for(;i;){let r=i.node;if(this.t.isArrowFunctionExpression(r)||this.t.isFunctionDeclaration(r)){for(let n of r.params)if(s(n))return!0}i=i.parentPath}return!1}isStandAloneIdentifier(e){let t=e.node,i=e.parentPath?.node;if(this.t.isMemberExpression(i)&&i.property===t||this.isAttrFromFunction(e,t.name))return!1;for(;e.parentPath;){if(this.t.isVariableDeclarator(e.parentPath.node)||this.t.isObjectProperty(e.parentPath.node)&&e.parentPath.node.key===e.node&&!e.parentPath.node.computed)return!1;e=e.parentPath}return!0}getIdentifiers(e){if(this.t.isIdentifier(e))return[e.name];let t=new Set;return this.traverse(this.valueWrapper(e),{Identifier:i=>{this.isStandAloneIdentifier(i)&&t.add(i.node.name)}}),[...t]}isAssignmentExpressionLeft(e){let t=e.parentPath?.node;return this.t.isAssignmentExpression(t)&&t.left===e.node||this.t.isUpdateExpression(t)}isAssignmentExpressionRight(e,t){let i=e.node,s=!1,r=e.parentPath;for(;r&&r.node!==t;){if(this.t.isAssignmentExpression(r.node)){let n=r.node.left,a=i.type===n.type,o=i.property.name===n.property.name;s=a&&o}r=r.parentPath}return s}isMemberInEscapeFunction(e,t){let i=!1,s=e.parentPath;for(;s&&s.node!==t;){let r=s.node;if(this.t.isCallExpression(r)&&this.t.isIdentifier(r.callee)&&p.escapeNamings.includes(r.callee.name)){i=!0;break}s=s.parentPath}return i}isMemberInManualFunction(e,t){let i=!1,s=e.parentPath;for(;s&&s.node!==t;){let r=s.node,n=s.parentPath?.node,a=this.t.isFunctionExpression(r)||this.t.isArrowFunctionExpression(r),o=this.t.isCallExpression(n)&&this.t.isIdentifier(n.callee)&&n.callee.name==="manual";if(a&&o){i=!0;break}s=s.parentPath}return i}static uid(e=4){return Math.random().toString(32).slice(2,e+2)}},u=p;m(u,"defaultHTMLTags",["a","abbr","address","area","article","aside","audio","b","base","bdi","bdo","blockquote","body","br","button","canvas","caption","cite","code","col","colgroup","data","datalist","dd","del","details","dfn","dialog","div","dl","dt","em","embed","fieldset","figcaption","figure","footer","form","h1","h2","h3","h4","h5","h6","head","header","hgroup","hr","html","i","iframe","img","input","ins","kbd","label","legend","li","link","main","map","mark","menu","meta","meter","nav","noscript","object","ol","optgroup","option","output","p","picture","pre","progress","q","rp","rt","ruby","s","samp","script","section","select","slot","small","source","span","strong","style","sub","summary","sup","table","tbody","td","template","textarea","tfoot","th","thead","time","title","tr","track","u","ul","var","video","wbr","acronym","applet","basefont","bgsound","big","blink","center","dir","font","frame","frameset","isindex","keygen","listing","marquee","menuitem","multicol","nextid","nobr","noembed","noframes","param","plaintext","rb","rtc","spacer","strike","tt","xmp","animate","animateMotion","animateTransform","circle","clipPath","defs","desc","ellipse","feBlend","feColorMatrix","feComponentTransfer","feComposite","feConvolveMatrix","feDiffuseLighting","feDisplacementMap","feDistantLight","feDropShadow","feFlood","feFuncA","feFuncB","feFuncG","feFuncR","feGaussianBlur","feImage","feMerge","feMergeNode","feMorphology","feOffset","fePointLight","feSpecularLighting","feSpotLight","feTile","feTurbulence","filter","foreignObject","g","image","line","linearGradient","marker","mask","metadata","mpath","path","pattern","polygon","polyline","radialGradient","rect","set","stop","svg","switch","symbol","text","textPath","tspan","use","view"]),m(u,"availableDecoNames",["Static","Prop","Env","Content","Children"]),m(u,"dlightDefaultPackageName","@dlightjs/dlight"),m(u,"importMap",Object.fromEntries(["createTemplate","setStyle","setDataset","setMemorizedEvent","setHTMLProp","setHTMLAttr","setHTMLProps","setHTMLAttrs","insertNode","createElement","ForNode","IfNode","EnvNode","createTextNode","updateText","ExpNode","PropView"].map((e,t)=>C?[e,e]:[e,`$${t}$`]))),m(u,"escapeNamings",["escape","$"]);var E=u;function D(h,e){let{types:t}=h,{files:i="**/*.{js,jsx,ts,tsx}",excludeFiles:s="**/{dist,node_modules,lib}/*.{js,ts}",enableDevTools:r=!1,htmlTags:n=o=>o}=e,a=new E(h,t,Array.isArray(i)?i:[i],Array.isArray(s)?s:[s],r,n);return{visitor:{Program:{enter(o,{filename:d}){return a.programEnterVisitor(o,d)},exit:a.programExitVisitor.bind(a)},ClassDeclaration:{enter:a.classEnter.bind(a),exit:a.classExit.bind(a)},ClassExpression:{enter:a.classEnter.bind(a),exit:a.classExit.bind(a)},ClassMethod:a.classMethodVisitor.bind(a),ClassProperty:a.classPropertyVisitor.bind(a)}}}function q(h,e){return{plugins:[B,[M.default??M,{legacy:!0}],[D,e]]}}export{q as default}; | ||
//# sourceMappingURL=index.js.map |
{ | ||
"name": "babel-preset-dlight", | ||
"version": "1.0.0-alpha.0", | ||
"version": "1.0.0-alpha.1", | ||
"description": "DLight transpiler babel preset", | ||
@@ -32,4 +32,4 @@ "author": { | ||
"@dlightjs/reactivity-parser": "1.0.0-alpha.0", | ||
"@dlightjs/view-generator": "1.0.0-alpha.0", | ||
"@dlightjs/view-parser": "1.0.0-alpha.0" | ||
"@dlightjs/view-parser": "1.0.0-alpha.0", | ||
"@dlightjs/view-generator": "1.0.0-alpha.1" | ||
}, | ||
@@ -36,0 +36,0 @@ "tsup": { |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
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
Minified code
QualityThis package contains minified code. This may be harmless in some cases where minified code is included in packaged libraries, however packages on npm should not minify code.
Found 1 instance in 1 package
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
178957
181
3
+ Added@dlightjs/view-generator@1.0.0-alpha.1(transitive)
- Removed@dlightjs/view-generator@1.0.0-alpha.0(transitive)