@vobs/compiler 1.2.1 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/compile.cjs +349 -254
- package/dist/compile.cjs.map +1 -1
- package/dist/compile.js +90 -23
- package/dist/compile.js.map +1 -1
- package/dist/i18n-extractor.cjs +45 -16
- package/dist/i18n-extractor.cjs.map +1 -1
- package/dist/i18n-extractor.js +6 -5
- package/dist/i18n-extractor.js.map +1 -1
- package/dist/index.cjs +361 -260
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +99 -28
- package/dist/index.js.map +1 -1
- package/dist/plugin.cjs +18 -2
- package/dist/plugin.cjs.map +1 -1
- package/dist/plugin.d.cts +6 -0
- package/dist/plugin.d.ts +6 -0
- package/dist/plugin.js +0 -2
- package/dist/plugin.js.map +1 -1
- package/package.json +2 -2
- package/src/compile.test.ts +74 -0
- package/src/compile.ts +113 -17
- package/src/plugin.ts +6 -0
package/dist/index.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import ts from 'typescript';
|
|
2
|
-
import { VobsError } from '@vobs/runtime/error';
|
|
3
|
-
|
|
4
1
|
var __defProp = Object.defineProperty;
|
|
5
2
|
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
3
|
+
|
|
4
|
+
// packages/compiler/src/compile.ts
|
|
5
|
+
import ts from "typescript";
|
|
6
|
+
import { VobsError } from "@vobs/runtime/error";
|
|
6
7
|
function createCompiler(options = {}) {
|
|
7
8
|
const basePlugins = options.plugins ?? [];
|
|
8
9
|
return {
|
|
@@ -57,7 +58,8 @@ function compileWithSourceMap(code, options = {}) {
|
|
|
57
58
|
sourceLocation: options.sourceLocation ?? true,
|
|
58
59
|
stateAliases: collectStateAliases(sourceFile),
|
|
59
60
|
localBindings: collectLocallyDeclaredNames(sourceFile),
|
|
60
|
-
diagnostics: []
|
|
61
|
+
diagnostics: [],
|
|
62
|
+
hmrModuleId: options.hmrModuleId ?? null
|
|
61
63
|
};
|
|
62
64
|
const cleanFilename = filename.split(/[?#]/u, 1)[0] || filename;
|
|
63
65
|
const diagnostics = ts.transpileModule(code, {
|
|
@@ -83,14 +85,15 @@ function compileWithSourceMap(code, options = {}) {
|
|
|
83
85
|
}
|
|
84
86
|
for (const plugin of plugins) sourceFile = transformPluginNodes(sourceFile, plugin, context);
|
|
85
87
|
const statements = sourceFile.statements.map(
|
|
86
|
-
(statement) => ts.isImportDeclaration(statement) ? rebuildImport(state, statement) : transformStatement(state, statement)
|
|
88
|
+
(statement) => ts.isImportDeclaration(statement) ? rebuildImport(state, statement) : transformStatement(state, statement, true)
|
|
87
89
|
);
|
|
88
90
|
const templateDeclarations = createTemplateDeclarations(state);
|
|
89
|
-
|
|
91
|
+
let resultFile = ts.factory.updateSourceFile(sourceFile, [
|
|
90
92
|
...createRuntimeImports(state),
|
|
91
93
|
...templateDeclarations,
|
|
92
94
|
...statements
|
|
93
95
|
]);
|
|
96
|
+
resultFile = transformResidualJsx(state, resultFile);
|
|
94
97
|
const generated = ts.createPrinter().printFile(resultFile);
|
|
95
98
|
return {
|
|
96
99
|
code: generated,
|
|
@@ -372,7 +375,7 @@ function rebuildImport(state, node) {
|
|
|
372
375
|
), node);
|
|
373
376
|
}
|
|
374
377
|
__name(rebuildImport, "rebuildImport");
|
|
375
|
-
function transformStatement(state, node) {
|
|
378
|
+
function transformStatement(state, node, moduleScope = false) {
|
|
376
379
|
if (ts.isFunctionDeclaration(node) && node.body) {
|
|
377
380
|
return tagStatement(state, ts.factory.updateFunctionDeclaration(
|
|
378
381
|
node,
|
|
@@ -385,7 +388,7 @@ function transformStatement(state, node) {
|
|
|
385
388
|
transformBlock(state, node.body)
|
|
386
389
|
), node);
|
|
387
390
|
}
|
|
388
|
-
if (ts.isVariableStatement(node)) return transformVariableStatement(state, node);
|
|
391
|
+
if (ts.isVariableStatement(node)) return transformVariableStatement(state, node, moduleScope);
|
|
389
392
|
if (ts.isExportAssignment(node) && containsJsx(node.expression)) {
|
|
390
393
|
return tagStatement(state, ts.factory.updateExportAssignment(node, node.modifiers, transformEmbeddedExpression(state, node.expression)), node);
|
|
391
394
|
}
|
|
@@ -398,7 +401,7 @@ function transformStatement(state, node) {
|
|
|
398
401
|
return node;
|
|
399
402
|
}
|
|
400
403
|
__name(transformStatement, "transformStatement");
|
|
401
|
-
function transformVariableStatement(state, node) {
|
|
404
|
+
function transformVariableStatement(state, node, moduleScope = false) {
|
|
402
405
|
let changed = false;
|
|
403
406
|
const declarations = node.declarationList.declarations.map((declaration) => {
|
|
404
407
|
const initializer = declaration.initializer;
|
|
@@ -406,6 +409,8 @@ function transformVariableStatement(state, node) {
|
|
|
406
409
|
let nextInitializer = inferStateDebugName(state, declaration, initializer) ?? initializer;
|
|
407
410
|
if (containsJsx(nextInitializer)) {
|
|
408
411
|
nextInitializer = transformEmbeddedExpression(state, nextInitializer);
|
|
412
|
+
} else if (moduleScope && state.hmrModuleId !== null) {
|
|
413
|
+
nextInitializer = wrapStateWithHmrRef(state, declaration, nextInitializer) ?? nextInitializer;
|
|
409
414
|
}
|
|
410
415
|
if (nextInitializer === initializer) return declaration;
|
|
411
416
|
changed = true;
|
|
@@ -443,6 +448,29 @@ function inferStateDebugName(state, declaration, initializer) {
|
|
|
443
448
|
]);
|
|
444
449
|
}
|
|
445
450
|
__name(inferStateDebugName, "inferStateDebugName");
|
|
451
|
+
function wrapStateWithHmrRef(state, declaration, initializer) {
|
|
452
|
+
let call = initializer;
|
|
453
|
+
while (ts.isParenthesizedExpression(call) || ts.isAsExpression(call) || ts.isTypeAssertionExpression(call) || ts.isSatisfiesExpression(call)) {
|
|
454
|
+
call = call.expression;
|
|
455
|
+
}
|
|
456
|
+
if (!ts.isCallExpression(call)) return void 0;
|
|
457
|
+
const callee = call.expression;
|
|
458
|
+
if (!ts.isIdentifier(callee) || !state.stateAliases.has(callee.text)) return void 0;
|
|
459
|
+
if (state.localBindings.has(callee.text)) return void 0;
|
|
460
|
+
if (!ts.isIdentifier(declaration.name)) return void 0;
|
|
461
|
+
return ts.factory.createCallExpression(helperRef(state, "hmrStateRef"), void 0, [
|
|
462
|
+
ts.factory.createStringLiteral(`${state.hmrModuleId}#${declaration.name.text}`),
|
|
463
|
+
ts.factory.createArrowFunction(
|
|
464
|
+
void 0,
|
|
465
|
+
void 0,
|
|
466
|
+
[],
|
|
467
|
+
void 0,
|
|
468
|
+
ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken),
|
|
469
|
+
initializer
|
|
470
|
+
)
|
|
471
|
+
]);
|
|
472
|
+
}
|
|
473
|
+
__name(wrapStateWithHmrRef, "wrapStateWithHmrRef");
|
|
446
474
|
function containsJsx(expression) {
|
|
447
475
|
let found = false;
|
|
448
476
|
const visit = /* @__PURE__ */ __name((node) => {
|
|
@@ -703,6 +731,27 @@ function transformEmbeddedExpression(state, expression) {
|
|
|
703
731
|
}
|
|
704
732
|
}
|
|
705
733
|
__name(transformEmbeddedExpression, "transformEmbeddedExpression");
|
|
734
|
+
function transformResidualJsx(state, sourceFile) {
|
|
735
|
+
if (!containsJsx(sourceFile)) return sourceFile;
|
|
736
|
+
const result = ts.transform(sourceFile, [(context) => (root) => {
|
|
737
|
+
const visit = /* @__PURE__ */ __name((node) => {
|
|
738
|
+
if (ts.isReturnStatement(node) && node.expression && containsJsx(node.expression)) {
|
|
739
|
+
return ts.factory.updateReturnStatement(node, transformEmbeddedExpression(state, node.expression));
|
|
740
|
+
}
|
|
741
|
+
if (isJsxExpression(node)) {
|
|
742
|
+
return transformJsxExpression(state, node);
|
|
743
|
+
}
|
|
744
|
+
return ts.visitEachChild(node, visit, context);
|
|
745
|
+
}, "visit");
|
|
746
|
+
return ts.visitNode(root, visit);
|
|
747
|
+
}]);
|
|
748
|
+
try {
|
|
749
|
+
return result.transformed[0];
|
|
750
|
+
} finally {
|
|
751
|
+
result.dispose();
|
|
752
|
+
}
|
|
753
|
+
}
|
|
754
|
+
__name(transformResidualJsx, "transformResidualJsx");
|
|
706
755
|
function isStaticElement(tagName, attributes, children) {
|
|
707
756
|
if (!ts.isIdentifier(tagName) || !/^[a-z]/.test(tagName.text)) return false;
|
|
708
757
|
for (const attribute of attributes.properties) {
|
|
@@ -955,36 +1004,52 @@ function createSourceLocation(node) {
|
|
|
955
1004
|
}
|
|
956
1005
|
__name(createSourceLocation, "createSourceLocation");
|
|
957
1006
|
function transformDynamicExpression(state, expression) {
|
|
1007
|
+
const converted = convertDynamicNodeExpression(state, expression);
|
|
1008
|
+
return converted ? createGetter(converted) : null;
|
|
1009
|
+
}
|
|
1010
|
+
__name(transformDynamicExpression, "transformDynamicExpression");
|
|
1011
|
+
function convertDynamicNodeExpression(state, expression) {
|
|
958
1012
|
if (ts.isBinaryExpression(expression) && expression.operatorToken.kind === ts.SyntaxKind.AmpersandAmpersandToken) {
|
|
959
1013
|
const right = unwrapExpression(expression.right);
|
|
960
|
-
if (
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
ts.factory.createNull()
|
|
967
|
-
));
|
|
1014
|
+
if (isJsxExpression(right)) {
|
|
1015
|
+
return createNodeConditional(expression.left, transformJsxExpression(state, right), null);
|
|
1016
|
+
}
|
|
1017
|
+
const convertedRight = convertDynamicNodeExpression(state, right);
|
|
1018
|
+
if (convertedRight) return createNodeConditional(expression.left, convertedRight, null);
|
|
1019
|
+
return null;
|
|
968
1020
|
}
|
|
969
1021
|
if (ts.isConditionalExpression(expression)) {
|
|
970
1022
|
const whenTrue = transformDynamicBranch(state, expression.whenTrue);
|
|
971
1023
|
const whenFalse = transformDynamicBranch(state, expression.whenFalse);
|
|
972
1024
|
if (!whenTrue && !whenFalse) return null;
|
|
973
|
-
return
|
|
1025
|
+
return ts.factory.createConditionalExpression(
|
|
974
1026
|
expression.condition,
|
|
975
1027
|
ts.factory.createToken(ts.SyntaxKind.QuestionToken),
|
|
976
1028
|
whenTrue ?? ts.factory.createNull(),
|
|
977
1029
|
ts.factory.createToken(ts.SyntaxKind.ColonToken),
|
|
978
1030
|
whenFalse ?? ts.factory.createNull()
|
|
979
|
-
)
|
|
1031
|
+
);
|
|
980
1032
|
}
|
|
981
1033
|
return null;
|
|
982
1034
|
}
|
|
983
|
-
__name(
|
|
1035
|
+
__name(convertDynamicNodeExpression, "convertDynamicNodeExpression");
|
|
1036
|
+
function createNodeConditional(condition, whenTrue, whenFalse) {
|
|
1037
|
+
return ts.factory.createConditionalExpression(
|
|
1038
|
+
condition,
|
|
1039
|
+
ts.factory.createToken(ts.SyntaxKind.QuestionToken),
|
|
1040
|
+
whenTrue,
|
|
1041
|
+
ts.factory.createToken(ts.SyntaxKind.ColonToken),
|
|
1042
|
+
whenFalse ?? ts.factory.createNull()
|
|
1043
|
+
);
|
|
1044
|
+
}
|
|
1045
|
+
__name(createNodeConditional, "createNodeConditional");
|
|
984
1046
|
function transformDynamicBranch(state, expression) {
|
|
985
1047
|
const branch = unwrapExpression(expression);
|
|
986
1048
|
if (isJsxExpression(branch)) return transformJsxExpression(state, branch);
|
|
987
1049
|
if (branch.kind === ts.SyntaxKind.NullKeyword || branch.kind === ts.SyntaxKind.FalseKeyword) return branch;
|
|
1050
|
+
if (ts.isConditionalExpression(branch) || ts.isBinaryExpression(branch) && branch.operatorToken.kind === ts.SyntaxKind.AmpersandAmpersandToken) {
|
|
1051
|
+
return convertDynamicNodeExpression(state, branch);
|
|
1052
|
+
}
|
|
988
1053
|
return null;
|
|
989
1054
|
}
|
|
990
1055
|
__name(transformDynamicBranch, "transformDynamicBranch");
|
|
@@ -1135,6 +1200,9 @@ function nextIdentifier(state, prefix) {
|
|
|
1135
1200
|
return ts.factory.createIdentifier(name);
|
|
1136
1201
|
}
|
|
1137
1202
|
__name(nextIdentifier, "nextIdentifier");
|
|
1203
|
+
|
|
1204
|
+
// packages/compiler/src/i18n-extractor.ts
|
|
1205
|
+
import ts2 from "typescript";
|
|
1138
1206
|
function createI18nExtractor(options = {}) {
|
|
1139
1207
|
const names = new Set(options.functions ?? ["t"]);
|
|
1140
1208
|
const keys = /* @__PURE__ */ new Set();
|
|
@@ -1142,14 +1210,14 @@ function createI18nExtractor(options = {}) {
|
|
|
1142
1210
|
name: "i18n-extractor",
|
|
1143
1211
|
analyze(program, context) {
|
|
1144
1212
|
const visit = /* @__PURE__ */ __name((node) => {
|
|
1145
|
-
if (
|
|
1213
|
+
if (ts2.isCallExpression(node) && isTranslationCall(node.expression, names)) {
|
|
1146
1214
|
const key = readStaticKey(node.arguments[0]);
|
|
1147
1215
|
if (key) {
|
|
1148
1216
|
keys.add(key);
|
|
1149
1217
|
options.onKey?.(key, context.filename);
|
|
1150
1218
|
}
|
|
1151
1219
|
}
|
|
1152
|
-
|
|
1220
|
+
ts2.forEachChild(node, visit);
|
|
1153
1221
|
}, "visit");
|
|
1154
1222
|
visit(program);
|
|
1155
1223
|
}
|
|
@@ -1162,17 +1230,20 @@ function createI18nExtractor(options = {}) {
|
|
|
1162
1230
|
}
|
|
1163
1231
|
__name(createI18nExtractor, "createI18nExtractor");
|
|
1164
1232
|
function isTranslationCall(expression, names) {
|
|
1165
|
-
if (
|
|
1166
|
-
return
|
|
1233
|
+
if (ts2.isIdentifier(expression)) return names.has(expression.text);
|
|
1234
|
+
return ts2.isPropertyAccessExpression(expression) && names.has(expression.name.text);
|
|
1167
1235
|
}
|
|
1168
1236
|
__name(isTranslationCall, "isTranslationCall");
|
|
1169
1237
|
function readStaticKey(argument) {
|
|
1170
1238
|
if (!argument) return void 0;
|
|
1171
|
-
if (
|
|
1239
|
+
if (ts2.isStringLiteral(argument) || ts2.isNoSubstitutionTemplateLiteral(argument)) return argument.text;
|
|
1172
1240
|
return void 0;
|
|
1173
1241
|
}
|
|
1174
1242
|
__name(readStaticKey, "readStaticKey");
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1243
|
+
export {
|
|
1244
|
+
compile,
|
|
1245
|
+
compileWithSourceMap,
|
|
1246
|
+
createCompiler,
|
|
1247
|
+
createI18nExtractor
|
|
1248
|
+
};
|
|
1178
1249
|
//# sourceMappingURL=index.js.map
|