!160 feat(transpiler): add import alias

* feat(transpiler): import alias test
* feat(transpiler): add import alias
This commit is contained in:
Hoikan 2024-02-23 06:17:24 +00:00 committed by 陈超涛
parent 2445208856
commit 09c5522af3
8 changed files with 103 additions and 33 deletions

View File

@ -1,4 +1,4 @@
const importAliasPrefix = '$$';
export const importMap = [ export const importMap = [
'createElement', 'createElement',
'setStyle', 'setStyle',
@ -13,7 +13,7 @@ export const importMap = [
'runComponent', 'runComponent',
'createText' 'createText'
].reduce<Record<string, string>>((acc, cur) => { ].reduce<Record<string, string>>((acc, cur) => {
acc[cur] = cur; acc[cur] = `${importAliasPrefix}${cur}`;
return acc; return acc;
}, {}); }, {});

View File

@ -82,7 +82,10 @@ export class PluginProvider {
const t = this.babelApi.types; const t = this.babelApi.types;
// add automatic import // add automatic import
return t.importDeclaration( return t.importDeclaration(
[...this.allUsedApis].map(api => t.importSpecifier(t.identifier(api), t.identifier(api))), [...this.allUsedApis].map(api => {
if (importMap[api] === undefined) throw new Error(`Unknown api: ${api}`);
return t.importSpecifier(t.identifier(importMap[api]), t.identifier(api));
}),
t.stringLiteral(this.inulaPackageName), t.stringLiteral(this.inulaPackageName),
); );
} }
@ -103,7 +106,7 @@ export class PluginProvider {
// ---- Add templates to the program // ---- Add templates to the program
this.programNode!.body.unshift(...templates); this.programNode!.body.unshift(...templates);
// ---- collect the used apis // ---- collect the used apis
usedApis.forEach(api => this.allUsedApis.add(api)) usedApis.forEach(api => this.allUsedApis.add(api));
// ---- Replace the JSXElement with the viewAst // ---- Replace the JSXElement with the viewAst
path.replaceWith(viewAst); path.replaceWith(viewAst);
path.skip(); path.skip();

View File

@ -3,51 +3,60 @@ import { expect } from './mock';
describe('Entering', () => { describe('Entering', () => {
it('should use inula jsx preset in babel', () => { it('should use inula jsx preset in babel', () => {
const code = 'console.log(\'hello world\');'; const code = "console.log('hello world');";
expect(code, code); expect(code, code);
}); });
it('should transform jsx to inula view', () => { it('should transform jsx to inula view', () => {
expect(/*jsx*/` expect(
/*jsx*/ `
import A from "inula" import A from "inula"
function App() { function App() {
return ( return (
<div></div> <div></div>
) )
} }
`, /*js*/` `,
/*js*/ `
import { createElement as $$createElement } from "inula";
import A from "inula"; import A from "inula";
function App() { function App() {
return (() => { return (() => {
const $node0 = createElement("div"); const $node0 = $$createElement("div");
return [$node0]; return [$node0];
})(); })();
} }
`); `
);
}); });
it('should transform jsx to inula view with props', () => { it('should transform jsx to inula view with props', () => {
expect(/*jsx*/` expect(
/*jsx*/ `
import A from "inula" import A from "inula"
function App() { function App() {
return ( return (
<div id="myDiv"></div> <div id="myDiv"></div>
) )
} }
`, /*js*/` `,
/*js*/ `
import { createElement as $$createElement } from "inula";
import A from "inula"; import A from "inula";
function App() { function App() {
return (() => { return (() => {
const $node0 = createElement("div"); const $node0 = $$createElement("div");
$node0.id = "myDiv"; $node0.id = "myDiv";
return [$node0]; return [$node0];
})(); })();
} }
`); `
);
}); });
it('should transform jsx to inula view with template', () => { it('should transform jsx to inula view with template', () => {
expect(/*jsx*/` expect(
/*jsx*/ `
import A from "inula" import A from "inula"
function App() { function App() {
return ( return (
@ -57,15 +66,17 @@ describe('Entering', () => {
</div> </div>
) )
} }
`, /*js*/` `,
/*js*/ `
import { createElement as $$createElement, insert as $$insert } from "inula";
const $template0 = (() => { const $template0 = (() => {
const $node0 = createElement("div"); const $node0 = $$createElement("div");
const $node1 = createElement("p"); const $node1 = $$createElement("p");
$node1.textContent = "ok"; $node1.textContent = "ok";
insert($node0, $node1); $$insert($node0, $node1);
const $node2 = createElement("h1"); const $node2 = $$createElement("h1");
$node2.textContent = "fine"; $node2.textContent = "fine";
insert($node0, $node2); $$insert($node0, $node2);
return $node0; return $node0;
})(); })();
import A from "inula"; import A from "inula";
@ -75,6 +86,62 @@ describe('Entering', () => {
return [$node0]; return [$node0];
})(); })();
} }
`); `
);
});
it('should transform fragment', () => {
expect(
/*jsx*/ `
import A from "inula"
const CountingComponent = () => {
const count = reactive(0);
const add = () => {
count.set(c => c + 1);
};
return (
<>
<div id="count">Count value is {count.get()}.</div>
<div>
<button id="btn" onClick={add}>add</button>
</div>
</>
);
};
`,
/*js*/ `
import { createElement as $$createElement, createText as $$createText, insert as $$insert, delegateEvent as $$delegateEvent } from "inula";
const $template0 = (() => {
const $node0 = $$createElement("div");
const $node1 = $$createElement("button");
$node1.id = "btn";
$node1.textContent = "add";
$$insert($node0, $node1);
return $node0;
})();
import A from "inula";
const CountingComponent = () => {
const count = reactive(0);
const add = () => {
count.set(c => c + 1);
};
return (() => {
const $node0 = $$createElement("div");
$node0.id = "count";
const $node1 = $$createText("Count value is");
$$insert($node0, $node1);
const $node2 = count.get();
$$insert($node0, $node2);
const $node3 = $$createText(".");
$$insert($node0, $node3);
const $node4 = $template0.cloneNode(true);
const $node5 = $node4.firstChild;
$$delegateEvent($node5, "click", add);
return [$node0, $node4];
})();
};
`
);
}); });
}); });

