@xaendar/cli 0.2.0 → 0.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/index.js +217 -1264
- package/index.js.map +1 -1
- package/package.json +2 -2
package/index.js
CHANGED
|
@@ -6,7 +6,7 @@ var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
|
6
6
|
var __getProtoOf = Object.getPrototypeOf;
|
|
7
7
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
8
|
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
9
|
-
get: (
|
|
9
|
+
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
10
10
|
}) : x)(function(x) {
|
|
11
11
|
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
12
12
|
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
@@ -230,8 +230,8 @@ var require_help = __commonJS({
|
|
|
230
230
|
visibleCommands.push(helpCommand);
|
|
231
231
|
}
|
|
232
232
|
if (this.sortSubcommands) {
|
|
233
|
-
visibleCommands.sort((
|
|
234
|
-
return
|
|
233
|
+
visibleCommands.sort((a, b) => {
|
|
234
|
+
return a.name().localeCompare(b.name());
|
|
235
235
|
});
|
|
236
236
|
}
|
|
237
237
|
return visibleCommands;
|
|
@@ -243,11 +243,11 @@ var require_help = __commonJS({
|
|
|
243
243
|
* @param {Option} b
|
|
244
244
|
* @returns {number}
|
|
245
245
|
*/
|
|
246
|
-
compareOptions(
|
|
246
|
+
compareOptions(a, b) {
|
|
247
247
|
const getSortKey = (option) => {
|
|
248
248
|
return option.short ? option.short.replace(/^-/, "") : option.long.replace(/^--/, "");
|
|
249
249
|
};
|
|
250
|
-
return getSortKey(
|
|
250
|
+
return getSortKey(a).localeCompare(getSortKey(b));
|
|
251
251
|
}
|
|
252
252
|
/**
|
|
253
253
|
* Get an array of the visible options. Includes a placeholder for the implicit help option, if there is one.
|
|
@@ -1113,20 +1113,20 @@ var require_option = __commonJS({
|
|
|
1113
1113
|
var require_suggestSimilar = __commonJS({
|
|
1114
1114
|
"../node_modules/commander/lib/suggestSimilar.js"(exports) {
|
|
1115
1115
|
var maxDistance = 3;
|
|
1116
|
-
function editDistance(
|
|
1117
|
-
if (Math.abs(
|
|
1118
|
-
return Math.max(
|
|
1116
|
+
function editDistance(a, b) {
|
|
1117
|
+
if (Math.abs(a.length - b.length) > maxDistance)
|
|
1118
|
+
return Math.max(a.length, b.length);
|
|
1119
1119
|
const d = [];
|
|
1120
|
-
for (let i = 0; i <=
|
|
1120
|
+
for (let i = 0; i <= a.length; i++) {
|
|
1121
1121
|
d[i] = [i];
|
|
1122
1122
|
}
|
|
1123
1123
|
for (let j = 0; j <= b.length; j++) {
|
|
1124
1124
|
d[0][j] = j;
|
|
1125
1125
|
}
|
|
1126
1126
|
for (let j = 1; j <= b.length; j++) {
|
|
1127
|
-
for (let i = 1; i <=
|
|
1127
|
+
for (let i = 1; i <= a.length; i++) {
|
|
1128
1128
|
let cost = 1;
|
|
1129
|
-
if (
|
|
1129
|
+
if (a[i - 1] === b[j - 1]) {
|
|
1130
1130
|
cost = 0;
|
|
1131
1131
|
} else {
|
|
1132
1132
|
cost = 1;
|
|
@@ -1139,12 +1139,12 @@ var require_suggestSimilar = __commonJS({
|
|
|
1139
1139
|
d[i - 1][j - 1] + cost
|
|
1140
1140
|
// substitution
|
|
1141
1141
|
);
|
|
1142
|
-
if (i > 1 && j > 1 &&
|
|
1142
|
+
if (i > 1 && j > 1 && a[i - 1] === b[j - 2] && a[i - 2] === b[j - 1]) {
|
|
1143
1143
|
d[i][j] = Math.min(d[i][j], d[i - 2][j - 2] + 1);
|
|
1144
1144
|
}
|
|
1145
1145
|
}
|
|
1146
1146
|
}
|
|
1147
|
-
return d[
|
|
1147
|
+
return d[a.length][b.length];
|
|
1148
1148
|
}
|
|
1149
1149
|
function suggestSimilar(word, candidates) {
|
|
1150
1150
|
if (!candidates || candidates.length === 0) return "";
|
|
@@ -1171,7 +1171,7 @@ var require_suggestSimilar = __commonJS({
|
|
|
1171
1171
|
}
|
|
1172
1172
|
}
|
|
1173
1173
|
});
|
|
1174
|
-
similar.sort((
|
|
1174
|
+
similar.sort((a, b) => a.localeCompare(b));
|
|
1175
1175
|
if (searchingOptions) {
|
|
1176
1176
|
similar = similar.map((candidate) => `--${candidate}`);
|
|
1177
1177
|
}
|
|
@@ -3477,8 +3477,9 @@ var {
|
|
|
3477
3477
|
// ../packages/cli/src/commands/generate/component/component.command.ts
|
|
3478
3478
|
import { mkdirSync, writeFileSync, existsSync, rmSync } from "fs";
|
|
3479
3479
|
import { join } from "path";
|
|
3480
|
-
function generateComponent(name, path, force) {
|
|
3480
|
+
function generateComponent(name, path, force, style) {
|
|
3481
3481
|
const dir = join(path, name);
|
|
3482
|
+
style ??= "css";
|
|
3482
3483
|
if (existsSync(dir)) {
|
|
3483
3484
|
if (force) {
|
|
3484
3485
|
console.log(`Deleting "${name}"...`);
|
|
@@ -3491,9 +3492,9 @@ function generateComponent(name, path, force) {
|
|
|
3491
3492
|
}
|
|
3492
3493
|
mkdirSync(dir, { recursive: true });
|
|
3493
3494
|
const files = [
|
|
3494
|
-
[`${name}.xd.component.ts`, tsTemplate(name)],
|
|
3495
|
+
[`${name}.xd.component.ts`, tsTemplate(name, style)],
|
|
3495
3496
|
[`${name}.xd.component.html`, htmlTemplate(name)],
|
|
3496
|
-
[`${name}.xd.component
|
|
3497
|
+
[`${name}.xd.component.${style}`, cssTemplate(name)],
|
|
3497
3498
|
[`${name}.xd.component.spec.ts`, specTemplate(name)]
|
|
3498
3499
|
];
|
|
3499
3500
|
for (const [filename, content] of files) {
|
|
@@ -3505,13 +3506,13 @@ function generateComponent(name, path, force) {
|
|
|
3505
3506
|
console.log(`${name}/${filename}`);
|
|
3506
3507
|
}
|
|
3507
3508
|
}
|
|
3508
|
-
function tsTemplate(name) {
|
|
3509
|
+
function tsTemplate(name, style) {
|
|
3509
3510
|
const className = toPascalCase(name);
|
|
3510
3511
|
return `import { BaseWebComponent, WebComponent } from '@xaendar/core';
|
|
3511
3512
|
|
|
3512
3513
|
@WebComponent({
|
|
3513
3514
|
selector: '${toKebabCase(name)}',
|
|
3514
|
-
styleUrl: './${name}.xd.component
|
|
3515
|
+
styleUrl: './${name}.xd.component.${style}',
|
|
3515
3516
|
templateUrl: './${name}.xd.component.html'
|
|
3516
3517
|
})
|
|
3517
3518
|
export class ${className}Component extends BaseWebComponent {
|
|
@@ -3528,8 +3529,7 @@ function cssTemplate(_name) {
|
|
|
3528
3529
|
}
|
|
3529
3530
|
function specTemplate(name) {
|
|
3530
3531
|
const className = toPascalCase(name);
|
|
3531
|
-
return `
|
|
3532
|
-
import { describe, expect, it } from "vitest";
|
|
3532
|
+
return `import { describe, expect, it } from "vitest";
|
|
3533
3533
|
import { ${className}Component } from './${name}.xd.component';
|
|
3534
3534
|
|
|
3535
3535
|
describe('${className}Component', () => {
|
|
@@ -3548,8 +3548,8 @@ function toKebabCase(str) {
|
|
|
3548
3548
|
}
|
|
3549
3549
|
|
|
3550
3550
|
// ../packages/cli/src/commands/generate/generate.command.ts
|
|
3551
|
-
function
|
|
3552
|
-
const generate = new Command("generate").alias("g").description("Generate
|
|
3551
|
+
function generateCommand() {
|
|
3552
|
+
const generate = new Command("generate").alias("g").description("Generate Xaendar building blocks");
|
|
3553
3553
|
generate.command("component <name>").alias("c").option("-p, --path <path>", "Custom path for the generated component (default: current directory)").option("-f, --force", "Force generation deleting current component if already exists").description("Generate a new component (creates <name>/ folder with .ts, .html, .css, .spec.ts)").action((name, options) => {
|
|
3554
3554
|
const path = options.path || process.cwd();
|
|
3555
3555
|
generateComponent(name, path, !!options.force);
|
|
@@ -3557,1286 +3557,239 @@ function makeGenerateCommand() {
|
|
|
3557
3557
|
return generate;
|
|
3558
3558
|
}
|
|
3559
3559
|
|
|
3560
|
-
// ../packages/
|
|
3561
|
-
|
|
3562
|
-
|
|
3563
|
-
* Internal array holding the stack elements, ordered from bottom to top.
|
|
3564
|
-
*/
|
|
3565
|
-
_elements = new Array();
|
|
3566
|
-
constructor() {
|
|
3567
|
-
return new Proxy(this, {
|
|
3568
|
-
get(target, prop) {
|
|
3569
|
-
return isNaN(Number(prop)) ? target[prop] : target._elements[Number(prop)];
|
|
3570
|
-
}
|
|
3571
|
-
});
|
|
3572
|
-
}
|
|
3573
|
-
/**
|
|
3574
|
-
* The number of elements currently in the stack.
|
|
3575
|
-
*/
|
|
3576
|
-
get length() {
|
|
3577
|
-
return this._elements.length;
|
|
3578
|
-
}
|
|
3579
|
-
/**
|
|
3580
|
-
* A shallow copy of the elements in the stack, ordered from bottom to top.
|
|
3581
|
-
*/
|
|
3582
|
-
get values() {
|
|
3583
|
-
return [...this._elements];
|
|
3584
|
-
}
|
|
3585
|
-
/**
|
|
3586
|
-
* Removes and returns the top element of the stack.
|
|
3587
|
-
*
|
|
3588
|
-
* @returns The top element, or `undefined` if the stack is empty.
|
|
3589
|
-
*/
|
|
3590
|
-
pop() {
|
|
3591
|
-
return this._elements.pop();
|
|
3592
|
-
}
|
|
3593
|
-
/**
|
|
3594
|
-
* Pushes an element onto the top of the stack.
|
|
3595
|
-
*
|
|
3596
|
-
* @param element - The element to push.
|
|
3597
|
-
* @returns The new length of the stack.
|
|
3598
|
-
*/
|
|
3599
|
-
push(element) {
|
|
3600
|
-
return this._elements.push(element);
|
|
3601
|
-
}
|
|
3602
|
-
};
|
|
3603
|
-
|
|
3604
|
-
// ../packages/compiler/src/costants/chars.constants.ts
|
|
3605
|
-
var EOF = 0;
|
|
3606
|
-
var LF = 10;
|
|
3607
|
-
var CR = 13;
|
|
3608
|
-
var SPACE = 32;
|
|
3609
|
-
var LPAREN = 40;
|
|
3610
|
-
var RPAREN = 41;
|
|
3611
|
-
var SLASH = 47;
|
|
3612
|
-
var LESS_THAN = 60;
|
|
3613
|
-
var GREATER_THEN = 62;
|
|
3614
|
-
var AT_SIGN = 64;
|
|
3615
|
-
var GRAVE_ACCENT = 96;
|
|
3616
|
-
var LEFT_BRACE = 123;
|
|
3617
|
-
var RIGHT_BRACE = 125;
|
|
3560
|
+
// ../packages/cli/src/commands/new/new.command.ts
|
|
3561
|
+
import { existsSync as existsSync2, mkdirSync as mkdirSync2, readdirSync, writeFileSync as writeFileSync2 } from "fs";
|
|
3562
|
+
import { resolve } from "path/win32";
|
|
3618
3563
|
|
|
3619
|
-
// ../packages/
|
|
3620
|
-
|
|
3621
|
-
/**
|
|
3622
|
-
* Creates a new cursor for the given input source.
|
|
3623
|
-
*
|
|
3624
|
-
* @param input Full source string to be tokenized.
|
|
3625
|
-
*/
|
|
3626
|
-
constructor(input) {
|
|
3627
|
-
this.input = input;
|
|
3628
|
-
}
|
|
3629
|
-
input;
|
|
3630
|
-
/**
|
|
3631
|
-
* Representation of the current character.
|
|
3632
|
-
*
|
|
3633
|
-
* - `index`: absolute index within the input string
|
|
3634
|
-
* - `code`: Unicode code point of the character
|
|
3635
|
-
* - `value`: actual character value
|
|
3636
|
-
*
|
|
3637
|
-
* An index of `-1` indicates that the cursor has not yet consumed
|
|
3638
|
-
* any character or has reached EOF.
|
|
3639
|
-
*/
|
|
3640
|
-
_currentChar = {
|
|
3641
|
-
code: 0,
|
|
3642
|
-
index: -1,
|
|
3643
|
-
value: ""
|
|
3644
|
-
};
|
|
3645
|
-
/**
|
|
3646
|
-
* Returns a read-only snapshot of the current character.
|
|
3647
|
-
*/
|
|
3648
|
-
get currentChar() {
|
|
3649
|
-
return this._currentChar;
|
|
3650
|
-
}
|
|
3651
|
-
/**
|
|
3652
|
-
* Cache used by peek operations to avoid re-reading
|
|
3653
|
-
* the same character positions multiple times.
|
|
3654
|
-
*
|
|
3655
|
-
* Key: absolute character index
|
|
3656
|
-
* Value: Unicode code point
|
|
3657
|
-
*/
|
|
3658
|
-
_peekCache = /* @__PURE__ */ new Map();
|
|
3659
|
-
/**
|
|
3660
|
-
* Logical position of the cursor in the input.
|
|
3661
|
-
*
|
|
3662
|
-
* - `row`: zero-based line number
|
|
3663
|
-
* - `column`: zero-based column number
|
|
3664
|
-
*/
|
|
3665
|
-
_position = {
|
|
3666
|
-
row: 0,
|
|
3667
|
-
column: 0
|
|
3668
|
-
};
|
|
3669
|
-
/**
|
|
3670
|
-
* Returns a read-only snapshot of the current cursor position.
|
|
3671
|
-
*/
|
|
3672
|
-
get position() {
|
|
3673
|
-
return this._position;
|
|
3674
|
-
}
|
|
3675
|
-
/**
|
|
3676
|
-
* Advances the cursor by the specified number of characters.
|
|
3677
|
-
*
|
|
3678
|
-
* This method:
|
|
3679
|
-
* - Updates the current character
|
|
3680
|
-
* - Updates row/column position
|
|
3681
|
-
* - Detects line breaks (LF / CR)
|
|
3682
|
-
* - Throws an EOF error when the end of the input is reached
|
|
3683
|
-
*
|
|
3684
|
-
* @param chars Number of characters to consume (must be >= 1)
|
|
3685
|
-
*
|
|
3686
|
-
* @throws Error with cause `EOF` when advancing past input length
|
|
3687
|
-
*/
|
|
3688
|
-
advance(chars = 1) {
|
|
3689
|
-
if (chars < 1) {
|
|
3690
|
-
throw new Error(`${chars} is not a valid value. Please enter a number equal or greater than 1`);
|
|
3691
|
-
}
|
|
3692
|
-
const newIndex = this._currentChar.index + chars;
|
|
3693
|
-
if (newIndex >= this.input.length) {
|
|
3694
|
-
this._currentChar.code = EOF;
|
|
3695
|
-
this._currentChar.index = -1;
|
|
3696
|
-
this._currentChar.value = "";
|
|
3697
|
-
this.throwEOFError();
|
|
3698
|
-
} else {
|
|
3699
|
-
if ([LF, CR].includes(this._currentChar.code)) {
|
|
3700
|
-
this._position.row++;
|
|
3701
|
-
this._position.column = 0;
|
|
3702
|
-
} else {
|
|
3703
|
-
this._position.column++;
|
|
3704
|
-
}
|
|
3705
|
-
this._currentChar.index = newIndex;
|
|
3706
|
-
this._currentChar.value = this.input[newIndex];
|
|
3707
|
-
this._currentChar.code = this.input.charCodeAt(newIndex);
|
|
3708
|
-
}
|
|
3709
|
-
}
|
|
3710
|
-
peekMatch(pattern, length) {
|
|
3711
|
-
if (typeof pattern === "string") {
|
|
3712
|
-
const peekedChars = this.peek(pattern.length);
|
|
3713
|
-
for (let i = 0; i < pattern.length; i++) {
|
|
3714
|
-
if (peekedChars[i] !== pattern.charCodeAt(i)) {
|
|
3715
|
-
return false;
|
|
3716
|
-
}
|
|
3717
|
-
}
|
|
3718
|
-
return true;
|
|
3719
|
-
}
|
|
3720
|
-
const start = this._currentChar.index + 1;
|
|
3721
|
-
const slice = this.input.slice(start, start + length);
|
|
3722
|
-
return pattern.test(slice);
|
|
3723
|
-
}
|
|
3724
|
-
peek(charsOrOptions, options) {
|
|
3725
|
-
const cache = this._peekCache;
|
|
3726
|
-
const chars = typeof charsOrOptions === "number" ? charsOrOptions : 1;
|
|
3727
|
-
const offset = (typeof charsOrOptions === "object" ? charsOrOptions : options)?.offset ?? 0;
|
|
3728
|
-
return chars === 1 ? this.peekOneChar(this._currentChar.index + offset + 1, cache) : this.peekMany(chars + offset, cache);
|
|
3729
|
-
}
|
|
3730
|
-
/**
|
|
3731
|
-
* Skips all consecutive space characters from the current position.
|
|
3732
|
-
*/
|
|
3733
|
-
skipSpaces() {
|
|
3734
|
-
while (this.peek() === SPACE) {
|
|
3735
|
-
this.advance();
|
|
3736
|
-
}
|
|
3737
|
-
}
|
|
3738
|
-
/**
|
|
3739
|
-
* Peeks multiple characters ahead.
|
|
3740
|
-
*/
|
|
3741
|
-
peekMany(chars, cache) {
|
|
3742
|
-
const peekedChars = new Array();
|
|
3743
|
-
const nextCharIndex = this._currentChar.index + 1;
|
|
3744
|
-
for (let i = nextCharIndex; i < nextCharIndex + chars; i++) {
|
|
3745
|
-
peekedChars.push(this.peekOneChar(i, cache));
|
|
3746
|
-
}
|
|
3747
|
-
return peekedChars;
|
|
3748
|
-
}
|
|
3749
|
-
/**
|
|
3750
|
-
* Peeks a single character at the given absolute index.
|
|
3751
|
-
*/
|
|
3752
|
-
peekOneChar(index, cache) {
|
|
3753
|
-
if (cache.has(index)) {
|
|
3754
|
-
return cache.get(index);
|
|
3755
|
-
}
|
|
3756
|
-
if (index >= this.input.length) {
|
|
3757
|
-
this.throwEOFError();
|
|
3758
|
-
}
|
|
3759
|
-
const charCode = this.input.charCodeAt(index);
|
|
3760
|
-
cache.set(index, charCode);
|
|
3761
|
-
return charCode;
|
|
3762
|
-
}
|
|
3763
|
-
/**
|
|
3764
|
-
* Throws a standardized EOF error used by the lexer engine
|
|
3765
|
-
* to terminate tokenization.
|
|
3766
|
-
*/
|
|
3767
|
-
throwEOFError() {
|
|
3768
|
-
throw new Error("", { cause: EOF });
|
|
3769
|
-
}
|
|
3770
|
-
};
|
|
3564
|
+
// ../packages/cli/src/commands/new/structure.ts
|
|
3565
|
+
import { readFileSync } from "fs";
|
|
3771
3566
|
|
|
3772
|
-
// ../packages/
|
|
3773
|
-
|
|
3774
|
-
|
|
3775
|
-
|
|
3776
|
-
|
|
3777
|
-
|
|
3778
|
-
|
|
3779
|
-
|
|
3780
|
-
|
|
3781
|
-
|
|
3782
|
-
|
|
3783
|
-
|
|
3784
|
-
|
|
3785
|
-
|
|
3786
|
-
|
|
3787
|
-
|
|
3788
|
-
TokenType2[TokenType2["DEFAULT"] = 14] = "DEFAULT";
|
|
3789
|
-
TokenType2[TokenType2["CONDITION"] = 15] = "CONDITION";
|
|
3790
|
-
TokenType2[TokenType2["BLOCK_OPEN"] = 16] = "BLOCK_OPEN";
|
|
3791
|
-
TokenType2[TokenType2["BLOCK_CLOSE"] = 17] = "BLOCK_CLOSE";
|
|
3792
|
-
TokenType2[TokenType2["EOF"] = 18] = "EOF";
|
|
3793
|
-
return TokenType2;
|
|
3794
|
-
})(TokenType || {});
|
|
3795
|
-
|
|
3796
|
-
// ../packages/compiler/src/lexer/states/attribute.state.ts
|
|
3797
|
-
function consumeAttribute(cursor, _context) {
|
|
3798
|
-
let read = true;
|
|
3799
|
-
let attribute = "";
|
|
3800
|
-
let retVal;
|
|
3801
|
-
while (read) {
|
|
3802
|
-
switch (cursor.peek()) {
|
|
3803
|
-
case SPACE:
|
|
3804
|
-
case SLASH:
|
|
3805
|
-
case GREATER_THEN:
|
|
3806
|
-
retVal = {
|
|
3807
|
-
state: "tag-body" /* TAG_BODY */,
|
|
3808
|
-
tokens: [{
|
|
3809
|
-
type: 5 /* ATTRIBUTE */,
|
|
3810
|
-
parts: [attribute]
|
|
3811
|
-
}]
|
|
3812
|
-
};
|
|
3813
|
-
read = false;
|
|
3814
|
-
break;
|
|
3815
|
-
case LEFT_BRACE:
|
|
3816
|
-
retVal = {
|
|
3817
|
-
state: "interpolation" /* INTERPOLATION */,
|
|
3818
|
-
tokens: [{
|
|
3819
|
-
type: 5 /* ATTRIBUTE */,
|
|
3820
|
-
parts: [attribute]
|
|
3821
|
-
}],
|
|
3822
|
-
pushState: true
|
|
3823
|
-
};
|
|
3824
|
-
read = false;
|
|
3825
|
-
break;
|
|
3826
|
-
default:
|
|
3827
|
-
cursor.advance();
|
|
3828
|
-
attribute = `${attribute}${cursor.currentChar.value}`;
|
|
3829
|
-
}
|
|
3830
|
-
}
|
|
3831
|
-
return retVal;
|
|
3832
|
-
}
|
|
3833
|
-
|
|
3834
|
-
// ../packages/compiler/src/lexer/states/event.state.ts
|
|
3835
|
-
function consumeEvent(cursor, _context) {
|
|
3836
|
-
let read = true;
|
|
3837
|
-
let event = "";
|
|
3838
|
-
let retVal;
|
|
3839
|
-
cursor.advance();
|
|
3840
|
-
while (read) {
|
|
3841
|
-
switch (cursor.peek()) {
|
|
3842
|
-
case SPACE:
|
|
3843
|
-
case SLASH:
|
|
3844
|
-
case GREATER_THEN:
|
|
3845
|
-
retVal = {
|
|
3846
|
-
state: "tag-body" /* TAG_BODY */,
|
|
3847
|
-
tokens: [{
|
|
3848
|
-
type: 6 /* EVENT */,
|
|
3849
|
-
parts: [event]
|
|
3850
|
-
}]
|
|
3851
|
-
};
|
|
3852
|
-
read = false;
|
|
3853
|
-
break;
|
|
3854
|
-
default:
|
|
3855
|
-
cursor.advance();
|
|
3856
|
-
event = `${event}${cursor.currentChar.value}`;
|
|
3857
|
-
}
|
|
3858
|
-
}
|
|
3859
|
-
return retVal;
|
|
3860
|
-
}
|
|
3861
|
-
|
|
3862
|
-
// ../packages/compiler/src/lexer/states/flow-control.ts
|
|
3863
|
-
function consumeFlowControl(cursor, _context) {
|
|
3864
|
-
let retVal;
|
|
3865
|
-
cursor.advance();
|
|
3866
|
-
if (cursor.peekMatch("for ")) {
|
|
3867
|
-
cursor.advance(4);
|
|
3868
|
-
retVal = {
|
|
3869
|
-
state: "flow-control-condition" /* FLOW_CONTROL_CONDITION */,
|
|
3870
|
-
tokens: [{
|
|
3871
|
-
type: 10 /* FOR */
|
|
3872
|
-
}],
|
|
3873
|
-
pushState: true
|
|
3874
|
-
};
|
|
3875
|
-
} else if (cursor.peekMatch("if ")) {
|
|
3876
|
-
cursor.advance(2);
|
|
3877
|
-
retVal = {
|
|
3878
|
-
state: "flow-control-condition" /* FLOW_CONTROL_CONDITION */,
|
|
3879
|
-
tokens: [{
|
|
3880
|
-
type: 9 /* IF */
|
|
3881
|
-
}],
|
|
3882
|
-
pushState: true
|
|
3883
|
-
};
|
|
3884
|
-
} else if (cursor.peekMatch("else ")) {
|
|
3885
|
-
cursor.advance(5);
|
|
3886
|
-
retVal = {
|
|
3887
|
-
state: "flow-control-block" /* FLOW_CONTROL_BLOCK */,
|
|
3888
|
-
tokens: [{
|
|
3889
|
-
type: 11 /* ELSE */
|
|
3890
|
-
}],
|
|
3891
|
-
pushState: true
|
|
3892
|
-
};
|
|
3893
|
-
} else if (cursor.peekMatch("switch ")) {
|
|
3894
|
-
cursor.advance(7);
|
|
3895
|
-
retVal = {
|
|
3896
|
-
state: "flow-control-condition" /* FLOW_CONTROL_CONDITION */,
|
|
3897
|
-
tokens: [{
|
|
3898
|
-
type: 12 /* SWITCH */
|
|
3899
|
-
}],
|
|
3900
|
-
pushState: true
|
|
3901
|
-
};
|
|
3902
|
-
} else if (cursor.peekMatch("case ")) {
|
|
3903
|
-
cursor.advance(5);
|
|
3904
|
-
retVal = {
|
|
3905
|
-
state: "flow-control-condition" /* FLOW_CONTROL_CONDITION */,
|
|
3906
|
-
tokens: [{
|
|
3907
|
-
type: 13 /* CASE */
|
|
3908
|
-
}],
|
|
3909
|
-
pushState: true
|
|
3910
|
-
};
|
|
3911
|
-
} else if (cursor.peekMatch("default ")) {
|
|
3912
|
-
cursor.advance(8);
|
|
3913
|
-
retVal = {
|
|
3914
|
-
state: "flow-control-block" /* FLOW_CONTROL_BLOCK */,
|
|
3915
|
-
tokens: [{
|
|
3916
|
-
type: 14 /* DEFAULT */
|
|
3917
|
-
}],
|
|
3918
|
-
pushState: true
|
|
3919
|
-
};
|
|
3920
|
-
}
|
|
3921
|
-
return retVal;
|
|
3922
|
-
}
|
|
3923
|
-
|
|
3924
|
-
// ../packages/compiler/src/lexer/states/flow-control-block.state.ts
|
|
3925
|
-
function consumeFlowControlBlock(cursor, _context) {
|
|
3926
|
-
cursor.skipSpaces();
|
|
3927
|
-
if (cursor.peek() !== LEFT_BRACE) {
|
|
3928
|
-
throw new Error(`Expected '{' but got '${String.fromCharCode(cursor.peek())}' at row ${cursor.position.row}, col ${cursor.position.column}`);
|
|
3929
|
-
}
|
|
3930
|
-
cursor.advance();
|
|
3931
|
-
return {
|
|
3932
|
-
state: "text" /* TEXT */,
|
|
3933
|
-
tokens: [{ type: 16 /* BLOCK_OPEN */ }],
|
|
3934
|
-
pushState: true
|
|
3935
|
-
};
|
|
3567
|
+
// ../packages/cli/src/commands/new/templates/index-html.ts
|
|
3568
|
+
function indexHtml(name) {
|
|
3569
|
+
const selector = `${name}-root`;
|
|
3570
|
+
return `<!DOCTYPE html>
|
|
3571
|
+
<html lang="en">
|
|
3572
|
+
<head>
|
|
3573
|
+
<meta charset="UTF-8" />
|
|
3574
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
3575
|
+
<title>${name}</title>
|
|
3576
|
+
</head>
|
|
3577
|
+
<body>
|
|
3578
|
+
<${selector}></${selector}>
|
|
3579
|
+
<script type="module" src="/src/main.ts"></script>
|
|
3580
|
+
</body>
|
|
3581
|
+
</html>
|
|
3582
|
+
`;
|
|
3936
3583
|
}
|
|
3937
3584
|
|
|
3938
|
-
// ../packages/
|
|
3939
|
-
function
|
|
3940
|
-
|
|
3941
|
-
|
|
3942
|
-
|
|
3943
|
-
|
|
3944
|
-
cursor.advance();
|
|
3945
|
-
let expression = "";
|
|
3946
|
-
let depth = 1;
|
|
3947
|
-
while (depth > 0) {
|
|
3948
|
-
const code = cursor.peek();
|
|
3949
|
-
switch (code) {
|
|
3950
|
-
case LPAREN:
|
|
3951
|
-
depth++;
|
|
3952
|
-
cursor.advance();
|
|
3953
|
-
break;
|
|
3954
|
-
case RPAREN:
|
|
3955
|
-
depth--;
|
|
3956
|
-
if (!depth) {
|
|
3957
|
-
cursor.advance();
|
|
3958
|
-
break;
|
|
3959
|
-
}
|
|
3960
|
-
cursor.advance();
|
|
3961
|
-
break;
|
|
3962
|
-
default:
|
|
3963
|
-
cursor.advance();
|
|
3964
|
-
expression = `${expression}${cursor.currentChar.value}`;
|
|
3965
|
-
}
|
|
3966
|
-
}
|
|
3967
|
-
return {
|
|
3968
|
-
state: "flow-control-block" /* FLOW_CONTROL_BLOCK */,
|
|
3969
|
-
tokens: [{
|
|
3970
|
-
type: 15 /* CONDITION */,
|
|
3971
|
-
parts: [expression]
|
|
3972
|
-
}],
|
|
3973
|
-
popState: true
|
|
3974
|
-
};
|
|
3585
|
+
// ../packages/cli/src/commands/new/templates/main-ts.ts
|
|
3586
|
+
function mainTs(componentName) {
|
|
3587
|
+
return `import { loadSignals } from '@xaendar/signals';
|
|
3588
|
+
|
|
3589
|
+
loadSignals();
|
|
3590
|
+
`;
|
|
3975
3591
|
}
|
|
3976
3592
|
|
|
3977
|
-
// ../packages/
|
|
3978
|
-
function
|
|
3979
|
-
|
|
3980
|
-
|
|
3981
|
-
|
|
3982
|
-
|
|
3983
|
-
|
|
3984
|
-
|
|
3985
|
-
|
|
3986
|
-
|
|
3987
|
-
|
|
3988
|
-
|
|
3989
|
-
|
|
3990
|
-
|
|
3991
|
-
|
|
3992
|
-
|
|
3993
|
-
|
|
3994
|
-
|
|
3995
|
-
|
|
3996
|
-
|
|
3997
|
-
|
|
3998
|
-
|
|
3999
|
-
|
|
4000
|
-
|
|
4001
|
-
}
|
|
4002
|
-
;
|
|
4003
|
-
retVal = {
|
|
4004
|
-
state,
|
|
4005
|
-
tokens: [{
|
|
4006
|
-
type: 8 /* INTERPOLATION_EXPRESSION */,
|
|
4007
|
-
parts: [interpolation]
|
|
4008
|
-
}],
|
|
4009
|
-
popState: true
|
|
4010
|
-
};
|
|
4011
|
-
read = false;
|
|
4012
|
-
} else {
|
|
4013
|
-
interpolation = addCharacter(cursor, interpolation);
|
|
4014
|
-
}
|
|
4015
|
-
break;
|
|
4016
|
-
default:
|
|
4017
|
-
interpolation = addCharacter(cursor, interpolation);
|
|
4018
|
-
}
|
|
3593
|
+
// ../packages/cli/src/commands/new/templates/package-json.ts
|
|
3594
|
+
function packageJson(name, version) {
|
|
3595
|
+
return `{
|
|
3596
|
+
"name": "${name}",
|
|
3597
|
+
"version": "0.0.1",
|
|
3598
|
+
"private": true,
|
|
3599
|
+
"scripts": {
|
|
3600
|
+
"build": "vite build",
|
|
3601
|
+
"start": "vite",
|
|
3602
|
+
"test": "vitest",
|
|
3603
|
+
"xd": "xd"
|
|
3604
|
+
},
|
|
3605
|
+
"dependencies": {
|
|
3606
|
+
"@xaendar/core": "^${version}",
|
|
3607
|
+
"@xaendar/signals": "^${version}",
|
|
3608
|
+
"@xaendar/types": "^${version}"
|
|
3609
|
+
},
|
|
3610
|
+
"devDependencies": {
|
|
3611
|
+
"@vitest/coverage-v8": "^4.1.7",
|
|
3612
|
+
"@xaendar/build-tools": "^${version}",
|
|
3613
|
+
"@xaendar/cli": "^${version}",
|
|
3614
|
+
"typescript": "^6.0.3",
|
|
3615
|
+
"vite": "^8.0.14",
|
|
3616
|
+
"vitest": "^4.1.7"
|
|
4019
3617
|
}
|
|
4020
|
-
return retVal;
|
|
4021
3618
|
}
|
|
4022
|
-
|
|
4023
|
-
cursor.advance(1);
|
|
4024
|
-
return `${interpolation}${cursor.currentChar.value}`;
|
|
3619
|
+
`;
|
|
4025
3620
|
}
|
|
4026
3621
|
|
|
4027
|
-
// ../packages/
|
|
4028
|
-
function
|
|
4029
|
-
|
|
4030
|
-
|
|
4031
|
-
|
|
4032
|
-
|
|
4033
|
-
|
|
4034
|
-
|
|
4035
|
-
|
|
4036
|
-
|
|
4037
|
-
|
|
4038
|
-
|
|
4039
|
-
|
|
4040
|
-
|
|
4041
|
-
|
|
4042
|
-
|
|
4043
|
-
|
|
4044
|
-
|
|
4045
|
-
|
|
4046
|
-
|
|
4047
|
-
}
|
|
4048
|
-
;
|
|
4049
|
-
retVal = {
|
|
4050
|
-
state,
|
|
4051
|
-
tokens: [{
|
|
4052
|
-
type: 7 /* INTERPOLATION_LITERAL */,
|
|
4053
|
-
parts: [interpolation]
|
|
4054
|
-
}],
|
|
4055
|
-
popState: true
|
|
4056
|
-
};
|
|
4057
|
-
read = false;
|
|
4058
|
-
} else {
|
|
4059
|
-
interpolation = `${interpolation}${cursor.currentChar.value}`;
|
|
4060
|
-
}
|
|
4061
|
-
break;
|
|
4062
|
-
default:
|
|
4063
|
-
interpolation = addCharacter2(cursor, interpolation);
|
|
3622
|
+
// ../packages/cli/src/commands/new/templates/tsconfig-json.ts
|
|
3623
|
+
function tsconfigJson() {
|
|
3624
|
+
return `{
|
|
3625
|
+
"compilerOptions": {
|
|
3626
|
+
"target": "ESNext",
|
|
3627
|
+
"module": "ESNext",
|
|
3628
|
+
"moduleResolution": "bundler",
|
|
3629
|
+
"lib": ["ESNext", "DOM", "DOM.Iterable"],
|
|
3630
|
+
"outDir": "./dist",
|
|
3631
|
+
"rootDir": "./src",
|
|
3632
|
+
"declaration": true,
|
|
3633
|
+
"declarationMap": true,
|
|
3634
|
+
"sourceMap": true,
|
|
3635
|
+
"isolatedModules": true,
|
|
3636
|
+
"moduleDetection": "force",
|
|
3637
|
+
"noUncheckedIndexedAccess": true,
|
|
3638
|
+
"noEmit": true,
|
|
3639
|
+
"skipLibCheck": true,
|
|
3640
|
+
"paths": {
|
|
3641
|
+
"@/*": ["./src/*"]
|
|
4064
3642
|
}
|
|
4065
|
-
}
|
|
4066
|
-
|
|
3643
|
+
},
|
|
3644
|
+
"include": ["src/**/*.ts"],
|
|
3645
|
+
"exclude": ["dist", "node_modules", "**/*.spec.ts"]
|
|
4067
3646
|
}
|
|
4068
|
-
|
|
4069
|
-
cursor.advance(1);
|
|
4070
|
-
return `${interpolation}${cursor.currentChar.value}`;
|
|
3647
|
+
`;
|
|
4071
3648
|
}
|
|
4072
3649
|
|
|
4073
|
-
// ../packages/
|
|
4074
|
-
function
|
|
4075
|
-
return
|
|
4076
|
-
}
|
|
4077
|
-
function isJSIdentifierStart(code) {
|
|
4078
|
-
return code >= 65 && code <= 90 || // A-Z
|
|
4079
|
-
code >= 97 && code <= 122 || // a-z
|
|
4080
|
-
code === 36 || // $
|
|
4081
|
-
code === 95;
|
|
4082
|
-
}
|
|
3650
|
+
// ../packages/cli/src/commands/new/templates/vite-config-ts.ts
|
|
3651
|
+
function viteConfigTs() {
|
|
3652
|
+
return `import { defineConfig } from 'vite';
|
|
3653
|
+
import { xaendarPlugin } from '@xaendar/build-tools';
|
|
4083
3654
|
|
|
4084
|
-
|
|
4085
|
-
|
|
4086
|
-
|
|
4087
|
-
|
|
4088
|
-
cursor.skipSpaces();
|
|
4089
|
-
const nextChar = cursor.peek();
|
|
4090
|
-
if (nextChar === GRAVE_ACCENT) {
|
|
4091
|
-
retVal = { state: "interpolation-literal" /* INTERPOLATION_LITERAL */ };
|
|
4092
|
-
} else if (isJSIdentifierStart(nextChar)) {
|
|
4093
|
-
retVal = { state: "interpolation-expression" /* INTERPOLATION_EXPRESSION */ };
|
|
4094
|
-
} else {
|
|
4095
|
-
throw new Error(`Unrecognized First Character ${String.fromCharCode(nextChar)} in interpolation`);
|
|
4096
|
-
}
|
|
4097
|
-
return retVal;
|
|
3655
|
+
export default defineConfig({
|
|
3656
|
+
plugins: [xaendarPlugin()],
|
|
3657
|
+
});
|
|
3658
|
+
`;
|
|
4098
3659
|
}
|
|
4099
3660
|
|
|
4100
|
-
// ../packages/
|
|
4101
|
-
function
|
|
4102
|
-
|
|
4103
|
-
|
|
4104
|
-
|
|
4105
|
-
|
|
4106
|
-
|
|
4107
|
-
|
|
4108
|
-
|
|
4109
|
-
|
|
4110
|
-
};
|
|
4111
|
-
read = false;
|
|
4112
|
-
break;
|
|
4113
|
-
case SPACE:
|
|
4114
|
-
cursor.advance();
|
|
4115
|
-
break;
|
|
4116
|
-
case GREATER_THEN:
|
|
4117
|
-
case SLASH:
|
|
4118
|
-
retVal = {
|
|
4119
|
-
state: "tag-open-end" /* TAG_OPEN_END */
|
|
4120
|
-
};
|
|
4121
|
-
read = false;
|
|
4122
|
-
break;
|
|
4123
|
-
default:
|
|
4124
|
-
retVal = {
|
|
4125
|
-
state: "attribute" /* ATTRIBUTE */
|
|
4126
|
-
};
|
|
4127
|
-
read = false;
|
|
3661
|
+
// ../packages/cli/src/commands/new/templates/xaendar-json.ts
|
|
3662
|
+
function xaendarJson(name, style) {
|
|
3663
|
+
return `{
|
|
3664
|
+
"name": "${name}",
|
|
3665
|
+
"entry": "src/main.ts",
|
|
3666
|
+
"outDir": "dist",
|
|
3667
|
+
"assetsDir": "assets",
|
|
3668
|
+
"generate": {
|
|
3669
|
+
"components": {
|
|
3670
|
+
"style": "${style}"
|
|
4128
3671
|
}
|
|
4129
3672
|
}
|
|
4130
|
-
return retVal;
|
|
4131
3673
|
}
|
|
4132
|
-
|
|
4133
|
-
// ../packages/compiler/src/lexer/states/tag-close.state.ts
|
|
4134
|
-
function consumeTagClose(cursor, _context) {
|
|
4135
|
-
let read = true;
|
|
4136
|
-
let tagName = "";
|
|
4137
|
-
let retVal;
|
|
4138
|
-
cursor.advance(2);
|
|
4139
|
-
cursor.skipSpaces();
|
|
4140
|
-
while (read) {
|
|
4141
|
-
switch (cursor.peek()) {
|
|
4142
|
-
case GREATER_THEN:
|
|
4143
|
-
cursor.advance();
|
|
4144
|
-
retVal = {
|
|
4145
|
-
state: "text" /* TEXT */,
|
|
4146
|
-
tokens: [{
|
|
4147
|
-
type: 4 /* TAG_CLOSE_NAME */,
|
|
4148
|
-
parts: [tagName]
|
|
4149
|
-
}]
|
|
4150
|
-
};
|
|
4151
|
-
read = false;
|
|
4152
|
-
break;
|
|
4153
|
-
case SPACE:
|
|
4154
|
-
throw new Error("Tag Close Name cannot contains spaces");
|
|
4155
|
-
default:
|
|
4156
|
-
cursor.advance();
|
|
4157
|
-
tagName = `${tagName}${cursor.currentChar.value}`;
|
|
4158
|
-
}
|
|
4159
|
-
}
|
|
4160
|
-
return retVal;
|
|
3674
|
+
`;
|
|
4161
3675
|
}
|
|
4162
3676
|
|
|
4163
|
-
// ../packages/
|
|
4164
|
-
function
|
|
4165
|
-
|
|
4166
|
-
|
|
4167
|
-
|
|
4168
|
-
|
|
4169
|
-
state: "text" /* TEXT */,
|
|
4170
|
-
tokens: [{
|
|
4171
|
-
type: 3 /* TAG_OPEN_END */,
|
|
4172
|
-
parts: []
|
|
4173
|
-
}]
|
|
4174
|
-
};
|
|
4175
|
-
} else {
|
|
4176
|
-
cursor.advance();
|
|
4177
|
-
const nextChar = cursor.peek();
|
|
4178
|
-
if (nextChar === GREATER_THEN) {
|
|
4179
|
-
cursor.advance();
|
|
4180
|
-
retVal = {
|
|
4181
|
-
state: "text" /* TEXT */,
|
|
4182
|
-
tokens: [{
|
|
4183
|
-
type: 2 /* TAG_SELF_CLOSE */,
|
|
4184
|
-
parts: []
|
|
4185
|
-
}]
|
|
4186
|
-
};
|
|
4187
|
-
} else {
|
|
4188
|
-
throw new Error(`Unexpected character ${nextChar} for closing tag.
|
|
4189
|
-
Expected />
|
|
4190
|
-
Read of /${String.fromCharCode(nextChar)}
|
|
4191
|
-
At line ${cursor.position.row + 1} col ${cursor.position.column + 1}`);
|
|
3677
|
+
// ../packages/cli/src/commands/new/structure.ts
|
|
3678
|
+
function readCliVersion() {
|
|
3679
|
+
try {
|
|
3680
|
+
const cliPackageJson = JSON.parse(readFileSync("./package.json", "utf8"));
|
|
3681
|
+
if (!cliPackageJson.version) {
|
|
3682
|
+
throw new Error("Unable to determine Xaendar CLI version.");
|
|
4192
3683
|
}
|
|
3684
|
+
return cliPackageJson.version;
|
|
3685
|
+
} catch (error) {
|
|
3686
|
+
console.error("Error reading Xaendar CLI version:", error);
|
|
3687
|
+
process.exit(1);
|
|
4193
3688
|
}
|
|
4194
|
-
return retVal;
|
|
4195
3689
|
}
|
|
4196
|
-
|
|
4197
|
-
|
|
4198
|
-
|
|
4199
|
-
|
|
4200
|
-
|
|
4201
|
-
|
|
4202
|
-
|
|
4203
|
-
|
|
4204
|
-
|
|
4205
|
-
|
|
4206
|
-
|
|
4207
|
-
|
|
4208
|
-
|
|
4209
|
-
|
|
4210
|
-
|
|
4211
|
-
|
|
4212
|
-
|
|
4213
|
-
|
|
4214
|
-
|
|
4215
|
-
|
|
4216
|
-
|
|
4217
|
-
|
|
4218
|
-
|
|
4219
|
-
|
|
4220
|
-
|
|
3690
|
+
function buildStructure(context) {
|
|
3691
|
+
const version = readCliVersion();
|
|
3692
|
+
const componentName = context.name;
|
|
3693
|
+
return [
|
|
3694
|
+
{
|
|
3695
|
+
type: "file",
|
|
3696
|
+
name: "package.json",
|
|
3697
|
+
content: packageJson(componentName, version)
|
|
3698
|
+
},
|
|
3699
|
+
{
|
|
3700
|
+
type: "file",
|
|
3701
|
+
name: "xaendar.json",
|
|
3702
|
+
content: xaendarJson(componentName, context.style)
|
|
3703
|
+
},
|
|
3704
|
+
{
|
|
3705
|
+
type: "file",
|
|
3706
|
+
name: "vite.config.ts",
|
|
3707
|
+
content: viteConfigTs()
|
|
3708
|
+
},
|
|
3709
|
+
{
|
|
3710
|
+
type: "file",
|
|
3711
|
+
name: "tsconfig.json",
|
|
3712
|
+
content: tsconfigJson()
|
|
3713
|
+
},
|
|
3714
|
+
{
|
|
3715
|
+
type: "directory",
|
|
3716
|
+
name: "src",
|
|
3717
|
+
children: [
|
|
3718
|
+
{
|
|
3719
|
+
type: "file",
|
|
3720
|
+
name: "index.html",
|
|
3721
|
+
content: indexHtml(componentName)
|
|
3722
|
+
},
|
|
3723
|
+
{
|
|
3724
|
+
type: "file",
|
|
3725
|
+
name: "main.ts",
|
|
3726
|
+
content: mainTs(componentName)
|
|
3727
|
+
},
|
|
3728
|
+
{
|
|
3729
|
+
type: "generateComponent",
|
|
3730
|
+
name: componentName
|
|
3731
|
+
}
|
|
3732
|
+
]
|
|
4221
3733
|
}
|
|
4222
|
-
|
|
4223
|
-
return retVal;
|
|
3734
|
+
];
|
|
4224
3735
|
}
|
|
4225
3736
|
|
|
4226
|
-
// ../packages/
|
|
4227
|
-
function
|
|
4228
|
-
|
|
4229
|
-
|
|
4230
|
-
|
|
4231
|
-
|
|
4232
|
-
|
|
4233
|
-
|
|
4234
|
-
|
|
4235
|
-
retVal = { state: nextState };
|
|
4236
|
-
read = false;
|
|
4237
|
-
break;
|
|
4238
|
-
case LEFT_BRACE:
|
|
4239
|
-
retVal = {
|
|
4240
|
-
state: "interpolation" /* INTERPOLATION */,
|
|
4241
|
-
pushState: true
|
|
4242
|
-
};
|
|
4243
|
-
read = false;
|
|
4244
|
-
break;
|
|
4245
|
-
case AT_SIGN:
|
|
4246
|
-
retVal = {
|
|
4247
|
-
state: "flow-control" /* FLOW_CONTROL */
|
|
4248
|
-
};
|
|
4249
|
-
read = false;
|
|
4250
|
-
break;
|
|
4251
|
-
case RIGHT_BRACE:
|
|
4252
|
-
if (context.history[context.history.length - 1] === "flow-control-block" /* FLOW_CONTROL_BLOCK */) {
|
|
4253
|
-
cursor.advance();
|
|
4254
|
-
retVal = {
|
|
4255
|
-
state: "text" /* TEXT */,
|
|
4256
|
-
tokens: [{ type: 17 /* BLOCK_CLOSE */ }],
|
|
4257
|
-
popState: true
|
|
4258
|
-
};
|
|
4259
|
-
read = false;
|
|
4260
|
-
} else {
|
|
4261
|
-
cursor.advance();
|
|
4262
|
-
text = `${text}${cursor.currentChar.value}`;
|
|
4263
|
-
}
|
|
4264
|
-
break;
|
|
4265
|
-
case LF:
|
|
4266
|
-
case CR:
|
|
4267
|
-
cursor.advance();
|
|
4268
|
-
break;
|
|
4269
|
-
default:
|
|
4270
|
-
cursor.advance();
|
|
4271
|
-
text = `${text}${cursor.currentChar.value}`;
|
|
4272
|
-
}
|
|
4273
|
-
}
|
|
4274
|
-
retVal.tokens ??= isNotBlank(text) ? [{ type: 0 /* TEXT */, parts: [text] }] : void 0;
|
|
4275
|
-
return retVal;
|
|
3737
|
+
// ../packages/cli/src/commands/new/new.command.ts
|
|
3738
|
+
function newCommand() {
|
|
3739
|
+
return new Command("new").description("Sccafold a new Xaendar project").argument("<name>", "Name of the project to create").option("-p, --path <path>", "Custom path for the generated project (default: current directory)").option("-s, --style <style>", "CSS preprocessor to use (css, scss, less, styl)", "css").action((name, options) => {
|
|
3740
|
+
const style = resolveStyleOptions(options.style);
|
|
3741
|
+
const workingDirectory = options.path || process.cwd();
|
|
3742
|
+
const projectDirectory = resolve(workingDirectory, name);
|
|
3743
|
+
checkAndCreateProjectDirectory(projectDirectory);
|
|
3744
|
+
createFiles(buildStructure({ name, style }), projectDirectory, style);
|
|
3745
|
+
});
|
|
4276
3746
|
}
|
|
4277
|
-
|
|
4278
|
-
|
|
4279
|
-
|
|
4280
|
-
|
|
4281
|
-
* Creates a new Cursor instance for the given template content.
|
|
4282
|
-
*
|
|
4283
|
-
* @param input The full template text that the cursor will navigate.
|
|
4284
|
-
*/
|
|
4285
|
-
constructor(input) {
|
|
4286
|
-
this.input = input;
|
|
4287
|
-
this._cursor = new LexerCursor(this.input);
|
|
4288
|
-
}
|
|
4289
|
-
input;
|
|
4290
|
-
_cursor;
|
|
4291
|
-
_state = "start" /* START */;
|
|
4292
|
-
_stack = new Stack();
|
|
4293
|
-
_tokens = new Array();
|
|
4294
|
-
_states = {
|
|
4295
|
-
["start" /* START */]: consumeText,
|
|
4296
|
-
["text" /* TEXT */]: consumeText,
|
|
4297
|
-
["tag-open-name" /* TAG_OPEN_NAME */]: consumeTagOpenName,
|
|
4298
|
-
["tag-body" /* TAG_BODY */]: consumeTagBody,
|
|
4299
|
-
["tag-open-end" /* TAG_OPEN_END */]: consumeTagOpenEnd,
|
|
4300
|
-
["tag-close" /* TAG_CLOSE */]: consumeTagClose,
|
|
4301
|
-
["attribute" /* ATTRIBUTE */]: consumeAttribute,
|
|
4302
|
-
["flow-control" /* FLOW_CONTROL */]: consumeFlowControl,
|
|
4303
|
-
["flow-control-condition" /* FLOW_CONTROL_CONDITION */]: consumeFlowControlCondition,
|
|
4304
|
-
["flow-control-block" /* FLOW_CONTROL_BLOCK */]: consumeFlowControlBlock,
|
|
4305
|
-
["event" /* EVENT */]: consumeEvent,
|
|
4306
|
-
["interpolation" /* INTERPOLATION */]: consumeInterpolation,
|
|
4307
|
-
["interpolation-expression" /* INTERPOLATION_EXPRESSION */]: consumeInterpolationExpression,
|
|
4308
|
-
["interpolation-literal" /* INTERPOLATION_LITERAL */]: consumeInterpolationliteral
|
|
4309
|
-
};
|
|
4310
|
-
tokenize() {
|
|
4311
|
-
let eof = false;
|
|
4312
|
-
while (!eof) {
|
|
4313
|
-
try {
|
|
4314
|
-
const transitionFunction = this._states[this._state];
|
|
4315
|
-
const { state, tokens, popState, pushState } = transitionFunction(this._cursor, { history: this._stack.values });
|
|
4316
|
-
if (tokens?.length) {
|
|
4317
|
-
this._tokens.push(...tokens);
|
|
4318
|
-
}
|
|
4319
|
-
if (pushState) {
|
|
4320
|
-
this._stack.push(this._state);
|
|
4321
|
-
}
|
|
4322
|
-
if (popState) {
|
|
4323
|
-
this._stack.pop();
|
|
4324
|
-
}
|
|
4325
|
-
this._state = state;
|
|
4326
|
-
} catch (err) {
|
|
4327
|
-
const error = err;
|
|
4328
|
-
if (error.cause === EOF) {
|
|
4329
|
-
eof = true;
|
|
4330
|
-
} else {
|
|
4331
|
-
throw err;
|
|
4332
|
-
}
|
|
4333
|
-
}
|
|
4334
|
-
}
|
|
4335
|
-
return this._tokens;
|
|
4336
|
-
}
|
|
4337
|
-
};
|
|
4338
|
-
|
|
4339
|
-
// ../packages/compiler/src/parser/models/parser-cursor.model.ts
|
|
4340
|
-
var ParserCursor = class {
|
|
4341
|
-
/**
|
|
4342
|
-
* Creates a new ParserCursor for the given token array.
|
|
4343
|
-
*
|
|
4344
|
-
* @param _tokens Array of tokens to navigate.
|
|
4345
|
-
*/
|
|
4346
|
-
constructor(_tokens) {
|
|
4347
|
-
this._tokens = _tokens;
|
|
4348
|
-
}
|
|
4349
|
-
_tokens;
|
|
4350
|
-
/**
|
|
4351
|
-
* Representation of the current token.
|
|
4352
|
-
*
|
|
4353
|
-
* - `index`: absolute index within the token array
|
|
4354
|
-
* - `value`: current token object (or EOF token)
|
|
4355
|
-
*
|
|
4356
|
-
* An index of `-1` indicates that the cursor has not
|
|
4357
|
-
* yet consumed any token or has reached EOF.
|
|
4358
|
-
*/
|
|
4359
|
-
_currentToken = {
|
|
4360
|
-
value: { type: 18 /* EOF */ },
|
|
4361
|
-
index: -1
|
|
4362
|
-
};
|
|
4363
|
-
/**
|
|
4364
|
-
* Returns a read-only snapshot of the current token.
|
|
4365
|
-
*/
|
|
4366
|
-
get currentToken() {
|
|
4367
|
-
return this._currentToken;
|
|
4368
|
-
}
|
|
4369
|
-
/**
|
|
4370
|
-
* Advances the cursor by the specified number of tokens.
|
|
4371
|
-
*
|
|
4372
|
-
* Updates the current token and index.
|
|
4373
|
-
*
|
|
4374
|
-
* @param chars Number of tokens to advance (must be >= 1)
|
|
4375
|
-
*
|
|
4376
|
-
* @throws Error with cause `EOF` when advancing past the end
|
|
4377
|
-
*/
|
|
4378
|
-
advance(chars = 1) {
|
|
4379
|
-
if (chars < 1) {
|
|
4380
|
-
throw new Error(`${chars} is not a valid value. Please enter a number equal or greater than 1`);
|
|
4381
|
-
}
|
|
4382
|
-
const newIndex = this._currentToken.index + chars;
|
|
4383
|
-
if (newIndex >= this._tokens.length) {
|
|
4384
|
-
this._currentToken.value = { type: 18 /* EOF */ };
|
|
4385
|
-
this._currentToken.index = -1;
|
|
4386
|
-
this.throwEOFError();
|
|
4387
|
-
} else {
|
|
4388
|
-
this._currentToken.index = newIndex;
|
|
4389
|
-
this._currentToken.value = this._tokens[newIndex];
|
|
4390
|
-
}
|
|
4391
|
-
}
|
|
4392
|
-
peek(charsOrOptions, options) {
|
|
4393
|
-
const tokens = typeof charsOrOptions === "number" ? charsOrOptions : 1;
|
|
4394
|
-
const offset = (typeof charsOrOptions === "object" ? charsOrOptions : options)?.offset ?? 0;
|
|
4395
|
-
return tokens === 1 ? this.peekOneToken(this._currentToken.index + offset + 1) : this.peekMany(tokens + offset);
|
|
4396
|
-
}
|
|
4397
|
-
/**
|
|
4398
|
-
* Peeks multiple tokens ahead.
|
|
4399
|
-
*/
|
|
4400
|
-
peekMany(chars) {
|
|
4401
|
-
const peekedTokens = [];
|
|
4402
|
-
const nextTokenIndex = this._currentToken.index + 1;
|
|
4403
|
-
for (let i = nextTokenIndex; i < nextTokenIndex + chars; i++) {
|
|
4404
|
-
peekedTokens.push(this.peekOneToken(i));
|
|
4405
|
-
}
|
|
4406
|
-
return peekedTokens;
|
|
3747
|
+
function resolveStyleOptions(style) {
|
|
3748
|
+
const validStyles = ["css", "scss", "less", "styl"];
|
|
3749
|
+
if (!style) {
|
|
3750
|
+
return "css";
|
|
4407
3751
|
}
|
|
4408
|
-
|
|
4409
|
-
|
|
4410
|
-
|
|
4411
|
-
peekOneToken(index) {
|
|
4412
|
-
if (index >= this._tokens.length) {
|
|
4413
|
-
this.throwEOFError();
|
|
4414
|
-
}
|
|
4415
|
-
return this._tokens[index];
|
|
4416
|
-
}
|
|
4417
|
-
/**
|
|
4418
|
-
* Throws a standardized EOF error used by the parser
|
|
4419
|
-
* to terminate token consumption.
|
|
4420
|
-
*/
|
|
4421
|
-
throwEOFError() {
|
|
4422
|
-
throw new Error("", { cause: EOF });
|
|
4423
|
-
}
|
|
4424
|
-
};
|
|
4425
|
-
|
|
4426
|
-
// ../packages/compiler/src/parser/parser.ts
|
|
4427
|
-
var Parser = class {
|
|
4428
|
-
/**
|
|
4429
|
-
* Creates a new Parser instance.
|
|
4430
|
-
*
|
|
4431
|
-
* @param tokens Array of tokens produced by the Lexer
|
|
4432
|
-
*/
|
|
4433
|
-
constructor(tokens) {
|
|
4434
|
-
this.tokens = tokens;
|
|
4435
|
-
this._cursor = new ParserCursor(this.tokens);
|
|
4436
|
-
}
|
|
4437
|
-
tokens;
|
|
4438
|
-
/** Internal cursor for navigating tokens */
|
|
4439
|
-
_cursor;
|
|
4440
|
-
/**
|
|
4441
|
-
* Entry point for parsing the token stream into AST nodes.
|
|
4442
|
-
*
|
|
4443
|
-
* @returns Array of top-level AST nodes
|
|
4444
|
-
*/
|
|
4445
|
-
parse() {
|
|
4446
|
-
let eof = false;
|
|
4447
|
-
const nodes = [];
|
|
4448
|
-
while (!eof) {
|
|
4449
|
-
try {
|
|
4450
|
-
nodes.push(this.parseNode());
|
|
4451
|
-
} catch (err) {
|
|
4452
|
-
const error = err;
|
|
4453
|
-
if (error.cause === EOF) {
|
|
4454
|
-
eof = true;
|
|
4455
|
-
} else {
|
|
4456
|
-
throw err;
|
|
4457
|
-
}
|
|
4458
|
-
}
|
|
4459
|
-
}
|
|
4460
|
-
return nodes;
|
|
4461
|
-
}
|
|
4462
|
-
/**
|
|
4463
|
-
* Parses the next AST node based on the current token.
|
|
4464
|
-
*
|
|
4465
|
-
* @returns Parsed AST node
|
|
4466
|
-
* @throws Error if an unexpected token is encountered
|
|
4467
|
-
*/
|
|
4468
|
-
parseNode() {
|
|
4469
|
-
const token = this._cursor.peek();
|
|
4470
|
-
switch (token.type) {
|
|
4471
|
-
case 0 /* TEXT */:
|
|
4472
|
-
return this.parseText(token);
|
|
4473
|
-
case 8 /* INTERPOLATION_EXPRESSION */:
|
|
4474
|
-
case 7 /* INTERPOLATION_LITERAL */:
|
|
4475
|
-
return this.parseInterpolation(token);
|
|
4476
|
-
case 1 /* TAG_OPEN_NAME */:
|
|
4477
|
-
return this.parseElement(token);
|
|
4478
|
-
case 9 /* IF */:
|
|
4479
|
-
return this.parseIfControlFlow(token);
|
|
4480
|
-
case 10 /* FOR */:
|
|
4481
|
-
return this.parseForControlFlow(token);
|
|
4482
|
-
case 12 /* SWITCH */:
|
|
4483
|
-
return this.parseSwitchControlFlow(token);
|
|
4484
|
-
default:
|
|
4485
|
-
throw this.error(`Unexpected token ${TokenType[token.type]}`);
|
|
4486
|
-
}
|
|
3752
|
+
if (!validStyles.includes(style)) {
|
|
3753
|
+
console.error(`\u2716 Invalid style option: ${style}`);
|
|
3754
|
+
process.exit(1);
|
|
4487
3755
|
}
|
|
4488
|
-
|
|
4489
|
-
|
|
4490
|
-
|
|
4491
|
-
|
|
4492
|
-
|
|
4493
|
-
|
|
4494
|
-
|
|
4495
|
-
parseIfControlFlow(_token) {
|
|
4496
|
-
this._cursor.advance();
|
|
4497
|
-
const conditionToken = this._cursor.peek();
|
|
4498
|
-
if (conditionToken.type !== 15 /* CONDITION */) {
|
|
4499
|
-
throw this.error(`Expected CONDITION after IF, got ${TokenType[conditionToken.type]}`);
|
|
4500
|
-
}
|
|
4501
|
-
const condition = conditionToken.parts[0];
|
|
4502
|
-
this._cursor.advance();
|
|
4503
|
-
this._cursor.advance();
|
|
4504
|
-
const consequent = this.parseBlockChildren();
|
|
4505
|
-
let alternate = null;
|
|
4506
|
-
const next = this._cursor.peek();
|
|
4507
|
-
if (next.type === 11 /* ELSE */) {
|
|
4508
|
-
this._cursor.advance();
|
|
4509
|
-
this._cursor.advance();
|
|
4510
|
-
const elseChildren = this.parseBlockChildren();
|
|
4511
|
-
alternate = { type: 4 /* Else */, children: elseChildren };
|
|
4512
|
-
}
|
|
4513
|
-
return { type: 3 /* If */, condition, consequent, alternate };
|
|
3756
|
+
return style;
|
|
3757
|
+
}
|
|
3758
|
+
function checkAndCreateProjectDirectory(path) {
|
|
3759
|
+
const exists = existsSync2(path);
|
|
3760
|
+
if (exists && readdirSync(path).length) {
|
|
3761
|
+
console.error(`\u2716 Cannot create project: target directory is not empty: ${path}`);
|
|
3762
|
+
process.exit(1);
|
|
4514
3763
|
}
|
|
4515
|
-
|
|
4516
|
-
|
|
4517
|
-
*
|
|
4518
|
-
* Expected token sequence:
|
|
4519
|
-
* FOR → CONDITION → BLOCK_OPEN → ...children... → BLOCK_CLOSE
|
|
4520
|
-
*/
|
|
4521
|
-
parseForControlFlow(_token) {
|
|
4522
|
-
this._cursor.advance();
|
|
4523
|
-
const conditionToken = this._cursor.peek();
|
|
4524
|
-
if (conditionToken.type !== 15 /* CONDITION */) {
|
|
4525
|
-
throw this.error(`Expected CONDITION after FOR, got ${TokenType[conditionToken.type]}`);
|
|
4526
|
-
}
|
|
4527
|
-
const expression = conditionToken.parts[0];
|
|
4528
|
-
this._cursor.advance();
|
|
4529
|
-
this._cursor.advance();
|
|
4530
|
-
const children = this.parseBlockChildren();
|
|
4531
|
-
return { type: 5 /* For */, expression, children };
|
|
3764
|
+
if (!exists) {
|
|
3765
|
+
mkdirSync2(path);
|
|
4532
3766
|
}
|
|
4533
|
-
|
|
4534
|
-
|
|
4535
|
-
|
|
4536
|
-
|
|
4537
|
-
|
|
4538
|
-
|
|
4539
|
-
|
|
4540
|
-
|
|
4541
|
-
|
|
4542
|
-
|
|
4543
|
-
|
|
4544
|
-
|
|
4545
|
-
|
|
4546
|
-
|
|
4547
|
-
}
|
|
4548
|
-
const expression = conditionToken.parts[0];
|
|
4549
|
-
this._cursor.advance();
|
|
4550
|
-
this._cursor.advance();
|
|
4551
|
-
const cases = [];
|
|
4552
|
-
while (this._cursor.peek().type !== 17 /* BLOCK_CLOSE */) {
|
|
4553
|
-
const t = this._cursor.peek();
|
|
4554
|
-
if (t.type === 13 /* CASE */) {
|
|
4555
|
-
this._cursor.advance();
|
|
4556
|
-
const caseCondition = this._cursor.peek();
|
|
4557
|
-
if (caseCondition.type !== 15 /* CONDITION */) {
|
|
4558
|
-
throw this.error(`Expected CONDITION after CASE`);
|
|
3767
|
+
}
|
|
3768
|
+
function createFiles(entries, basePath, style) {
|
|
3769
|
+
entries.forEach((entry) => {
|
|
3770
|
+
switch (entry.type) {
|
|
3771
|
+
case "file":
|
|
3772
|
+
case void 0:
|
|
3773
|
+
const content = entry.content;
|
|
3774
|
+
writeFileSync2(resolve(basePath, entry.name), content, "utf8");
|
|
3775
|
+
break;
|
|
3776
|
+
case "directory":
|
|
3777
|
+
const dirPath = resolve(basePath, entry.name);
|
|
3778
|
+
mkdirSync2(dirPath);
|
|
3779
|
+
if (entry.children) {
|
|
3780
|
+
createFiles(entry.children, dirPath, style);
|
|
4559
3781
|
}
|
|
4560
|
-
const caseExpr = caseCondition.parts[0];
|
|
4561
|
-
this._cursor.advance();
|
|
4562
|
-
this._cursor.advance();
|
|
4563
|
-
cases.push({ type: 7 /* Case */, condition: caseExpr, children: this.parseBlockChildren() });
|
|
4564
|
-
} else if (t.type === 14 /* DEFAULT */) {
|
|
4565
|
-
this._cursor.advance();
|
|
4566
|
-
this._cursor.advance();
|
|
4567
|
-
cases.push({ type: 7 /* Case */, condition: null, children: this.parseBlockChildren() });
|
|
4568
|
-
} else {
|
|
4569
3782
|
break;
|
|
4570
|
-
|
|
4571
|
-
|
|
4572
|
-
|
|
4573
|
-
return { type: 6 /* Switch */, expression, cases };
|
|
4574
|
-
}
|
|
4575
|
-
/**
|
|
4576
|
-
* Parses child nodes until a BLOCK_CLOSE token is encountered.
|
|
4577
|
-
* Consumes the BLOCK_CLOSE before returning.
|
|
4578
|
-
*/
|
|
4579
|
-
parseBlockChildren() {
|
|
4580
|
-
const children = [];
|
|
4581
|
-
while (this._cursor.peek().type !== 17 /* BLOCK_CLOSE */) {
|
|
4582
|
-
children.push(this.parseNode());
|
|
4583
|
-
}
|
|
4584
|
-
this._cursor.advance();
|
|
4585
|
-
return children;
|
|
4586
|
-
}
|
|
4587
|
-
/**
|
|
4588
|
-
* Parses a text token into a TextNode.
|
|
4589
|
-
*/
|
|
4590
|
-
parseText(token) {
|
|
4591
|
-
this._cursor.advance();
|
|
4592
|
-
return {
|
|
4593
|
-
type: 1 /* Text */,
|
|
4594
|
-
value: token.parts[0]
|
|
4595
|
-
};
|
|
4596
|
-
}
|
|
4597
|
-
/**
|
|
4598
|
-
* Parses an interpolation token into an InterpolationNode.
|
|
4599
|
-
*/
|
|
4600
|
-
parseInterpolation(token) {
|
|
4601
|
-
this._cursor.advance();
|
|
4602
|
-
return {
|
|
4603
|
-
type: 2 /* Interpolation */,
|
|
4604
|
-
expression: token.parts[0]
|
|
4605
|
-
};
|
|
4606
|
-
}
|
|
4607
|
-
/**
|
|
4608
|
-
* Parses an element starting from a TAG_OPEN_NAME token.
|
|
4609
|
-
* Handles attributes, events, children, and tag closure.
|
|
4610
|
-
*/
|
|
4611
|
-
parseElement(token) {
|
|
4612
|
-
this._cursor.advance();
|
|
4613
|
-
const tagName = token.parts[0];
|
|
4614
|
-
const attributes = new Array();
|
|
4615
|
-
const events = new Array();
|
|
4616
|
-
let read = true;
|
|
4617
|
-
while (read) {
|
|
4618
|
-
const token2 = this._cursor.peek();
|
|
4619
|
-
switch (token2.type) {
|
|
4620
|
-
case 5 /* ATTRIBUTE */:
|
|
4621
|
-
attributes.push(this.parseAttribute(token2));
|
|
4622
|
-
break;
|
|
4623
|
-
case 6 /* EVENT */:
|
|
4624
|
-
events.push(this.parseEvent(token2));
|
|
4625
|
-
break;
|
|
4626
|
-
default:
|
|
4627
|
-
read = false;
|
|
4628
|
-
}
|
|
4629
|
-
}
|
|
4630
|
-
if (this._cursor.peek().type === 3 /* TAG_OPEN_END */) {
|
|
4631
|
-
this._cursor.advance();
|
|
4632
|
-
}
|
|
4633
|
-
if (this._cursor.peek().type === 2 /* TAG_SELF_CLOSE */) {
|
|
4634
|
-
this._cursor.advance();
|
|
4635
|
-
return {
|
|
4636
|
-
type: 0 /* Element */,
|
|
4637
|
-
tagName,
|
|
4638
|
-
attributes,
|
|
4639
|
-
events,
|
|
4640
|
-
children: []
|
|
4641
|
-
};
|
|
4642
|
-
}
|
|
4643
|
-
const children = [];
|
|
4644
|
-
while (!this.isTagClose(tagName)) {
|
|
4645
|
-
children.push(this.parseNode());
|
|
4646
|
-
}
|
|
4647
|
-
this._cursor.advance();
|
|
4648
|
-
return {
|
|
4649
|
-
type: 0 /* Element */,
|
|
4650
|
-
tagName,
|
|
4651
|
-
attributes,
|
|
4652
|
-
events,
|
|
4653
|
-
children
|
|
4654
|
-
};
|
|
4655
|
-
}
|
|
4656
|
-
/**
|
|
4657
|
-
* Parses an attribute token into an AttributeNode.
|
|
4658
|
-
* Supports literal values and interpolations as attribute values.
|
|
4659
|
-
*/
|
|
4660
|
-
parseAttribute(token) {
|
|
4661
|
-
this._cursor.advance();
|
|
4662
|
-
const raw = token.parts[0];
|
|
4663
|
-
if (!raw.includes("=")) {
|
|
4664
|
-
return { name: raw, value: "true" };
|
|
4665
|
-
}
|
|
4666
|
-
const [name, value] = raw.split("=");
|
|
4667
|
-
if (!name || !value) {
|
|
4668
|
-
throw this.error(`Invalid attribute format: ${raw}`);
|
|
4669
|
-
}
|
|
4670
|
-
const nextToken = this._cursor.peek();
|
|
4671
|
-
if (nextToken.type === 8 /* INTERPOLATION_EXPRESSION */ || nextToken.type === 7 /* INTERPOLATION_LITERAL */) {
|
|
4672
|
-
return {
|
|
4673
|
-
name,
|
|
4674
|
-
value: this.parseInterpolation(nextToken)
|
|
4675
|
-
};
|
|
4676
|
-
}
|
|
4677
|
-
return {
|
|
4678
|
-
name,
|
|
4679
|
-
value: value.replace(/^['']|['']$/g, "")
|
|
4680
|
-
};
|
|
4681
|
-
}
|
|
4682
|
-
/**
|
|
4683
|
-
* Parses an event token into an EventNode.
|
|
4684
|
-
*/
|
|
4685
|
-
parseEvent(token) {
|
|
4686
|
-
this._cursor.advance();
|
|
4687
|
-
const raw = token.parts[0];
|
|
4688
|
-
const [name, value] = raw.split("=");
|
|
4689
|
-
if (!name || !value) {
|
|
4690
|
-
throw this.error(`Invalid event format: ${raw}`);
|
|
3783
|
+
case "generateComponent":
|
|
3784
|
+
generateComponent(entry.name, basePath, false, style);
|
|
3785
|
+
break;
|
|
4691
3786
|
}
|
|
4692
|
-
return {
|
|
4693
|
-
name,
|
|
4694
|
-
handler: value.replace(/^[""]|[""]$/g, "")
|
|
4695
|
-
};
|
|
4696
|
-
}
|
|
4697
|
-
/**
|
|
4698
|
-
* Checks whether the next token is a closing tag matching the given name.
|
|
4699
|
-
*/
|
|
4700
|
-
isTagClose(tagName) {
|
|
4701
|
-
const nextToken = this._cursor.peek();
|
|
4702
|
-
return nextToken.type === 4 /* TAG_CLOSE_NAME */ && nextToken.parts[0] === tagName;
|
|
4703
|
-
}
|
|
4704
|
-
/**
|
|
4705
|
-
* Creates a parser error with a consistent prefix.
|
|
4706
|
-
*/
|
|
4707
|
-
error(message) {
|
|
4708
|
-
return new Error(`[Parser] ${message}`);
|
|
4709
|
-
}
|
|
4710
|
-
};
|
|
4711
|
-
|
|
4712
|
-
// ../packages/compiler/src/render-generator/render-generator.model.ts
|
|
4713
|
-
function generateRenderFunction(ast, componentVar = "this") {
|
|
4714
|
-
return [
|
|
4715
|
-
`
|
|
4716
|
-
const shadow = ${componentVar}.shadowRoot!;
|
|
4717
|
-
`,
|
|
4718
|
-
...ast.map((node, i) => processNode(node, `node${i}`, componentVar, "shadow")).flat()
|
|
4719
|
-
].join("\n");
|
|
4720
|
-
}
|
|
4721
|
-
function processNode(node, varName, componentVar, parentVar) {
|
|
4722
|
-
switch (node.type) {
|
|
4723
|
-
case 1 /* Text */:
|
|
4724
|
-
case 2 /* Interpolation */:
|
|
4725
|
-
return processTextAndInterpolation(node, varName, componentVar, parentVar);
|
|
4726
|
-
case 0 /* Element */:
|
|
4727
|
-
return processElement(node, varName, componentVar, parentVar);
|
|
4728
|
-
case 3 /* If */:
|
|
4729
|
-
return processIf(node, varName, componentVar, parentVar);
|
|
4730
|
-
case 5 /* For */:
|
|
4731
|
-
return processFor(node, varName, componentVar, parentVar);
|
|
4732
|
-
case 6 /* Switch */:
|
|
4733
|
-
return processSwitch(node, varName, componentVar, parentVar);
|
|
4734
|
-
default:
|
|
4735
|
-
return [];
|
|
4736
|
-
}
|
|
4737
|
-
}
|
|
4738
|
-
function processTextAndInterpolation(node, varName, componentVar, parentVar) {
|
|
4739
|
-
const textValue = node.type === 1 /* Text */ ? JSON.stringify(node.value) : resolveExpression(node.expression, componentVar);
|
|
4740
|
-
return [
|
|
4741
|
-
`const ${varName} = document.createTextNode(${textValue});`,
|
|
4742
|
-
`${parentVar}.appendChild(${varName});`
|
|
4743
|
-
];
|
|
4744
|
-
}
|
|
4745
|
-
function processElement(node, varName, componentVar, parentVar) {
|
|
4746
|
-
return [
|
|
4747
|
-
`const ${varName} = document.createElement("${node.tagName}");`,
|
|
4748
|
-
...node.attributes?.map((attr) => `${varName}.setAttribute('${attr.name}', ${typeof attr.value === "string" ? attr.value : `${componentVar}.${attr.value.expression}`});`) || [],
|
|
4749
|
-
...node.events?.map((event) => `${varName}.addEventListener("${event.name}", ${componentVar}.${event.handler}.bind(${componentVar}));`) || [],
|
|
4750
|
-
`${parentVar}.appendChild(${varName});`,
|
|
4751
|
-
...node.children.map((child, i) => processNode(child, `${varName}_c${i}`, componentVar, varName)).flat()
|
|
4752
|
-
];
|
|
4753
|
-
}
|
|
4754
|
-
function processIf(node, varName, componentVar, parentVar) {
|
|
4755
|
-
const code = [
|
|
4756
|
-
`if (${resolveExpression(node.condition, componentVar)}) {`,
|
|
4757
|
-
...node.consequent.map((child, idx) => indent(...processNode(child, `${varName}_t${idx}`, componentVar, parentVar))).flat(),
|
|
4758
|
-
"}"
|
|
4759
|
-
];
|
|
4760
|
-
const alt = node.alternate;
|
|
4761
|
-
if (alt) {
|
|
4762
|
-
code[code.length - 1] += " else {";
|
|
4763
|
-
code.push(
|
|
4764
|
-
...alt.children.map((child, idx) => indent(...processNode(child, `${varName}_e${idx}`, componentVar, parentVar))).flat(),
|
|
4765
|
-
"}"
|
|
4766
|
-
);
|
|
4767
|
-
}
|
|
4768
|
-
return code;
|
|
4769
|
-
}
|
|
4770
|
-
function processFor(node, varName, componentVar, parentVar) {
|
|
4771
|
-
const iterExpr = resolveForExpression(node.expression, componentVar);
|
|
4772
|
-
return [
|
|
4773
|
-
`for (${iterExpr}) {`,
|
|
4774
|
-
...node.children.map((child, idx) => indent(...processNode(child, `${varName}_f${idx}`, componentVar, parentVar))).flat(),
|
|
4775
|
-
"}"
|
|
4776
|
-
];
|
|
4777
|
-
}
|
|
4778
|
-
function processSwitch(node, varName, componentVar, parentVar) {
|
|
4779
|
-
return [
|
|
4780
|
-
`switch (${resolveExpression(node.expression, componentVar)}) {`,
|
|
4781
|
-
...node.cases.map((caseNode) => [
|
|
4782
|
-
...indent(
|
|
4783
|
-
`${!caseNode.condition ? "default" : `case ${caseNode.condition}`}: {`,
|
|
4784
|
-
...caseNode.children.map((child, i) => indent(...processNode(child, `${varName}_s${i}_${i}`, componentVar, parentVar))).flat(),
|
|
4785
|
-
`${indent("break;")}`,
|
|
4786
|
-
`}`
|
|
4787
|
-
)
|
|
4788
|
-
]).flat(),
|
|
4789
|
-
"}"
|
|
4790
|
-
];
|
|
4791
|
-
}
|
|
4792
|
-
function resolveForExpression(expression, componentVar) {
|
|
4793
|
-
const match = expression.match(/^let\s+(\w+)\s+of\s+(\w+)$/);
|
|
4794
|
-
if (!match) {
|
|
4795
|
-
throw new Error(`String "${expression}" does not match the structure "let X of Y"`);
|
|
4796
|
-
}
|
|
4797
|
-
const [, X, Y] = match;
|
|
4798
|
-
return `const ${X} of this.${Y}`;
|
|
4799
|
-
}
|
|
4800
|
-
function resolveExpression(expression, componentVar) {
|
|
4801
|
-
return expression.replace(/\b([a-zA-Z_$][a-zA-Z0-9_$]*)\b/g, (match) => match === componentVar ? match : `${componentVar}.${match}`);
|
|
4802
|
-
}
|
|
4803
|
-
function indent(...lines) {
|
|
4804
|
-
return lines.map((line) => ` ${line}`);
|
|
4805
|
-
}
|
|
4806
|
-
|
|
4807
|
-
// ../packages/cli/src/commands/compile/compile.command.ts
|
|
4808
|
-
import { readFileSync, writeFileSync as writeFileSync2 } from "fs";
|
|
4809
|
-
import { basename, dirname, extname, resolve } from "path";
|
|
4810
|
-
function compileFile(inputPath, outputPath) {
|
|
4811
|
-
const absInput = resolve(process.cwd(), inputPath);
|
|
4812
|
-
const absOutput = outputPath ? resolve(process.cwd(), outputPath) : resolve(dirname(absInput), `${basename(absInput, extname(absInput))}.render.js`);
|
|
4813
|
-
let source;
|
|
4814
|
-
try {
|
|
4815
|
-
source = readFileSync(absInput, "utf8");
|
|
4816
|
-
} catch {
|
|
4817
|
-
console.error(`\u2716 Cannot read file: ${absInput}`);
|
|
4818
|
-
process.exit(1);
|
|
4819
|
-
}
|
|
4820
|
-
const result = compile(source);
|
|
4821
|
-
writeFileSync2(absOutput, result, "utf8");
|
|
4822
|
-
console.log(`\u2714 Compiled: ${inputPath} \u2192 ${absOutput}`);
|
|
4823
|
-
}
|
|
4824
|
-
function compile(source) {
|
|
4825
|
-
const tokens = new Lexer(source).tokenize();
|
|
4826
|
-
const ast = new Parser(tokens).parse();
|
|
4827
|
-
return generateRenderFunction(ast);
|
|
4828
|
-
}
|
|
4829
|
-
|
|
4830
|
-
// ../packages/cli/src/commands/compile/compile.ts
|
|
4831
|
-
function makeCompileCommand() {
|
|
4832
|
-
return new Command("compile").alias("co").description("Compile a Xendar HTML template into a render function").argument("<input>", "Path to the .xd.component.html template file").option("-o, --output <path>", "Path for the emitted output file (default: <input>.render.js)").action((input, options) => {
|
|
4833
|
-
compileFile(input, options.output);
|
|
4834
3787
|
});
|
|
4835
3788
|
}
|
|
4836
3789
|
|
|
4837
3790
|
// ../packages/cli/src/index.ts
|
|
4838
|
-
program.name("xd").description("
|
|
4839
|
-
program.addCommand(
|
|
4840
|
-
program.addCommand(
|
|
3791
|
+
program.name("xd").description("Xaendar CLI").version("0.2.0");
|
|
3792
|
+
program.addCommand(generateCommand());
|
|
3793
|
+
program.addCommand(newCommand());
|
|
4841
3794
|
program.parse();
|
|
4842
3795
|
//# sourceMappingURL=index.js.map
|