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

View File

@ -82,7 +82,10 @@ export class PluginProvider {
const t = this.babelApi.types;
// add automatic import
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),
);
}
@ -103,7 +106,7 @@ export class PluginProvider {
// ---- Add templates to the program
this.programNode!.body.unshift(...templates);
// ---- collect the used apis
usedApis.forEach(api => this.allUsedApis.add(api))
usedApis.forEach(api => this.allUsedApis.add(api));
// ---- Replace the JSXElement with the viewAst
path.replaceWith(viewAst);
path.skip();

View File

@ -3,51 +3,60 @@ import { expect } from './mock';
describe('Entering', () => {
it('should use inula jsx preset in babel', () => {
const code = 'console.log(\'hello world\');';
const code = "console.log('hello world');";
expect(code, code);
});
it('should transform jsx to inula view', () => {
expect(/*jsx*/`
expect(
/*jsx*/ `
import A from "inula"
function App() {
return (
<div></div>
)
}
`, /*js*/`
`,
/*js*/ `
import { createElement as $$createElement } from "inula";
import A from "inula";
function App() {
return (() => {
const $node0 = createElement("div");
const $node0 = $$createElement("div");
return [$node0];
})();
}
`);
`
);
});
it('should transform jsx to inula view with props', () => {
expect(/*jsx*/`
expect(
/*jsx*/ `
import A from "inula"
function App() {
return (
<div id="myDiv"></div>
)
}
`, /*js*/`
`,
/*js*/ `
import { createElement as $$createElement } from "inula";
import A from "inula";
function App() {
return (() => {
const $node0 = createElement("div");
const $node0 = $$createElement("div");
$node0.id = "myDiv";
return [$node0];
})();
}
`);
`
);
});
it('should transform jsx to inula view with template', () => {
expect(/*jsx*/`
expect(
/*jsx*/ `
import A from "inula"
function App() {
return (
@ -57,15 +66,17 @@ describe('Entering', () => {
</div>
)
}
`, /*js*/`
`,
/*js*/ `
import { createElement as $$createElement, insert as $$insert } from "inula";
const $template0 = (() => {
const $node0 = createElement("div");
const $node1 = createElement("p");
const $node0 = $$createElement("div");
const $node1 = $$createElement("p");
$node1.textContent = "ok";
insert($node0, $node1);
const $node2 = createElement("h1");
$$insert($node0, $node1);
const $node2 = $$createElement("h1");
$node2.textContent = "fine";
insert($node0, $node2);
$$insert($node0, $node2);
return $node0;
})();
import A from "inula";
@ -75,6 +86,62 @@ describe('Entering', () => {
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,
value: t.Expression,
) {
this.addUsedApi(this.importMap.setStyle);
this.addUsedApi('setStyle');
return this.t.callExpression(
this.t.identifier(this.importMap.setStyle),
[this.t.identifier(nodeName), value]
@ -63,7 +63,7 @@ export class HTMLPropGenerator extends BaseGenerator {
nodeName: string,
value: t.Expression,
) {
this.addUsedApi(this.importMap.setDataset);
this.addUsedApi('setDataset');
return this.t.callExpression(
this.t.identifier(this.importMap.setDataset),
[this.t.identifier(nodeName), value]
@ -98,7 +98,7 @@ export class HTMLPropGenerator extends BaseGenerator {
key: string,
value: t.Expression,
) {
this.addUsedApi(this.importMap.setProperty);
this.addUsedApi('setProperty');
return this.t.callExpression(
this.t.identifier(this.importMap.setProperty),
[this.t.identifier(nodeName), this.t.stringLiteral(key), value]
@ -133,7 +133,7 @@ export class HTMLPropGenerator extends BaseGenerator {
key: string,
value: t.Expression,
) {
this.addUsedApi(this.importMap.setAttribute);
this.addUsedApi('setAttribute');
return this.t.callExpression(
this.t.identifier(this.importMap.setAttribute),
[this.t.identifier(nodeName), this.t.stringLiteral(key), value]
@ -149,7 +149,7 @@ export class HTMLPropGenerator extends BaseGenerator {
eventName: string,
value: t.Expression,
) {
this.addUsedApi(this.importMap.delegateEvent);
this.addUsedApi('delegateEvent');
return this.t.callExpression(
this.t.identifier(this.importMap.delegateEvent),
[this.t.identifier(nodeName), this.t.stringLiteral(eventName), value]
@ -183,7 +183,7 @@ export class HTMLPropGenerator extends BaseGenerator {
eventName: string,
value: t.Expression,
) {
this.addUsedApi(this.importMap.addEventListener);
this.addUsedApi('addEventListener');
return this.t.callExpression(
this.t.identifier(this.importMap.addEventListener),
[this.t.identifier(nodeName), this.t.stringLiteral(eventName), value]

View File

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

View File

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

View File

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

View File

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