View File

@ -48,7 +48,7 @@ export class HTMLPropGenerator extends BaseGenerator {
nodeName: string, nodeName: string,
value: t.Expression, value: t.Expression,
) { ) {
this.addUsedApi(this.importMap.setStyle); this.addUsedApi('setStyle');
return this.t.callExpression( return this.t.callExpression(
this.t.identifier(this.importMap.setStyle), this.t.identifier(this.importMap.setStyle),
[this.t.identifier(nodeName), value] [this.t.identifier(nodeName), value]
@ -63,7 +63,7 @@ export class HTMLPropGenerator extends BaseGenerator {
nodeName: string, nodeName: string,
value: t.Expression, value: t.Expression,
) { ) {
this.addUsedApi(this.importMap.setDataset); this.addUsedApi('setDataset');
return this.t.callExpression( return this.t.callExpression(
this.t.identifier(this.importMap.setDataset), this.t.identifier(this.importMap.setDataset),
[this.t.identifier(nodeName), value] [this.t.identifier(nodeName), value]
@ -98,7 +98,7 @@ export class HTMLPropGenerator extends BaseGenerator {
key: string, key: string,
value: t.Expression, value: t.Expression,
) { ) {
this.addUsedApi(this.importMap.setProperty); this.addUsedApi('setProperty');
return this.t.callExpression( return this.t.callExpression(
this.t.identifier(this.importMap.setProperty), this.t.identifier(this.importMap.setProperty),
[this.t.identifier(nodeName), this.t.stringLiteral(key), value] [this.t.identifier(nodeName), this.t.stringLiteral(key), value]
@ -133,7 +133,7 @@ export class HTMLPropGenerator extends BaseGenerator {
key: string, key: string,
value: t.Expression, value: t.Expression,
) { ) {
this.addUsedApi(this.importMap.setAttribute); this.addUsedApi('setAttribute');
return this.t.callExpression( return this.t.callExpression(
this.t.identifier(this.importMap.setAttribute), this.t.identifier(this.importMap.setAttribute),
[this.t.identifier(nodeName), this.t.stringLiteral(key), value] [this.t.identifier(nodeName), this.t.stringLiteral(key), value]
@ -149,7 +149,7 @@ export class HTMLPropGenerator extends BaseGenerator {
eventName: string, eventName: string,
value: t.Expression, value: t.Expression,
) { ) {
this.addUsedApi(this.importMap.delegateEvent); this.addUsedApi('delegateEvent');
return this.t.callExpression( return this.t.callExpression(
this.t.identifier(this.importMap.delegateEvent), this.t.identifier(this.importMap.delegateEvent),
[this.t.identifier(nodeName), this.t.stringLiteral(eventName), value] [this.t.identifier(nodeName), this.t.stringLiteral(eventName), value]
@ -183,7 +183,7 @@ export class HTMLPropGenerator extends BaseGenerator {
eventName: string, eventName: string,
value: t.Expression, value: t.Expression,
) { ) {
this.addUsedApi(this.importMap.addEventListener); this.addUsedApi('addEventListener');
return this.t.callExpression( return this.t.callExpression(
this.t.identifier(this.importMap.addEventListener), this.t.identifier(this.importMap.addEventListener),
[this.t.identifier(nodeName), this.t.stringLiteral(eventName), value] [this.t.identifier(nodeName), this.t.stringLiteral(eventName), value]

View File

@ -55,7 +55,7 @@ export class CompGenerator extends BaseGenerator {
nodes.push(propNode); nodes.push(propNode);
} }
this.addUsedApi(this.importMap.runComponent); this.addUsedApi('runComponent');
return [name, this.t.variableDeclaration('const', [ return [name, this.t.variableDeclaration('const', [
this.t.variableDeclarator( this.t.variableDeclarator(
this.t.identifier(name), this.t.identifier(name),

View File

@ -34,7 +34,7 @@ export class HTMLGenerator extends HTMLPropGenerator {
*/ */
declareHTMLNode(tag: t.Expression): [string, t.Statement] { declareHTMLNode(tag: t.Expression): [string, t.Statement] {
const name = this.geneNodeName(); const name = this.geneNodeName();
this.addUsedApi(this.importMap.createElement); this.addUsedApi('createElement');
return [name, this.t.variableDeclaration('const', [ return [name, this.t.variableDeclaration('const', [
this.t.variableDeclarator( this.t.variableDeclarator(
this.t.identifier(name), this.t.identifier(name),
@ -54,7 +54,7 @@ export class HTMLGenerator extends HTMLPropGenerator {
parent: string, parent: string,
child: string child: string
) { ) {
this.addUsedApi(this.importMap.insert); this.addUsedApi('insert');
return this.t.expressionStatement( return this.t.expressionStatement(
this.t.callExpression( this.t.callExpression(
this.t.identifier(this.importMap.insert), this.t.identifier(this.importMap.insert),

View File

@ -115,7 +115,7 @@ export class TemplateGenerator extends HTMLPropGenerator{
nextName: string nextName: string
) { ) {
const nextNode = nextName ? [this.t.identifier(nextName)] : []; const nextNode = nextName ? [this.t.identifier(nextName)] : [];
this.addUsedApi(this.importMap.insert); this.addUsedApi('insert');
return this.t.expressionStatement( return this.t.expressionStatement(
this.t.callExpression( this.t.callExpression(
this.t.identifier(this.importMap.insert), this.t.identifier(this.importMap.insert),

View File

@ -12,7 +12,7 @@ export class TextGenerator extends BaseGenerator {
declareTextNode(content: t.Literal): [string, t.Statement] { declareTextNode(content: t.Literal): [string, t.Statement] {
const name = this.geneNodeName(); const name = this.geneNodeName();
this.addUsedApi(this.importMap.createText); this.addUsedApi('createText');
return [name, this.t.variableDeclaration('const', [ return [name, this.t.variableDeclaration('const', [
this.t.variableDeclarator( this.t.variableDeclarator(
this.t.identifier(name), this.t.identifier(name),