!158 feat(transpiler): add packageName options

* fix: transpiler
* feat(transpiler): add packageName options
* chore: remove dist
This commit is contained in:
Hoikan 2024-02-22 08:30:38 +00:00 committed by 陈超涛
parent 553613bbc6
commit 2640177de5
18 changed files with 26 additions and 322 deletions

4
.gitignore vendored
View File

@ -4,5 +4,7 @@
package-lock.json
pnpm-lock.yaml
/packages/**/node_modules
dist
# to ignore all dist folders in all levels
**/dist
.history
dumped*

View File

@ -6,7 +6,7 @@
"scripts": {
"test": "vitest --ui",
"bench": "vitest bench",
"dump-test": "babel tests --out-dir dumped-tests --extensions .tsx --presets=babel-preset-inula-jsx --copy-files --out-file-extension .ts"
"dump-test": "babel tests --out-dir dumped-tests --extensions .ts,.tsx --presets babel-preset-inula-jsx --copy-files --out-file-extension .ts"
},
"dependencies": {
"@babel/cli": "^7.23.9",

View File

@ -26,7 +26,7 @@ export default defineConfig({
},
plugins: [
// @ts-expect-error TODO: fix vite plugin interface is not compatible
inula(),
inula({ packageName: 'inula-reactive' }),
],
test: {
environment: 'jsdom', // or 'jsdom', 'node'

View File

@ -8,7 +8,7 @@ import { attributeMap, htmlTags, importMap } from './const';
export class PluginProvider {
private static readonly inulaPackageName = 'inula-reactive';
private inulaPackageName = 'inula-reactive';
// ---- Plugin Level ----
private readonly babelApi: typeof babel
private readonly t: typeof t
@ -34,6 +34,7 @@ export class PluginProvider {
this.htmlTags = options.htmlTags ?? htmlTags;
this.parseTemplate = options.parseTemplate ?? true;
this.attributeMap = options.attributeMap ?? attributeMap;
options.packageName && (this.inulaPackageName = options.packageName);
}
// ---- Two levels of enter:
@ -56,7 +57,7 @@ export class PluginProvider {
this.t.isImportDeclaration(n)
) as t.ImportDeclaration[];
const inulaImports = this.allImports.filter(
n => n.source.value === PluginProvider.inulaPackageName
n => n.source.value === this.inulaPackageName
);
// ---- @Enter2
if (inulaImports.length === 0) {

View File

@ -1,22 +1,20 @@
import babel, { transform, types as t, parseSync } from '@babel/core';
import babel, { transform, types as t, parseSync } from '@babel/core';
import inula from '../';
import babelJSX from '@babel/plugin-syntax-jsx';
import generate from '@babel/generator';
import { expect as ep } from 'vitest';
function formatCode(code: string) {
return generate(
parseSync(code, {plugins: [babelJSX]})!
)!.code;
return generate(parseSync(code, { plugins: [babelJSX] })!)!.code;
}
export function transformInula(code: string) {
return transform(code, {
presets: [[inula, {'files': '*'}]]
presets: [[inula, { files: '*', packageName: 'inula' }]],
})?.code;
}
export function expect(ori: string, expected: string) {
const transformed = transformInula(ori)!;
ep(formatCode(transformed)).toBe(formatCode(expected));
}
}

View File

@ -27,4 +27,9 @@ export interface InulaOption {
* @example { createElement: 'createElement' }
*/
parseTemplate?: boolean
/**
* @brief The package name of inula. It will be used to identify whether we should transform the file.
* @default inula
*/
packageName?: string
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,217 +0,0 @@
import { ViewUnit, UnitProp } from '@inula/jsx-view-parser';
import Babel, { types, traverse } from '@babel/core';
interface ViewGeneratorConfig {
babelApi: typeof Babel;
importMap: Record<string, string>;
/**
* @brief Using AttributeMap to identify propertyfied attributes
* Reason for adding this:
* `el.prop = xxx` is faster than `el.setAttribute('prop', xxx)`
* @example { href: ["a", "area", "base", "link"], id: ["*"] }
*/
attributeMap?: Record<string, string[]>;
}
declare class BaseGenerator {
readonly viewUnit: ViewUnit;
readonly config: ViewGeneratorConfig;
readonly t: typeof types;
readonly traverse: typeof traverse;
readonly elementAttributeMap: Record<string, string[]>;
readonly importMap: Record<string, string>;
constructor(viewUnit: ViewUnit, config: ViewGeneratorConfig);
private readonly initStatements;
addStatement(...statements: types.Statement[]): void;
private readonly templates;
addTemplate(...template: types.Statement[]): void;
/**
* @brief To be implemented by the subclass
*/
run(): string;
generate(): [string, types.Statement[], types.Statement[]];
/**
* @brief Check if the expression is reactive, which satisfies the following conditions:
* 1. Contains .get() property
* 2. The whole expression is not a function
* @param expression
* @returns
*/
checkReactive(expression: types.Expression): boolean;
private readonly prefixMap;
nodeIdx: number;
geneNodeName(idx?: number): string;
templateIdx: number;
generateTemplateName(): string;
/**
* @brief Wrap the value in a file
* @param node
* @returns wrapped value
*/
wrapWithFile(node: types.Expression): types.File;
addWatch(value: types.Expression): types.CallExpression;
createCollector(): [types.Statement[], (statement: types.Statement | types.Statement[] | null) => void];
parseViewProp(prop: UnitProp, generateView: (units: ViewUnit[], config: ViewGeneratorConfig, templateIdx: number) => [types.Statement[], types.ExpressionStatement]): types.Expression;
parseProps(props: Record<string, UnitProp>, generateView: (units: ViewUnit[], config: ViewGeneratorConfig) => [types.Statement[], types.ExpressionStatement]): {
[k: string]: types.Expression;
};
}
declare class CompGenerator extends BaseGenerator {
run(): string;
/**
* @View
* const $el = createComponent(tag, {
* ...props
* }, spreadProps)
*/
declareCompNode(tag: types.Expression, props: Record<string, types.Expression>, children: ViewUnit[]): [string, types.Statement];
}
declare class HTMLPropGenerator extends BaseGenerator {
static DelegatedEvents: Set<string>;
addHTMLProp(nodeName: string, tag: string, key: string, value: types.Expression): types.Statement;
/**
* @View
* setStyle($node, value)
*/
private setStyle;
/**
* @View
* setDataset($node, value)
*/
private setDataset;
/**
* @View
* $node.key = value
*/
private setStaticProperty;
/**
* @View
* setProperty($node, key, value)
*/
private setDynamicProperty;
/**
* @View
* $node.setAttribute(key, value)
*/
private setStaticAttribute;
/**
* @View
* setAttribute($node, key, value)
*/
private setDynamicAttribute;
/**
* @View
* delegateEvent($node, eventName, value)
*/
private setDelegatedEvent;
/**
* @View
* $node.addEventListener(eventName, value)
*/
private setStaticEvent;
/**
* @View
* addEventListener($node, eventName, value)
*/
private setDynamicEvent;
private setDynamicHTMLProp;
/**
* @brief Check if the attribute is internal, i.e., can be accessed as js property
* @param tag
* @param attribute
* @returns true if the attribute is internal
*/
isInternalAttribute(tag: string, attribute: string): boolean;
}
declare class HTMLGenerator extends HTMLPropGenerator {
run(): string;
/**
* @View
* const $el = createElement(tag)
*/
declareHTMLNode(tag: types.Expression): [string, types.Statement];
/**
* @View
* $insert($el, childNode)
*/
private insertChildNode;
}
declare class TemplateGenerator extends HTMLPropGenerator {
run(): string;
private generateTemplate;
/**
* @View
* const $el = template.cloneNode(true)
*/
private declareTemplateNode;
/**
* @View
* $insert($el, childNode)
*/
private insertChildNode;
/**
* @View
* ${dlNodeName}.firstChild
* or
* ${dlNodeName}.firstChild.nextSibling
* or
* ...
* ${dlNodeName}.childNodes[${num}]
*/
private insertElement;
/**
* @brief Insert elements to the template node from the paths
* @param paths
* @param dlNodeName
* @returns
*/
private insertElements;
/**
* @brief Extract common prefix from paths
* e.g.
* [0, 1, 2, 3] + [0, 1, 2, 4] => [0, 1, 2], [0, 1, 2, 3], [0, 1, 2, 4]
* [0, 1, 2] is the common prefix
* @param paths
* @returns paths with common prefix
*/
private static pathWithCommonPrefix;
/**
* @brief Find the best node name and path for the given path by looking into the nameMap.
* If there's a full match, return the name and an empty path
* If there's a partly match, return the name and the remaining path
* If there's a nextSibling match, return the name and the remaining path with sibling offset
* @param nameMap
* @param path
* @param defaultName
* @returns [name, path, siblingOffset]
*/
private static findBestNodeAndPath;
}
declare class TextGenerator extends BaseGenerator {
run(): string;
declareTextNode(content: types.Literal): [string, types.Statement];
}
declare class ExpressionGenerator extends BaseGenerator {
run(): string;
declareExpressionNode(expression: types.Expression): [string, types.Statement];
}
declare const viewGeneratorMap: {
readonly html: typeof HTMLGenerator;
readonly comp: typeof CompGenerator;
readonly template: typeof TemplateGenerator;
readonly text: typeof TextGenerator;
readonly exp: typeof ExpressionGenerator;
readonly if: typeof CompGenerator;
readonly env: typeof CompGenerator;
};
declare function generateNew(oldGenerator: any, viewUnit: ViewUnit, resetIdx?: boolean): [string, types.Statement[], types.Statement[]];
declare function generateView(viewUnits: ViewUnit[], config: ViewGeneratorConfig, templateIdx?: number): [types.Statement[], types.ExpressionStatement];
export { ViewGeneratorConfig, generateNew, generateView, viewGeneratorMap };

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -146,7 +146,7 @@ export class HTMLPropGenerator extends BaseGenerator {
value: t.Expression,
) {
return this.t.callExpression(
this.t.identifier(this.importMap.delegateEvents),
this.t.identifier(this.importMap.delegateEvent),
[this.t.identifier(nodeName), this.t.stringLiteral(eventName), value]
);
}

View File

@ -1,12 +1,12 @@
export const importMap = [
'createElement',
'setStyle',
'setAttribute',
'setDataset',
'setProperty',
'setEvent',
'delegateEvent',
'createElement',
'setStyle',
'setAttribute',
'setDataset',
'setProperty',
'setEvent',
'delegateEvent',
'addEventListener',
'watch',
'insert',
@ -510,4 +510,4 @@ export const attributeMap = {
ariaRowIndex: ['*'],
ariaRowSpan: ['*'],
ariaSetSize: ['*'],
};
};

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,73 +0,0 @@
import Babel, { types } from '@babel/core';
interface UnitProp {
value: types.Expression;
viewPropMap: Record<string, ViewUnit[]>;
specifier?: string;
}
interface TextUnit {
type: 'text';
content: types.Literal;
}
type MutableUnit = ViewUnit & {
path: number[];
};
interface TemplateProp {
tag: types.Expression;
name: string;
key: string;
path: number[];
value: types.Expression;
}
interface TemplateUnit {
type: 'template';
template: HTMLUnit;
mutableUnits: MutableUnit[];
props: TemplateProp[];
}
interface HTMLUnit {
type: 'html';
tag: types.Expression;
props: Record<string, UnitProp>;
children: ViewUnit[];
}
interface CompUnit {
type: 'comp';
tag: types.Expression;
props: Record<string, UnitProp>;
children: ViewUnit[];
}
interface IfBranch {
condition: types.Expression;
children: ViewUnit[];
}
interface IfUnit {
type: 'if';
branches: IfBranch[];
}
interface ExpUnit {
type: 'exp';
content: UnitProp;
}
interface EnvUnit {
type: 'env';
props: Record<string, UnitProp>;
children: ViewUnit[];
}
type ViewUnit = TextUnit | HTMLUnit | CompUnit | IfUnit | ExpUnit | EnvUnit | TemplateUnit;
interface ViewParserConfig {
babelApi: typeof Babel;
htmlTags: string[];
parseTemplate?: boolean;
}
type AllowedJSXNode = types.JSXElement | types.JSXFragment | types.JSXText | types.JSXExpressionContainer | types.JSXSpreadChild;
/**
* @brief Generate view units from a babel ast
* @param statement
* @param config
* @returns ViewUnit[]
*/
declare function parseView(node: AllowedJSXNode, config: ViewParserConfig): ViewUnit[];
export { AllowedJSXNode, CompUnit, EnvUnit, ExpUnit, HTMLUnit, IfBranch, IfUnit, MutableUnit, TemplateProp, TemplateUnit, TextUnit, UnitProp, ViewParserConfig, ViewUnit, parseView };

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long