@xaendar/compiler 0.6.19 → 0.6.20
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/xaendar-compiler.es.js +89 -102
- package/package.json +3 -3
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Stack, indent } from "@xaendar/common";
|
|
2
|
-
import ts from "typescript";
|
|
2
|
+
import ts, { ScriptTarget, SyntaxKind, createSourceFile, forEachChild, isExpressionStatement, isIdentifier } from "typescript";
|
|
3
3
|
//#region ../packages/compiler/src/lexer/types/lexer-state.enum.ts
|
|
4
4
|
/**
|
|
5
5
|
* Represents the set of states the lexer can be in while processing template input.
|
|
@@ -196,7 +196,8 @@ function consumeAttributeValue(cursor, _context) {
|
|
|
196
196
|
tokens: [{
|
|
197
197
|
type: TokenType.ATTRIBUTE_VALUE,
|
|
198
198
|
parts: [value]
|
|
199
|
-
}]
|
|
199
|
+
}],
|
|
200
|
+
popState: true
|
|
200
201
|
};
|
|
201
202
|
break;
|
|
202
203
|
default:
|
|
@@ -658,29 +659,6 @@ function addCharacter(cursor, interpolation) {
|
|
|
658
659
|
return `${interpolation}${cursor.currentChar.value}`;
|
|
659
660
|
}
|
|
660
661
|
//#endregion
|
|
661
|
-
//#region ../packages/compiler/src/utils/chars.utils.ts
|
|
662
|
-
/**
|
|
663
|
-
* Checks whether a string contains at least one non-whitespace character.
|
|
664
|
-
*
|
|
665
|
-
* Whitespace characters include space, `\n`, `\r`, `\t`, `\f`, and `\v`.
|
|
666
|
-
*
|
|
667
|
-
* @param str - The string to check.
|
|
668
|
-
* @returns `true` if the string is not blank, `false` if it consists entirely of whitespace.
|
|
669
|
-
*/
|
|
670
|
-
function isNotBlank(str) {
|
|
671
|
-
return /\S/.test(str);
|
|
672
|
-
}
|
|
673
|
-
/**
|
|
674
|
-
* Checks whether the given ASCII code is a valid first character for a
|
|
675
|
-
* JavaScript identifier (`A`–`Z`, `a`–`z`, `$`, `_`).
|
|
676
|
-
*
|
|
677
|
-
* @param code - The ASCII code to evaluate.
|
|
678
|
-
* @returns `true` if the code can start a JS identifier, `false` otherwise.
|
|
679
|
-
*/
|
|
680
|
-
function isJSIdentifierStart(code) {
|
|
681
|
-
return code >= 65 && code <= 90 || code >= 97 && code <= 122 || code === 36 || code === 95;
|
|
682
|
-
}
|
|
683
|
-
//#endregion
|
|
684
662
|
//#region ../packages/compiler/src/lexer/states/interpolation.state.ts
|
|
685
663
|
/**
|
|
686
664
|
* Dispatches between an expression and a literal interpolation after the opening `{`.
|
|
@@ -692,14 +670,9 @@ function isJSIdentifierStart(code) {
|
|
|
692
670
|
* @returns Transition result with the appropriate interpolation sub-state.
|
|
693
671
|
*/
|
|
694
672
|
function consumeInterpolation(cursor, _context) {
|
|
695
|
-
let retVal;
|
|
696
673
|
cursor.advance();
|
|
697
674
|
cursor.skipSpaces();
|
|
698
|
-
|
|
699
|
-
if (nextChar === 96) retVal = { state: LexerState.INTERPOLATION_LITERAL };
|
|
700
|
-
else if (isJSIdentifierStart(nextChar)) retVal = { state: LexerState.INTERPOLATION_EXPRESSION };
|
|
701
|
-
else throw new Error(`Unrecognized First Character ${String.fromCharCode(nextChar)} in interpolation`);
|
|
702
|
-
return retVal;
|
|
675
|
+
return cursor.peek() === 96 ? { state: LexerState.INTERPOLATION_LITERAL } : { state: LexerState.INTERPOLATION_EXPRESSION };
|
|
703
676
|
}
|
|
704
677
|
//#endregion
|
|
705
678
|
//#region ../packages/compiler/src/lexer/states/tag-body.state.ts
|
|
@@ -842,6 +815,19 @@ function consumeTagOpenName(cursor, _context) {
|
|
|
842
815
|
return retVal;
|
|
843
816
|
}
|
|
844
817
|
//#endregion
|
|
818
|
+
//#region ../packages/compiler/src/utils/chars.utils.ts
|
|
819
|
+
/**
|
|
820
|
+
* Checks whether a string contains at least one non-whitespace character.
|
|
821
|
+
*
|
|
822
|
+
* Whitespace characters include space, `\n`, `\r`, `\t`, `\f`, and `\v`.
|
|
823
|
+
*
|
|
824
|
+
* @param str - The string to check.
|
|
825
|
+
* @returns `true` if the string is not blank, `false` if it consists entirely of whitespace.
|
|
826
|
+
*/
|
|
827
|
+
function isNotBlank(str) {
|
|
828
|
+
return /\S/.test(str);
|
|
829
|
+
}
|
|
830
|
+
//#endregion
|
|
845
831
|
//#region ../packages/compiler/src/lexer/states/text.state.ts
|
|
846
832
|
/**
|
|
847
833
|
* Consumes plain text content, accumulating characters until a structural boundary
|
|
@@ -1315,7 +1301,7 @@ var ASTNodeType = /* @__PURE__ */ function(ASTNodeType) {
|
|
|
1315
1301
|
* // "'await' is not allowed inside template expressions."
|
|
1316
1302
|
*/
|
|
1317
1303
|
function validateExpression(source) {
|
|
1318
|
-
const expression =
|
|
1304
|
+
const expression = createSourceFile("expression.ts", `const x = ${source}`, ScriptTarget.ESNext, true).statements[0].declarationList.declarations[0].initializer;
|
|
1319
1305
|
const diagnostics = new Array();
|
|
1320
1306
|
visitNode(expression, 10, diagnostics);
|
|
1321
1307
|
if (diagnostics.length) throw new Error(diagnostics.reduce((acc, d) => `${acc}${d.message}\n`, ""));
|
|
@@ -1335,7 +1321,7 @@ function validateExpression(source) {
|
|
|
1335
1321
|
*/
|
|
1336
1322
|
function visitNode(node, offset, diagnostics) {
|
|
1337
1323
|
if (!isAllowedNode(node)) throw new Error(buildDisallowedMessage(node));
|
|
1338
|
-
|
|
1324
|
+
forEachChild(node, (child) => visitNode(child, offset, diagnostics));
|
|
1339
1325
|
if (diagnostics.length) throw new Error(diagnostics[0].message);
|
|
1340
1326
|
}
|
|
1341
1327
|
/**
|
|
@@ -1348,62 +1334,63 @@ function visitNode(node, offset, diagnostics) {
|
|
|
1348
1334
|
*/
|
|
1349
1335
|
function isAllowedNode(node) {
|
|
1350
1336
|
switch (node.kind) {
|
|
1351
|
-
case
|
|
1352
|
-
case
|
|
1353
|
-
case
|
|
1354
|
-
case
|
|
1355
|
-
case
|
|
1356
|
-
case
|
|
1357
|
-
case
|
|
1358
|
-
case
|
|
1359
|
-
case
|
|
1360
|
-
case
|
|
1361
|
-
case
|
|
1362
|
-
case
|
|
1363
|
-
case
|
|
1364
|
-
case
|
|
1365
|
-
case
|
|
1366
|
-
case
|
|
1367
|
-
case
|
|
1368
|
-
case
|
|
1369
|
-
case
|
|
1370
|
-
case
|
|
1371
|
-
case
|
|
1372
|
-
case
|
|
1373
|
-
case
|
|
1374
|
-
case
|
|
1375
|
-
case
|
|
1376
|
-
case
|
|
1377
|
-
case
|
|
1378
|
-
case
|
|
1379
|
-
case
|
|
1380
|
-
case
|
|
1381
|
-
case
|
|
1382
|
-
case
|
|
1383
|
-
case
|
|
1384
|
-
case
|
|
1385
|
-
case
|
|
1386
|
-
case
|
|
1387
|
-
case
|
|
1388
|
-
case
|
|
1389
|
-
case
|
|
1390
|
-
case
|
|
1391
|
-
case
|
|
1392
|
-
case
|
|
1393
|
-
case
|
|
1394
|
-
case
|
|
1395
|
-
case
|
|
1396
|
-
case
|
|
1397
|
-
case
|
|
1398
|
-
case
|
|
1399
|
-
case
|
|
1400
|
-
case
|
|
1401
|
-
case
|
|
1402
|
-
case
|
|
1403
|
-
case
|
|
1404
|
-
case
|
|
1405
|
-
case
|
|
1406
|
-
case
|
|
1337
|
+
case SyntaxKind.StringLiteral:
|
|
1338
|
+
case SyntaxKind.NumericLiteral:
|
|
1339
|
+
case SyntaxKind.BigIntLiteral:
|
|
1340
|
+
case SyntaxKind.TrueKeyword:
|
|
1341
|
+
case SyntaxKind.FalseKeyword:
|
|
1342
|
+
case SyntaxKind.NullKeyword:
|
|
1343
|
+
case SyntaxKind.UndefinedKeyword:
|
|
1344
|
+
case SyntaxKind.Identifier:
|
|
1345
|
+
case SyntaxKind.PropertyAccessExpression:
|
|
1346
|
+
case SyntaxKind.ElementAccessExpression:
|
|
1347
|
+
case SyntaxKind.CallExpression:
|
|
1348
|
+
case SyntaxKind.BinaryExpression:
|
|
1349
|
+
case SyntaxKind.EqualsEqualsToken:
|
|
1350
|
+
case SyntaxKind.EqualsEqualsEqualsToken:
|
|
1351
|
+
case SyntaxKind.ExclamationEqualsToken:
|
|
1352
|
+
case SyntaxKind.ExclamationEqualsEqualsToken:
|
|
1353
|
+
case SyntaxKind.LessThanToken:
|
|
1354
|
+
case SyntaxKind.LessThanEqualsToken:
|
|
1355
|
+
case SyntaxKind.GreaterThanToken:
|
|
1356
|
+
case SyntaxKind.GreaterThanEqualsToken:
|
|
1357
|
+
case SyntaxKind.PlusToken:
|
|
1358
|
+
case SyntaxKind.MinusToken:
|
|
1359
|
+
case SyntaxKind.AsteriskToken:
|
|
1360
|
+
case SyntaxKind.SlashToken:
|
|
1361
|
+
case SyntaxKind.PercentToken:
|
|
1362
|
+
case SyntaxKind.AsteriskAsteriskToken:
|
|
1363
|
+
case SyntaxKind.AmpersandAmpersandToken:
|
|
1364
|
+
case SyntaxKind.BarBarToken:
|
|
1365
|
+
case SyntaxKind.QuestionQuestionToken:
|
|
1366
|
+
case SyntaxKind.QuestionDotToken:
|
|
1367
|
+
case SyntaxKind.AmpersandToken:
|
|
1368
|
+
case SyntaxKind.BarToken:
|
|
1369
|
+
case SyntaxKind.CaretToken:
|
|
1370
|
+
case SyntaxKind.LessThanLessThanToken:
|
|
1371
|
+
case SyntaxKind.GreaterThanGreaterThanToken:
|
|
1372
|
+
case SyntaxKind.GreaterThanGreaterThanGreaterThanToken:
|
|
1373
|
+
case SyntaxKind.InstanceOfKeyword:
|
|
1374
|
+
case SyntaxKind.InKeyword:
|
|
1375
|
+
case SyntaxKind.PrefixUnaryExpression:
|
|
1376
|
+
case SyntaxKind.PostfixUnaryExpression:
|
|
1377
|
+
case SyntaxKind.TypeOfExpression:
|
|
1378
|
+
case SyntaxKind.VoidExpression:
|
|
1379
|
+
case SyntaxKind.ConditionalExpression:
|
|
1380
|
+
case SyntaxKind.ParenthesizedExpression:
|
|
1381
|
+
case SyntaxKind.TemplateExpression:
|
|
1382
|
+
case SyntaxKind.NoSubstitutionTemplateLiteral:
|
|
1383
|
+
case SyntaxKind.TemplateHead:
|
|
1384
|
+
case SyntaxKind.TemplateMiddle:
|
|
1385
|
+
case SyntaxKind.TemplateTail:
|
|
1386
|
+
case SyntaxKind.TemplateSpan:
|
|
1387
|
+
case SyntaxKind.ArrayLiteralExpression:
|
|
1388
|
+
case SyntaxKind.ObjectLiteralExpression:
|
|
1389
|
+
case SyntaxKind.PropertyAssignment:
|
|
1390
|
+
case SyntaxKind.ShorthandPropertyAssignment:
|
|
1391
|
+
case SyntaxKind.SpreadAssignment:
|
|
1392
|
+
case SyntaxKind.SpreadElement:
|
|
1393
|
+
case SyntaxKind.SyntaxList: return true;
|
|
1407
1394
|
default: return false;
|
|
1408
1395
|
}
|
|
1409
1396
|
}
|
|
@@ -1416,25 +1403,25 @@ function isAllowedNode(node) {
|
|
|
1416
1403
|
*/
|
|
1417
1404
|
function buildDisallowedMessage(node) {
|
|
1418
1405
|
switch (node.kind) {
|
|
1419
|
-
case
|
|
1420
|
-
case
|
|
1421
|
-
case
|
|
1422
|
-
case
|
|
1423
|
-
case
|
|
1424
|
-
case
|
|
1425
|
-
case
|
|
1426
|
-
default: return `'${
|
|
1406
|
+
case SyntaxKind.AwaitExpression: return "'await' is not allowed inside template expressions.";
|
|
1407
|
+
case SyntaxKind.YieldExpression: return "'yield' is not allowed inside template expressions.";
|
|
1408
|
+
case SyntaxKind.NewExpression: return "'new' is not allowed inside template expressions.";
|
|
1409
|
+
case SyntaxKind.ArrowFunction:
|
|
1410
|
+
case SyntaxKind.FunctionExpression: return "Function expressions are not allowed inside template expressions.";
|
|
1411
|
+
case SyntaxKind.TaggedTemplateExpression: return "Tagged template expressions are not allowed inside template expressions.";
|
|
1412
|
+
case SyntaxKind.BinaryExpression: return isAssignmentOperator(node.operatorToken.kind) ? "Assignments are not allowed inside template expressions. Use @const to declare local template variables instead." : `'${SyntaxKind[node.kind]}' is not allowed inside template expressions.`;
|
|
1413
|
+
default: return `'${SyntaxKind[node.kind]}' is not allowed inside template expressions.`;
|
|
1427
1414
|
}
|
|
1428
1415
|
}
|
|
1429
1416
|
/**
|
|
1430
|
-
* Returns `true` if the given {@link
|
|
1417
|
+
* Returns `true` if the given {@link SyntaxKind} is an assignment operator.
|
|
1431
1418
|
*
|
|
1432
1419
|
* Covers simple assignment (`=`) as well as all compound assignment operators
|
|
1433
1420
|
* (`+=`, `-=`, `&&=`, `||=`, `??=`, etc.) as defined by the TypeScript
|
|
1434
1421
|
* `FirstAssignment`–`LastAssignment` range.
|
|
1435
1422
|
*/
|
|
1436
1423
|
function isAssignmentOperator(kind) {
|
|
1437
|
-
return kind >=
|
|
1424
|
+
return kind >= SyntaxKind.FirstAssignment && kind <= SyntaxKind.LastAssignment;
|
|
1438
1425
|
}
|
|
1439
1426
|
//#endregion
|
|
1440
1427
|
//#region ../packages/compiler/src/parser/states/parse-interpolation.state.ts
|
|
@@ -1756,8 +1743,8 @@ function splitForSections(source) {
|
|
|
1756
1743
|
*/
|
|
1757
1744
|
function isValidIdentifier(name) {
|
|
1758
1745
|
if (!name.length) return false;
|
|
1759
|
-
const statement =
|
|
1760
|
-
return !!statement &&
|
|
1746
|
+
const statement = createSourceFile("__id.ts", name, ScriptTarget.ESNext, false).statements[0];
|
|
1747
|
+
return !!statement && isExpressionStatement(statement) && isIdentifier(statement.expression) && statement.expression.text === name;
|
|
1761
1748
|
}
|
|
1762
1749
|
//#endregion
|
|
1763
1750
|
//#region ../packages/compiler/src/parser/states/parse-if.state.ts
|
|
@@ -2426,7 +2413,7 @@ function processFor(node, nodeName, parentNode, compilerContext) {
|
|
|
2426
2413
|
counterName
|
|
2427
2414
|
]
|
|
2428
2415
|
});
|
|
2429
|
-
mainBlock.push(`_for(${parentNode}, context, () => ${iterableExpr}, this.${forKey}.bind(this));`);
|
|
2416
|
+
mainBlock.push(`_for(${parentNode}, context, () => ${iterableExpr}, (${node.itemAlias}) => ${resolveExpression(node.trackExpression, forContext)}, this.${forKey}.bind(this));`);
|
|
2430
2417
|
return {
|
|
2431
2418
|
mainBlock,
|
|
2432
2419
|
fns: functionsToProcess
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xaendar/compiler",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.20",
|
|
4
4
|
"description": "A library for transpiling Xaendar Templates into JavaScript code",
|
|
5
5
|
"sideEffects": false,
|
|
6
6
|
"type": "module",
|
|
@@ -16,8 +16,8 @@
|
|
|
16
16
|
}
|
|
17
17
|
},
|
|
18
18
|
"dependencies": {
|
|
19
|
-
"@xaendar/common": "0.6.
|
|
20
|
-
"@xaendar/types": "0.6.
|
|
19
|
+
"@xaendar/common": "0.6.20",
|
|
20
|
+
"@xaendar/types": "0.6.20",
|
|
21
21
|
"typescript": "^6.0.3"
|
|
22
22
|
}
|
|
23
23
|
}
|