@canvasengine/compiler 2.0.0-beta.5 → 2.0.0-beta.50
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/grammar.pegjs +1119 -0
- package/dist/grammar2.pegjs +995 -0
- package/dist/index.d.ts +35 -2
- package/dist/index.js +335 -10
- package/dist/index.js.map +1 -1
- package/package.json +5 -2
- package/grammar.pegjs +0 -186
- package/index.ts +0 -167
- package/tests/compiler.spec.ts +0 -352
- package/tsconfig.json +0 -29
- package/tsup.config.ts +0 -14
package/dist/index.d.ts
CHANGED
|
@@ -1,9 +1,42 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Vite plugin to load shader files (.frag, .vert, .wgsl) as text strings
|
|
3
|
+
*
|
|
4
|
+
* This plugin allows importing shader files directly as string literals in your code.
|
|
5
|
+
* It supports fragment shaders (.frag), vertex shaders (.vert), and WebGPU shaders (.wgsl).
|
|
6
|
+
* The content is loaded as a raw string and can be used directly with graphics APIs.
|
|
7
|
+
*
|
|
8
|
+
* @returns {object} - Vite plugin configuration object
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```typescript
|
|
12
|
+
* // In your vite.config.ts
|
|
13
|
+
* import { shaderLoader } from './path/to/compiler'
|
|
14
|
+
*
|
|
15
|
+
* export default defineConfig({
|
|
16
|
+
* plugins: [shaderLoader()]
|
|
17
|
+
* })
|
|
18
|
+
*
|
|
19
|
+
* // In your code
|
|
20
|
+
* import fragmentShader from './shader.frag'
|
|
21
|
+
* import vertexShader from './shader.vert'
|
|
22
|
+
* import computeShader from './shader.wgsl'
|
|
23
|
+
*
|
|
24
|
+
* console.log(fragmentShader) // Raw shader code as string
|
|
25
|
+
* ```
|
|
26
|
+
*/
|
|
27
|
+
declare function shaderLoader(): {
|
|
2
28
|
name: string;
|
|
3
29
|
transform(code: string, id: string): {
|
|
4
30
|
code: string;
|
|
5
31
|
map: null;
|
|
6
32
|
} | undefined;
|
|
7
33
|
};
|
|
34
|
+
declare function canvasengine(): {
|
|
35
|
+
name: string;
|
|
36
|
+
transform(code: string, id: string): {
|
|
37
|
+
code: string;
|
|
38
|
+
map: null;
|
|
39
|
+
} | null;
|
|
40
|
+
};
|
|
8
41
|
|
|
9
|
-
export { canvasengine as default };
|
|
42
|
+
export { canvasengine as default, shaderLoader };
|
package/dist/index.js
CHANGED
|
@@ -8,17 +8,292 @@ import * as ts from "typescript";
|
|
|
8
8
|
import { fileURLToPath } from "url";
|
|
9
9
|
var { generate } = pkg;
|
|
10
10
|
var DEV_SRC = "../../src";
|
|
11
|
+
function generateHash(str) {
|
|
12
|
+
let hash = 0;
|
|
13
|
+
for (let i = 0; i < str.length; i++) {
|
|
14
|
+
const char = str.charCodeAt(i);
|
|
15
|
+
hash = (hash << 5) - hash + char;
|
|
16
|
+
hash = hash & hash;
|
|
17
|
+
}
|
|
18
|
+
const positiveHash = Math.abs(hash);
|
|
19
|
+
let result = "";
|
|
20
|
+
for (let i = 0; i < 8; i++) {
|
|
21
|
+
const letterIndex = (positiveHash + i * 31) % 26;
|
|
22
|
+
result += String.fromCharCode(97 + letterIndex);
|
|
23
|
+
}
|
|
24
|
+
return result;
|
|
25
|
+
}
|
|
26
|
+
function showErrorMessage(template, error) {
|
|
27
|
+
if (!error.location) {
|
|
28
|
+
return `Syntax error: ${error.message}`;
|
|
29
|
+
}
|
|
30
|
+
const lines = template.split("\n");
|
|
31
|
+
const { line, column } = error.location.start;
|
|
32
|
+
const errorLine = lines[line - 1] || "";
|
|
33
|
+
const pointer = " ".repeat(column - 1) + "^";
|
|
34
|
+
return `Syntax error at line ${line}, column ${column}: ${error.message}
|
|
35
|
+
|
|
36
|
+
${errorLine}
|
|
37
|
+
${pointer}
|
|
38
|
+
`;
|
|
39
|
+
}
|
|
40
|
+
function scopeCSS(css, scopeClass) {
|
|
41
|
+
const scopeSelector = `.${scopeClass}`;
|
|
42
|
+
let result = "";
|
|
43
|
+
let i = 0;
|
|
44
|
+
let depth = 0;
|
|
45
|
+
let inRule = false;
|
|
46
|
+
let selectorBuffer = "";
|
|
47
|
+
while (i < css.length) {
|
|
48
|
+
const char = css[i];
|
|
49
|
+
if (char === "@" && !inRule && selectorBuffer === "") {
|
|
50
|
+
const atRuleStart = i;
|
|
51
|
+
i++;
|
|
52
|
+
while (i < css.length && css[i] !== "{") {
|
|
53
|
+
i++;
|
|
54
|
+
}
|
|
55
|
+
if (i < css.length) {
|
|
56
|
+
depth = 1;
|
|
57
|
+
i++;
|
|
58
|
+
while (i < css.length && depth > 0) {
|
|
59
|
+
if (css[i] === "{") depth++;
|
|
60
|
+
else if (css[i] === "}") depth--;
|
|
61
|
+
i++;
|
|
62
|
+
}
|
|
63
|
+
result += css.substring(atRuleStart, i);
|
|
64
|
+
}
|
|
65
|
+
continue;
|
|
66
|
+
}
|
|
67
|
+
if (char === "{" && !inRule) {
|
|
68
|
+
const selectorText = selectorBuffer.trim();
|
|
69
|
+
if (selectorText) {
|
|
70
|
+
const scopedSelectors = selectorText.split(",").map((sel) => {
|
|
71
|
+
const trimmed = sel.trim();
|
|
72
|
+
return trimmed ? `${scopeSelector} ${trimmed}` : trimmed;
|
|
73
|
+
}).join(", ");
|
|
74
|
+
result += scopedSelectors;
|
|
75
|
+
}
|
|
76
|
+
result += " {";
|
|
77
|
+
inRule = true;
|
|
78
|
+
depth = 1;
|
|
79
|
+
selectorBuffer = "";
|
|
80
|
+
} else if (char === "{" && inRule) {
|
|
81
|
+
result += char;
|
|
82
|
+
depth++;
|
|
83
|
+
} else if (char === "}" && inRule) {
|
|
84
|
+
result += char;
|
|
85
|
+
depth--;
|
|
86
|
+
if (depth === 0) {
|
|
87
|
+
inRule = false;
|
|
88
|
+
}
|
|
89
|
+
} else if (!inRule) {
|
|
90
|
+
selectorBuffer += char;
|
|
91
|
+
} else {
|
|
92
|
+
result += char;
|
|
93
|
+
if (char === "{") depth++;
|
|
94
|
+
}
|
|
95
|
+
i++;
|
|
96
|
+
}
|
|
97
|
+
if (selectorBuffer.trim()) {
|
|
98
|
+
const scopedSelectors = selectorBuffer.trim().split(",").map((sel) => {
|
|
99
|
+
const trimmed = sel.trim();
|
|
100
|
+
return trimmed ? `${scopeSelector} ${trimmed}` : trimmed;
|
|
101
|
+
}).join(", ");
|
|
102
|
+
result += scopedSelectors;
|
|
103
|
+
}
|
|
104
|
+
return result;
|
|
105
|
+
}
|
|
106
|
+
function splitCallArguments(argsText) {
|
|
107
|
+
const args = [];
|
|
108
|
+
let current = "";
|
|
109
|
+
let depth = 0;
|
|
110
|
+
let inSingle = false;
|
|
111
|
+
let inDouble = false;
|
|
112
|
+
let inTemplate = false;
|
|
113
|
+
let escaped = false;
|
|
114
|
+
for (let i = 0; i < argsText.length; i++) {
|
|
115
|
+
const char = argsText[i];
|
|
116
|
+
if (escaped) {
|
|
117
|
+
current += char;
|
|
118
|
+
escaped = false;
|
|
119
|
+
continue;
|
|
120
|
+
}
|
|
121
|
+
if (char === "\\") {
|
|
122
|
+
current += char;
|
|
123
|
+
escaped = true;
|
|
124
|
+
continue;
|
|
125
|
+
}
|
|
126
|
+
if (inSingle) {
|
|
127
|
+
current += char;
|
|
128
|
+
if (char === "'") inSingle = false;
|
|
129
|
+
continue;
|
|
130
|
+
}
|
|
131
|
+
if (inDouble) {
|
|
132
|
+
current += char;
|
|
133
|
+
if (char === '"') inDouble = false;
|
|
134
|
+
continue;
|
|
135
|
+
}
|
|
136
|
+
if (inTemplate) {
|
|
137
|
+
current += char;
|
|
138
|
+
if (char === "`") inTemplate = false;
|
|
139
|
+
continue;
|
|
140
|
+
}
|
|
141
|
+
if (char === "'") {
|
|
142
|
+
inSingle = true;
|
|
143
|
+
current += char;
|
|
144
|
+
continue;
|
|
145
|
+
}
|
|
146
|
+
if (char === '"') {
|
|
147
|
+
inDouble = true;
|
|
148
|
+
current += char;
|
|
149
|
+
continue;
|
|
150
|
+
}
|
|
151
|
+
if (char === "`") {
|
|
152
|
+
inTemplate = true;
|
|
153
|
+
current += char;
|
|
154
|
+
continue;
|
|
155
|
+
}
|
|
156
|
+
if (char === "(" || char === "{" || char === "[") {
|
|
157
|
+
depth++;
|
|
158
|
+
current += char;
|
|
159
|
+
continue;
|
|
160
|
+
}
|
|
161
|
+
if (char === ")" || char === "}" || char === "]") {
|
|
162
|
+
depth--;
|
|
163
|
+
current += char;
|
|
164
|
+
continue;
|
|
165
|
+
}
|
|
166
|
+
if (char === "," && depth === 0) {
|
|
167
|
+
args.push(current.trim());
|
|
168
|
+
current = "";
|
|
169
|
+
continue;
|
|
170
|
+
}
|
|
171
|
+
current += char;
|
|
172
|
+
}
|
|
173
|
+
if (current.trim()) {
|
|
174
|
+
args.push(current.trim());
|
|
175
|
+
}
|
|
176
|
+
return args;
|
|
177
|
+
}
|
|
178
|
+
function addScopeClassToDOMContainer(parsedTemplate, scopeClass) {
|
|
179
|
+
let result = "";
|
|
180
|
+
let cursor = 0;
|
|
181
|
+
while (cursor < parsedTemplate.length) {
|
|
182
|
+
const start = parsedTemplate.indexOf("h(DOMContainer", cursor);
|
|
183
|
+
if (start === -1) {
|
|
184
|
+
result += parsedTemplate.slice(cursor);
|
|
185
|
+
break;
|
|
186
|
+
}
|
|
187
|
+
result += parsedTemplate.slice(cursor, start);
|
|
188
|
+
const openParen = parsedTemplate.indexOf("(", start);
|
|
189
|
+
if (openParen === -1) {
|
|
190
|
+
result += parsedTemplate.slice(start);
|
|
191
|
+
break;
|
|
192
|
+
}
|
|
193
|
+
let depth = 0;
|
|
194
|
+
let inSingle = false;
|
|
195
|
+
let inDouble = false;
|
|
196
|
+
let inTemplate = false;
|
|
197
|
+
let escaped = false;
|
|
198
|
+
let end = -1;
|
|
199
|
+
for (let i = openParen; i < parsedTemplate.length; i++) {
|
|
200
|
+
const char = parsedTemplate[i];
|
|
201
|
+
if (escaped) {
|
|
202
|
+
escaped = false;
|
|
203
|
+
continue;
|
|
204
|
+
}
|
|
205
|
+
if (char === "\\") {
|
|
206
|
+
escaped = true;
|
|
207
|
+
continue;
|
|
208
|
+
}
|
|
209
|
+
if (inSingle) {
|
|
210
|
+
if (char === "'") inSingle = false;
|
|
211
|
+
continue;
|
|
212
|
+
}
|
|
213
|
+
if (inDouble) {
|
|
214
|
+
if (char === '"') inDouble = false;
|
|
215
|
+
continue;
|
|
216
|
+
}
|
|
217
|
+
if (inTemplate) {
|
|
218
|
+
if (char === "`") inTemplate = false;
|
|
219
|
+
continue;
|
|
220
|
+
}
|
|
221
|
+
if (char === "'") {
|
|
222
|
+
inSingle = true;
|
|
223
|
+
continue;
|
|
224
|
+
}
|
|
225
|
+
if (char === '"') {
|
|
226
|
+
inDouble = true;
|
|
227
|
+
continue;
|
|
228
|
+
}
|
|
229
|
+
if (char === "`") {
|
|
230
|
+
inTemplate = true;
|
|
231
|
+
continue;
|
|
232
|
+
}
|
|
233
|
+
if (char === "(") depth++;
|
|
234
|
+
if (char === ")") depth--;
|
|
235
|
+
if (depth === 0) {
|
|
236
|
+
end = i + 1;
|
|
237
|
+
break;
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
if (end === -1) {
|
|
241
|
+
result += parsedTemplate.slice(start);
|
|
242
|
+
break;
|
|
243
|
+
}
|
|
244
|
+
const callText = parsedTemplate.slice(start, end);
|
|
245
|
+
const argsText = parsedTemplate.slice(openParen + 1, end - 1);
|
|
246
|
+
const args = splitCallArguments(argsText);
|
|
247
|
+
if (args[0]?.trim() !== "DOMContainer") {
|
|
248
|
+
result += callText;
|
|
249
|
+
cursor = end;
|
|
250
|
+
continue;
|
|
251
|
+
}
|
|
252
|
+
if (args.length === 1) {
|
|
253
|
+
args.push(`{ _scopeClass: '${scopeClass}' }`);
|
|
254
|
+
} else {
|
|
255
|
+
const props = args[1].trim();
|
|
256
|
+
if (props === "null" || props === "undefined") {
|
|
257
|
+
args[1] = `{ _scopeClass: '${scopeClass}' }`;
|
|
258
|
+
} else if (props.startsWith("{")) {
|
|
259
|
+
args[1] = props.replace(/^\{\s*/, `{ _scopeClass: '${scopeClass}', `);
|
|
260
|
+
} else {
|
|
261
|
+
args[1] = `{ _scopeClass: '${scopeClass}', ...${props} }`;
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
result += `h(${args.join(", ")})`;
|
|
265
|
+
cursor = end;
|
|
266
|
+
}
|
|
267
|
+
return result;
|
|
268
|
+
}
|
|
269
|
+
function shaderLoader() {
|
|
270
|
+
const filter = createFilter(/\.(frag|vert|wgsl)$/);
|
|
271
|
+
return {
|
|
272
|
+
name: "vite-plugin-shader-loader",
|
|
273
|
+
transform(code, id) {
|
|
274
|
+
if (!filter(id)) return;
|
|
275
|
+
const escapedCode = code.replace(/\\/g, "\\\\").replace(/`/g, "\\`").replace(/\$/g, "\\$");
|
|
276
|
+
return {
|
|
277
|
+
code: `export default \`${escapedCode}\`;`,
|
|
278
|
+
map: null
|
|
279
|
+
};
|
|
280
|
+
}
|
|
281
|
+
};
|
|
282
|
+
}
|
|
11
283
|
function canvasengine() {
|
|
12
284
|
const filter = createFilter("**/*.ce");
|
|
285
|
+
const useLegacyGrammar = process.env.CANVASENGINE_COMPILER_V1 === "1";
|
|
13
286
|
const __filename = fileURLToPath(import.meta.url);
|
|
14
287
|
const __dirname = path.dirname(__filename);
|
|
288
|
+
const grammarFile = useLegacyGrammar ? "grammar.pegjs" : "grammar2.pegjs";
|
|
15
289
|
const grammar = fs.readFileSync(
|
|
16
|
-
path.join(__dirname,
|
|
290
|
+
path.join(__dirname, grammarFile),
|
|
17
291
|
"utf8"
|
|
18
292
|
);
|
|
19
293
|
const parser = generate(grammar);
|
|
20
294
|
const isDev = process.env.NODE_ENV === "dev";
|
|
21
295
|
const FLAG_COMMENT = "/*--[TPL]--*/";
|
|
296
|
+
let warnedAboutGrammar = false;
|
|
22
297
|
const PRIMITIVE_COMPONENTS = [
|
|
23
298
|
"Canvas",
|
|
24
299
|
"Sprite",
|
|
@@ -26,25 +301,56 @@ function canvasengine() {
|
|
|
26
301
|
"Viewport",
|
|
27
302
|
"Graphics",
|
|
28
303
|
"Container",
|
|
304
|
+
"Navigation",
|
|
29
305
|
"ImageMap",
|
|
30
306
|
"NineSliceSprite",
|
|
31
307
|
"Rect",
|
|
32
308
|
"Circle",
|
|
309
|
+
"Ellipse",
|
|
310
|
+
"Triangle",
|
|
33
311
|
"TilingSprite",
|
|
34
312
|
"svg",
|
|
35
|
-
"Video"
|
|
313
|
+
"Video",
|
|
314
|
+
"Mesh",
|
|
315
|
+
"Svg",
|
|
316
|
+
"DOMContainer",
|
|
317
|
+
"DOMElement",
|
|
318
|
+
"DOMSprite",
|
|
319
|
+
"Button",
|
|
320
|
+
"Joystick"
|
|
36
321
|
];
|
|
37
322
|
return {
|
|
38
323
|
name: "vite-plugin-ce",
|
|
39
324
|
transform(code, id) {
|
|
40
|
-
if (!filter(id)) return;
|
|
325
|
+
if (!filter(id)) return null;
|
|
326
|
+
if (!warnedAboutGrammar) {
|
|
327
|
+
warnedAboutGrammar = true;
|
|
328
|
+
const legacyNote = "Set CANVASENGINE_COMPILER_V1=1 to compile with the legacy grammar (v1).";
|
|
329
|
+
if (useLegacyGrammar) {
|
|
330
|
+
console.warn(`[canvasengine] Using legacy grammar v1. ${legacyNote}`);
|
|
331
|
+
} else {
|
|
332
|
+
console.warn(`[canvasengine] Breaking change: compiler grammar v2 is now the default. ${legacyNote}`);
|
|
333
|
+
}
|
|
334
|
+
}
|
|
41
335
|
const scriptMatch = code.match(/<script>([\s\S]*?)<\/script>/);
|
|
42
336
|
let scriptContent = scriptMatch ? scriptMatch[1].trim() : "";
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
337
|
+
const styleTagMatch = code.match(/<style([^>]*)>([\s\S]*?)<\/style>/);
|
|
338
|
+
let styleContent = "";
|
|
339
|
+
let isScoped = false;
|
|
340
|
+
if (styleTagMatch) {
|
|
341
|
+
const styleAttributes = styleTagMatch[1].trim();
|
|
342
|
+
styleContent = styleTagMatch[2].trim();
|
|
343
|
+
isScoped = /scoped(?:\s|>|$)/.test(styleAttributes);
|
|
344
|
+
}
|
|
345
|
+
let template = code.replace(/<script>[\s\S]*?<\/script>/, "").replace(/<style[^>]*>[\s\S]*?<\/style>/, "").replace(/^\s+|\s+$/g, "");
|
|
346
|
+
let parsedTemplate;
|
|
347
|
+
try {
|
|
348
|
+
parsedTemplate = parser.parse(template);
|
|
349
|
+
} catch (error) {
|
|
350
|
+
const errorMsg = showErrorMessage(template, error);
|
|
351
|
+
throw new Error(`Error parsing template in file ${id}:
|
|
352
|
+
${errorMsg}`);
|
|
353
|
+
}
|
|
48
354
|
scriptContent += FLAG_COMMENT + parsedTemplate;
|
|
49
355
|
let transpiledCode = ts.transpileModule(scriptContent, {
|
|
50
356
|
compilerOptions: {
|
|
@@ -95,10 +401,28 @@ ${importsCode}`;
|
|
|
95
401
|
${importsCode}`;
|
|
96
402
|
}
|
|
97
403
|
});
|
|
404
|
+
let processedStyleContent = styleContent;
|
|
405
|
+
let scopeClass = "";
|
|
406
|
+
if (isScoped && styleContent) {
|
|
407
|
+
const fileHash = generateHash(id);
|
|
408
|
+
scopeClass = fileHash;
|
|
409
|
+
processedStyleContent = scopeCSS(styleContent, scopeClass);
|
|
410
|
+
parsedTemplate = addScopeClassToDOMContainer(parsedTemplate, scopeClass);
|
|
411
|
+
}
|
|
412
|
+
const escapedStyleContent = processedStyleContent.replace(/\\/g, "\\\\").replace(/'/g, "\\'").replace(/\n/g, "\\n").replace(/\r/g, "\\r");
|
|
413
|
+
const styleId = `ce-style-${id.replace(/[^a-zA-Z0-9]/g, "-")}`;
|
|
414
|
+
const styleInjectionCode = styleContent ? `// Inject CSS styles into the document head
|
|
415
|
+
if (typeof document !== 'undefined' && !document.getElementById('${styleId}')) {
|
|
416
|
+
const styleElement = document.createElement('style');
|
|
417
|
+
styleElement.id = '${styleId}';
|
|
418
|
+
styleElement.textContent = '${escapedStyleContent}';
|
|
419
|
+
document.head.appendChild(styleElement);
|
|
420
|
+
}
|
|
421
|
+
` : "";
|
|
98
422
|
const output = String.raw`
|
|
99
423
|
${importsCode}
|
|
100
424
|
import { useProps, useDefineProps } from ${isDev ? `'${DEV_SRC}'` : "'canvasengine'"}
|
|
101
|
-
|
|
425
|
+
${styleInjectionCode}
|
|
102
426
|
export default function component($$props) {
|
|
103
427
|
const $props = useProps($$props)
|
|
104
428
|
const defineProps = useDefineProps($$props)
|
|
@@ -115,6 +439,7 @@ ${importsCode}`;
|
|
|
115
439
|
};
|
|
116
440
|
}
|
|
117
441
|
export {
|
|
118
|
-
canvasengine as default
|
|
442
|
+
canvasengine as default,
|
|
443
|
+
shaderLoader
|
|
119
444
|
};
|
|
120
445
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../index.ts"],"sourcesContent":["import { createFilter } from \"vite\";\nimport { parse } from \"acorn\";\nimport fs from \"fs\";\nimport pkg from \"peggy\";\nimport path from \"path\";\nimport * as ts from \"typescript\";\nimport { fileURLToPath } from 'url';\n\nconst { generate } = pkg;\n\nconst DEV_SRC = \"../../src\"\n\nexport default function canvasengine() {\n const filter = createFilter(\"**/*.ce\");\n\n // Convert import.meta.url to a file path\n const __filename = fileURLToPath(import.meta.url);\n const __dirname = path.dirname(__filename);\n\n const grammar = fs.readFileSync(\n path.join(__dirname, \"grammar.pegjs\").replace(\"dist/grammar.pegjs\", \"grammar.pegjs\"), \n \"utf8\");\n const parser = generate(grammar);\n const isDev = process.env.NODE_ENV === \"dev\";\n const FLAG_COMMENT = \"/*--[TPL]--*/\";\n\n const PRIMITIVE_COMPONENTS = [\n \"Canvas\",\n \"Sprite\",\n \"Text\",\n \"Viewport\",\n \"Graphics\",\n \"Container\",\n \"ImageMap\",\n \"NineSliceSprite\",\n \"Rect\",\n \"Circle\",\n \"TilingSprite\",\n \"svg\",\n \"Video\"\n ];\n\n return {\n name: \"vite-plugin-ce\",\n transform(code: string, id: string) {\n if (!filter(id)) return;\n\n // Extract the script content\n const scriptMatch = code.match(/<script>([\\s\\S]*?)<\\/script>/);\n let scriptContent = scriptMatch ? scriptMatch[1].trim() : \"\";\n \n // Transform SVG tags to Svg components\n let template = code.replace(/<script>[\\s\\S]*?<\\/script>/, \"\")\n .replace(/^\\s+|\\s+$/g, '');\n \n // Add SVG transformation\n template = template.replace(/<svg>([\\s\\S]*?)<\\/svg>/g, (match, content) => {\n return `<Svg content=\"${content.trim()}\" />`;\n });\n \n const parsedTemplate = parser.parse(template);\n\n // trick to avoid typescript remove imports in scriptContent\n scriptContent += FLAG_COMMENT + parsedTemplate\n\n let transpiledCode = ts.transpileModule(scriptContent, {\n compilerOptions: {\n module: ts.ModuleKind.Preserve,\n },\n }).outputText;\n\n // remove code after /*---*/\n transpiledCode = transpiledCode.split(FLAG_COMMENT)[0]\n\n // Use Acorn to parse the script content\n const parsed = parse(transpiledCode, {\n sourceType: \"module\",\n ecmaVersion: 2020,\n });\n\n // Extract imports\n const imports = parsed.body.filter(\n (node) => node.type === \"ImportDeclaration\"\n );\n\n // Extract non-import statements from scriptContent\n const nonImportCode = parsed.body\n .filter((node) => node.type !== \"ImportDeclaration\")\n .map((node) => transpiledCode.slice(node.start, node.end))\n .join(\"\\n\");\n\n let importsCode = imports\n .map((imp) => {\n let importCode = transpiledCode.slice(imp.start, imp.end);\n if (isDev && importCode.includes(\"from 'canvasengine'\")) {\n importCode = importCode.replace(\n \"from 'canvasengine'\",\n `from '${DEV_SRC}'`\n );\n }\n return importCode;\n })\n .join(\"\\n\");\n\n // Define an array for required imports\n const requiredImports = [\"h\", \"computed\", \"cond\", \"loop\"];\n\n // Check for missing imports\n const missingImports = requiredImports.filter(\n (importName) =>\n !imports.some(\n (imp) =>\n imp.specifiers &&\n imp.specifiers.some(\n (spec) =>\n spec.type === \"ImportSpecifier\" &&\n spec.imported && \n 'name' in spec.imported &&\n spec.imported.name === importName\n )\n )\n );\n\n // Add missing imports\n if (missingImports.length > 0) {\n const additionalImportCode = `import { ${missingImports.join(\n \", \"\n )} } from ${isDev ? `'${DEV_SRC}'` : \"'canvasengine'\"};`;\n importsCode = `${additionalImportCode}\\n${importsCode}`;\n }\n\n // Check for primitive components in parsedTemplate\n const primitiveImports = PRIMITIVE_COMPONENTS.filter((component) =>\n parsedTemplate.includes(`h(${component}`)\n );\n\n // Add missing imports for primitive components\n primitiveImports.forEach((component) => {\n const importStatement = `import { ${component} } from ${\n isDev ? `'${DEV_SRC}'` : \"'canvasengine'\"\n };`;\n if (!importsCode.includes(importStatement)) {\n importsCode = `${importStatement}\\n${importsCode}`;\n }\n });\n\n // Generate the output\n const output = String.raw`\n ${importsCode}\n import { useProps, useDefineProps } from ${isDev ? `'${DEV_SRC}'` : \"'canvasengine'\"}\n\n export default function component($$props) {\n const $props = useProps($$props)\n const defineProps = useDefineProps($$props)\n ${nonImportCode}\n let $this = ${parsedTemplate}\n return $this\n }\n `;\n\n return {\n code: output,\n map: null,\n };\n },\n };\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../index.ts"],"sourcesContent":["import { createFilter } from \"vite\";\nimport { parse } from \"acorn\";\nimport fs from \"fs\";\nimport pkg from \"peggy\";\nimport path from \"path\";\nimport * as ts from \"typescript\";\nimport { fileURLToPath } from 'url';\n\nconst { generate } = pkg;\n\nconst DEV_SRC = \"../../src\"\n\n/**\n * Generates a short hash (8 characters, letters only) from a string\n * \n * @param {string} str - The string to hash\n * @returns {string} - An 8-character hash containing only lowercase letters (a-z)\n */\nfunction generateHash(str: string): string {\n let hash = 0;\n for (let i = 0; i < str.length; i++) {\n const char = str.charCodeAt(i);\n hash = ((hash << 5) - hash) + char;\n hash = hash & hash; // Convert to 32-bit integer\n }\n // Convert to positive number and map to letters only (a-z)\n // Use modulo to map to 26 letters, then convert to character\n const positiveHash = Math.abs(hash);\n let result = '';\n for (let i = 0; i < 8; i++) {\n const letterIndex = (positiveHash + i * 31) % 26; // 31 is a prime to spread values\n result += String.fromCharCode(97 + letterIndex); // 97 is 'a'\n }\n return result;\n}\n\n/**\n * Formats a syntax error message with visual pointer to the error location\n * \n * @param {string} template - The template content that failed to parse\n * @param {object} error - The error object with location information\n * @returns {string} - Formatted error message with a visual pointer\n * \n * @example\n * ```\n * const errorMessage = showErrorMessage(\"<Canvas>test(d)</Canvas>\", syntaxError);\n * // Returns a formatted error message with an arrow pointing to 'd'\n * ```\n */\nfunction showErrorMessage(template: string, error: any): string {\n if (!error.location) {\n return `Syntax error: ${error.message}`;\n }\n\n const lines = template.split('\\n');\n const { line, column } = error.location.start;\n const errorLine = lines[line - 1] || '';\n \n // Create a visual pointer with an arrow\n const pointer = ' '.repeat(column - 1) + '^';\n \n return `Syntax error at line ${line}, column ${column}: ${error.message}\\n\\n` +\n `${errorLine}\\n${pointer}\\n`;\n}\n\n/**\n * Scopes CSS selectors by prefixing them with a class selector\n * \n * This function prefixes all CSS rule selectors (not @rules) with a class\n * selector to scope the styles to a specific component instance.\n * \n * @param {string} css - The CSS content to scope\n * @param {string} scopeClass - The unique scope class to use (without the dot)\n * @returns {string} - The scoped CSS content\n * \n * @example\n * ```\n * const scoped = scopeCSS('.my-class { color: red; }', 'ce-scope-abc123');\n * // Returns: '.ce-scope-abc123 .my-class { color: red; }'\n * ```\n */\nfunction scopeCSS(css: string, scopeClass: string): string {\n const scopeSelector = `.${scopeClass}`;\n \n // Process CSS by finding rule blocks while skipping @rules\n let result = '';\n let i = 0;\n let depth = 0;\n let inRule = false;\n let selectorBuffer = '';\n \n while (i < css.length) {\n const char = css[i];\n \n if (char === '@' && !inRule && selectorBuffer === '') {\n // Found @rule - copy it as-is until matching closing brace\n const atRuleStart = i;\n i++; // Skip '@'\n \n // Find the opening brace\n while (i < css.length && css[i] !== '{') {\n i++;\n }\n \n if (i < css.length) {\n // Found opening brace, now find matching closing brace\n depth = 1;\n i++; // Skip '{'\n \n while (i < css.length && depth > 0) {\n if (css[i] === '{') depth++;\n else if (css[i] === '}') depth--;\n i++;\n }\n \n // Copy entire @rule as-is\n result += css.substring(atRuleStart, i);\n }\n continue;\n }\n \n if (char === '{' && !inRule) {\n // Start of a rule block - scope the selector we just collected\n const selectorText = selectorBuffer.trim();\n \n if (selectorText) {\n // Split selectors by comma and scope each one\n const scopedSelectors = selectorText\n .split(',')\n .map(sel => {\n const trimmed = sel.trim();\n return trimmed ? `${scopeSelector} ${trimmed}` : trimmed;\n })\n .join(', ');\n \n result += scopedSelectors;\n }\n result += ' {';\n inRule = true;\n depth = 1;\n selectorBuffer = '';\n } else if (char === '{' && inRule) {\n // Nested brace\n result += char;\n depth++;\n } else if (char === '}' && inRule) {\n result += char;\n depth--;\n if (depth === 0) {\n inRule = false;\n }\n } else if (!inRule) {\n // Collecting selector\n selectorBuffer += char;\n } else {\n // Inside rule block\n result += char;\n if (char === '{') depth++;\n }\n \n i++;\n }\n \n // Add any remaining selector (shouldn't happen in valid CSS, but handle it)\n if (selectorBuffer.trim()) {\n const scopedSelectors = selectorBuffer.trim()\n .split(',')\n .map(sel => {\n const trimmed = sel.trim();\n return trimmed ? `${scopeSelector} ${trimmed}` : trimmed;\n })\n .join(', ');\n result += scopedSelectors;\n }\n \n return result;\n}\n\nfunction splitCallArguments(argsText: string): string[] {\n const args: string[] = [];\n let current = \"\";\n let depth = 0;\n let inSingle = false;\n let inDouble = false;\n let inTemplate = false;\n let escaped = false;\n\n for (let i = 0; i < argsText.length; i++) {\n const char = argsText[i];\n\n if (escaped) {\n current += char;\n escaped = false;\n continue;\n }\n\n if (char === \"\\\\\") {\n current += char;\n escaped = true;\n continue;\n }\n\n if (inSingle) {\n current += char;\n if (char === \"'\") inSingle = false;\n continue;\n }\n\n if (inDouble) {\n current += char;\n if (char === '\"') inDouble = false;\n continue;\n }\n\n if (inTemplate) {\n current += char;\n if (char === \"`\") inTemplate = false;\n continue;\n }\n\n if (char === \"'\") {\n inSingle = true;\n current += char;\n continue;\n }\n\n if (char === '\"') {\n inDouble = true;\n current += char;\n continue;\n }\n\n if (char === \"`\") {\n inTemplate = true;\n current += char;\n continue;\n }\n\n if (char === \"(\" || char === \"{\" || char === \"[\") {\n depth++;\n current += char;\n continue;\n }\n\n if (char === \")\" || char === \"}\" || char === \"]\") {\n depth--;\n current += char;\n continue;\n }\n\n if (char === \",\" && depth === 0) {\n args.push(current.trim());\n current = \"\";\n continue;\n }\n\n current += char;\n }\n\n if (current.trim()) {\n args.push(current.trim());\n }\n\n return args;\n}\n\nfunction addScopeClassToDOMContainer(parsedTemplate: string, scopeClass: string): string {\n let result = \"\";\n let cursor = 0;\n\n while (cursor < parsedTemplate.length) {\n const start = parsedTemplate.indexOf(\"h(DOMContainer\", cursor);\n if (start === -1) {\n result += parsedTemplate.slice(cursor);\n break;\n }\n\n result += parsedTemplate.slice(cursor, start);\n const openParen = parsedTemplate.indexOf(\"(\", start);\n if (openParen === -1) {\n result += parsedTemplate.slice(start);\n break;\n }\n\n let depth = 0;\n let inSingle = false;\n let inDouble = false;\n let inTemplate = false;\n let escaped = false;\n let end = -1;\n\n for (let i = openParen; i < parsedTemplate.length; i++) {\n const char = parsedTemplate[i];\n\n if (escaped) {\n escaped = false;\n continue;\n }\n\n if (char === \"\\\\\") {\n escaped = true;\n continue;\n }\n\n if (inSingle) {\n if (char === \"'\") inSingle = false;\n continue;\n }\n\n if (inDouble) {\n if (char === '\"') inDouble = false;\n continue;\n }\n\n if (inTemplate) {\n if (char === \"`\") inTemplate = false;\n continue;\n }\n\n if (char === \"'\") {\n inSingle = true;\n continue;\n }\n\n if (char === '\"') {\n inDouble = true;\n continue;\n }\n\n if (char === \"`\") {\n inTemplate = true;\n continue;\n }\n\n if (char === \"(\") depth++;\n if (char === \")\") depth--;\n\n if (depth === 0) {\n end = i + 1;\n break;\n }\n }\n\n if (end === -1) {\n result += parsedTemplate.slice(start);\n break;\n }\n\n const callText = parsedTemplate.slice(start, end);\n const argsText = parsedTemplate.slice(openParen + 1, end - 1);\n const args = splitCallArguments(argsText);\n\n if (args[0]?.trim() !== \"DOMContainer\") {\n result += callText;\n cursor = end;\n continue;\n }\n\n if (args.length === 1) {\n args.push(`{ _scopeClass: '${scopeClass}' }`);\n } else {\n const props = args[1].trim();\n if (props === \"null\" || props === \"undefined\") {\n args[1] = `{ _scopeClass: '${scopeClass}' }`;\n } else if (props.startsWith(\"{\")) {\n args[1] = props.replace(/^\\{\\s*/, `{ _scopeClass: '${scopeClass}', `);\n } else {\n args[1] = `{ _scopeClass: '${scopeClass}', ...${props} }`;\n }\n }\n\n result += `h(${args.join(\", \")})`;\n cursor = end;\n }\n\n return result;\n}\n\n/**\n * Vite plugin to load shader files (.frag, .vert, .wgsl) as text strings\n * \n * This plugin allows importing shader files directly as string literals in your code.\n * It supports fragment shaders (.frag), vertex shaders (.vert), and WebGPU shaders (.wgsl).\n * The content is loaded as a raw string and can be used directly with graphics APIs.\n * \n * @returns {object} - Vite plugin configuration object\n * \n * @example\n * ```typescript\n * // In your vite.config.ts\n * import { shaderLoader } from './path/to/compiler'\n * \n * export default defineConfig({\n * plugins: [shaderLoader()]\n * })\n * \n * // In your code\n * import fragmentShader from './shader.frag'\n * import vertexShader from './shader.vert'\n * import computeShader from './shader.wgsl'\n * \n * console.log(fragmentShader) // Raw shader code as string\n * ```\n */\nexport function shaderLoader() {\n const filter = createFilter(/\\.(frag|vert|wgsl)$/);\n\n return {\n name: \"vite-plugin-shader-loader\",\n transform(code: string, id: string) {\n if (!filter(id)) return;\n\n // Escape the shader code to be safely embedded in a JavaScript string\n const escapedCode = code\n .replace(/\\\\/g, '\\\\\\\\') // Escape backslashes\n .replace(/`/g, '\\\\`') // Escape backticks\n .replace(/\\$/g, '\\\\$'); // Escape dollar signs\n\n // Return the shader content as a default export string\n return {\n code: `export default \\`${escapedCode}\\`;`,\n map: null,\n };\n },\n };\n}\n\nexport default function canvasengine() {\n const filter = createFilter(\"**/*.ce\");\n const useLegacyGrammar = process.env.CANVASENGINE_COMPILER_V1 === \"1\";\n\n // Convert import.meta.url to a file path\n const __filename = fileURLToPath(import.meta.url);\n const __dirname = path.dirname(__filename);\n\n const grammarFile = useLegacyGrammar ? \"grammar.pegjs\" : \"grammar2.pegjs\";\n const grammar = fs.readFileSync(\n path.join(__dirname, grammarFile),\n \"utf8\"\n );\n const parser = generate(grammar);\n const isDev = process.env.NODE_ENV === \"dev\";\n const FLAG_COMMENT = \"/*--[TPL]--*/\";\n let warnedAboutGrammar = false;\n\n const PRIMITIVE_COMPONENTS = [\n \"Canvas\",\n \"Sprite\",\n \"Text\",\n \"Viewport\",\n \"Graphics\",\n \"Container\",\n \"Navigation\",\n \"ImageMap\",\n \"NineSliceSprite\",\n \"Rect\",\n \"Circle\",\n \"Ellipse\",\n \"Triangle\",\n \"TilingSprite\",\n \"svg\",\n \"Video\",\n \"Mesh\",\n \"Svg\",\n \"DOMContainer\",\n \"DOMElement\",\n \"DOMSprite\",\n \"Button\",\n \"Joystick\"\n ];\n\n return {\n name: \"vite-plugin-ce\",\n transform(code: string, id: string) {\n if (!filter(id)) return null;\n if (!warnedAboutGrammar) {\n warnedAboutGrammar = true;\n const legacyNote = \"Set CANVASENGINE_COMPILER_V1=1 to compile with the legacy grammar (v1).\";\n if (useLegacyGrammar) {\n console.warn(`[canvasengine] Using legacy grammar v1. ${legacyNote}`);\n } else {\n console.warn(`[canvasengine] Breaking change: compiler grammar v2 is now the default. ${legacyNote}`);\n }\n }\n\n // Extract the script content\n const scriptMatch = code.match(/<script>([\\s\\S]*?)<\\/script>/);\n let scriptContent = scriptMatch ? scriptMatch[1].trim() : \"\";\n \n // Extract the style tag with attributes and content\n const styleTagMatch = code.match(/<style([^>]*)>([\\s\\S]*?)<\\/style>/);\n let styleContent = \"\";\n let isScoped = false;\n \n if (styleTagMatch) {\n const styleAttributes = styleTagMatch[1].trim();\n styleContent = styleTagMatch[2].trim();\n \n // Check if scoped attribute is present\n isScoped = /scoped(?:\\s|>|$)/.test(styleAttributes);\n }\n \n // Remove script and style tags from template before parsing\n let template = code\n .replace(/<script>[\\s\\S]*?<\\/script>/, \"\")\n .replace(/<style[^>]*>[\\s\\S]*?<\\/style>/, \"\")\n .replace(/^\\s+|\\s+$/g, '');\n\n let parsedTemplate;\n try {\n parsedTemplate = parser.parse(template);\n } catch (error) {\n const errorMsg = showErrorMessage(template, error);\n throw new Error(`Error parsing template in file ${id}:\\n${errorMsg}`);\n }\n\n // trick to avoid typescript remove imports in scriptContent\n scriptContent += FLAG_COMMENT + parsedTemplate\n\n let transpiledCode = ts.transpileModule(scriptContent, {\n compilerOptions: {\n module: ts.ModuleKind.Preserve,\n },\n }).outputText;\n\n // remove code after /*---*/\n transpiledCode = transpiledCode.split(FLAG_COMMENT)[0]\n\n // Use Acorn to parse the script content\n const parsed = parse(transpiledCode, {\n sourceType: \"module\",\n ecmaVersion: 2020,\n });\n\n // Extract imports\n const imports = parsed.body.filter(\n (node) => node.type === \"ImportDeclaration\"\n );\n\n // Extract non-import statements from scriptContent\n const nonImportCode = parsed.body\n .filter((node) => node.type !== \"ImportDeclaration\")\n .map((node) => transpiledCode.slice(node.start, node.end))\n .join(\"\\n\");\n\n let importsCode = imports\n .map((imp) => {\n let importCode = transpiledCode.slice(imp.start, imp.end);\n if (isDev && importCode.includes(\"from 'canvasengine'\")) {\n importCode = importCode.replace(\n \"from 'canvasengine'\",\n `from '${DEV_SRC}'`\n );\n }\n return importCode;\n })\n .join(\"\\n\");\n\n // Define an array for required imports\n const requiredImports = [\"h\", \"computed\", \"cond\", \"loop\"];\n\n // Check for missing imports\n const missingImports = requiredImports.filter(\n (importName) =>\n !imports.some(\n (imp) =>\n imp.specifiers &&\n imp.specifiers.some(\n (spec) =>\n spec.type === \"ImportSpecifier\" &&\n spec.imported && \n 'name' in spec.imported &&\n spec.imported.name === importName\n )\n )\n );\n\n // Add missing imports\n if (missingImports.length > 0) {\n const additionalImportCode = `import { ${missingImports.join(\n \", \"\n )} } from ${isDev ? `'${DEV_SRC}'` : \"'canvasengine'\"};`;\n importsCode = `${additionalImportCode}\\n${importsCode}`;\n }\n\n // Check for primitive components in parsedTemplate\n const primitiveImports = PRIMITIVE_COMPONENTS.filter((component) =>\n parsedTemplate.includes(`h(${component}`)\n );\n\n // Add missing imports for primitive components\n primitiveImports.forEach((component) => {\n const importStatement = `import { ${component} } from ${\n isDev ? `'${DEV_SRC}'` : \"'canvasengine'\"\n };`;\n if (!importsCode.includes(importStatement)) {\n importsCode = `${importStatement}\\n${importsCode}`;\n }\n });\n\n // Process CSS: scope it if scoped attribute is present\n let processedStyleContent = styleContent;\n let scopeClass = '';\n \n if (isScoped && styleContent) {\n // Generate short hash (8 characters) based on file path\n const fileHash = generateHash(id);\n scopeClass = fileHash;\n processedStyleContent = scopeCSS(styleContent, scopeClass);\n \n // Add _scopeClass prop to all DOMContainer in the template\n parsedTemplate = addScopeClassToDOMContainer(parsedTemplate, scopeClass);\n }\n \n // Escape style content for safe embedding in JavaScript string (using single quotes)\n // We need to escape: backslashes, single quotes, and line breaks\n const escapedStyleContent = processedStyleContent\n .replace(/\\\\/g, '\\\\\\\\') // Escape backslashes first\n .replace(/'/g, \"\\\\'\") // Escape single quotes\n .replace(/\\n/g, '\\\\n') // Escape newlines\n .replace(/\\r/g, '\\\\r'); // Escape carriage returns\n\n // Generate unique ID for style element based on file path\n const styleId = `ce-style-${id.replace(/[^a-zA-Z0-9]/g, '-')}`;\n\n // Generate CSS injection code if style content exists\n // Use single quotes to avoid escaping issues with backticks\n const styleInjectionCode = styleContent ? \n '// Inject CSS styles into the document head\\n' +\n `if (typeof document !== 'undefined' && !document.getElementById('${styleId}')) {\\n` +\n ' const styleElement = document.createElement(\\'style\\');\\n' +\n ` styleElement.id = '${styleId}';\\n` +\n ` styleElement.textContent = '${escapedStyleContent}';\\n` +\n ' document.head.appendChild(styleElement);\\n' +\n '}\\n'\n : '';\n \n\n // Generate the output\n const output = String.raw`\n ${importsCode}\n import { useProps, useDefineProps } from ${isDev ? `'${DEV_SRC}'` : \"'canvasengine'\"}\n ${styleInjectionCode}\n export default function component($$props) {\n const $props = useProps($$props)\n const defineProps = useDefineProps($$props)\n ${nonImportCode}\n let $this = ${parsedTemplate}\n return $this\n }\n `;\n\n return {\n code: output,\n map: null,\n };\n },\n };\n}\n"],"mappings":";AAAA,SAAS,oBAAoB;AAC7B,SAAS,aAAa;AACtB,OAAO,QAAQ;AACf,OAAO,SAAS;AAChB,OAAO,UAAU;AACjB,YAAY,QAAQ;AACpB,SAAS,qBAAqB;AAE9B,IAAM,EAAE,SAAS,IAAI;AAErB,IAAM,UAAU;AAQhB,SAAS,aAAa,KAAqB;AACzC,MAAI,OAAO;AACX,WAAS,IAAI,GAAG,IAAI,IAAI,QAAQ,KAAK;AACnC,UAAM,OAAO,IAAI,WAAW,CAAC;AAC7B,YAAS,QAAQ,KAAK,OAAQ;AAC9B,WAAO,OAAO;AAAA,EAChB;AAGA,QAAM,eAAe,KAAK,IAAI,IAAI;AAClC,MAAI,SAAS;AACb,WAAS,IAAI,GAAG,IAAI,GAAG,KAAK;AAC1B,UAAM,eAAe,eAAe,IAAI,MAAM;AAC9C,cAAU,OAAO,aAAa,KAAK,WAAW;AAAA,EAChD;AACA,SAAO;AACT;AAeA,SAAS,iBAAiB,UAAkB,OAAoB;AAC9D,MAAI,CAAC,MAAM,UAAU;AACnB,WAAO,iBAAiB,MAAM,OAAO;AAAA,EACvC;AAEA,QAAM,QAAQ,SAAS,MAAM,IAAI;AACjC,QAAM,EAAE,MAAM,OAAO,IAAI,MAAM,SAAS;AACxC,QAAM,YAAY,MAAM,OAAO,CAAC,KAAK;AAGrC,QAAM,UAAU,IAAI,OAAO,SAAS,CAAC,IAAI;AAEzC,SAAO,wBAAwB,IAAI,YAAY,MAAM,KAAK,MAAM,OAAO;AAAA;AAAA,EAC7D,SAAS;AAAA,EAAK,OAAO;AAAA;AACjC;AAkBA,SAAS,SAAS,KAAa,YAA4B;AACzD,QAAM,gBAAgB,IAAI,UAAU;AAGpC,MAAI,SAAS;AACb,MAAI,IAAI;AACR,MAAI,QAAQ;AACZ,MAAI,SAAS;AACb,MAAI,iBAAiB;AAErB,SAAO,IAAI,IAAI,QAAQ;AACrB,UAAM,OAAO,IAAI,CAAC;AAElB,QAAI,SAAS,OAAO,CAAC,UAAU,mBAAmB,IAAI;AAEpD,YAAM,cAAc;AACpB;AAGA,aAAO,IAAI,IAAI,UAAU,IAAI,CAAC,MAAM,KAAK;AACvC;AAAA,MACF;AAEA,UAAI,IAAI,IAAI,QAAQ;AAElB,gBAAQ;AACR;AAEA,eAAO,IAAI,IAAI,UAAU,QAAQ,GAAG;AAClC,cAAI,IAAI,CAAC,MAAM,IAAK;AAAA,mBACX,IAAI,CAAC,MAAM,IAAK;AACzB;AAAA,QACF;AAGA,kBAAU,IAAI,UAAU,aAAa,CAAC;AAAA,MACxC;AACA;AAAA,IACF;AAEA,QAAI,SAAS,OAAO,CAAC,QAAQ;AAE3B,YAAM,eAAe,eAAe,KAAK;AAEzC,UAAI,cAAc;AAEhB,cAAM,kBAAkB,aACrB,MAAM,GAAG,EACT,IAAI,SAAO;AACV,gBAAM,UAAU,IAAI,KAAK;AACzB,iBAAO,UAAU,GAAG,aAAa,IAAI,OAAO,KAAK;AAAA,QACnD,CAAC,EACA,KAAK,IAAI;AAEZ,kBAAU;AAAA,MACZ;AACA,gBAAU;AACV,eAAS;AACT,cAAQ;AACR,uBAAiB;AAAA,IACnB,WAAW,SAAS,OAAO,QAAQ;AAEjC,gBAAU;AACV;AAAA,IACF,WAAW,SAAS,OAAO,QAAQ;AACjC,gBAAU;AACV;AACA,UAAI,UAAU,GAAG;AACf,iBAAS;AAAA,MACX;AAAA,IACF,WAAW,CAAC,QAAQ;AAElB,wBAAkB;AAAA,IACpB,OAAO;AAEL,gBAAU;AACV,UAAI,SAAS,IAAK;AAAA,IACpB;AAEA;AAAA,EACF;AAGA,MAAI,eAAe,KAAK,GAAG;AACzB,UAAM,kBAAkB,eAAe,KAAK,EACzC,MAAM,GAAG,EACT,IAAI,SAAO;AACV,YAAM,UAAU,IAAI,KAAK;AACzB,aAAO,UAAU,GAAG,aAAa,IAAI,OAAO,KAAK;AAAA,IACnD,CAAC,EACA,KAAK,IAAI;AACZ,cAAU;AAAA,EACZ;AAEA,SAAO;AACT;AAEA,SAAS,mBAAmB,UAA4B;AACtD,QAAM,OAAiB,CAAC;AACxB,MAAI,UAAU;AACd,MAAI,QAAQ;AACZ,MAAI,WAAW;AACf,MAAI,WAAW;AACf,MAAI,aAAa;AACjB,MAAI,UAAU;AAEd,WAAS,IAAI,GAAG,IAAI,SAAS,QAAQ,KAAK;AACxC,UAAM,OAAO,SAAS,CAAC;AAEvB,QAAI,SAAS;AACX,iBAAW;AACX,gBAAU;AACV;AAAA,IACF;AAEA,QAAI,SAAS,MAAM;AACjB,iBAAW;AACX,gBAAU;AACV;AAAA,IACF;AAEA,QAAI,UAAU;AACZ,iBAAW;AACX,UAAI,SAAS,IAAK,YAAW;AAC7B;AAAA,IACF;AAEA,QAAI,UAAU;AACZ,iBAAW;AACX,UAAI,SAAS,IAAK,YAAW;AAC7B;AAAA,IACF;AAEA,QAAI,YAAY;AACd,iBAAW;AACX,UAAI,SAAS,IAAK,cAAa;AAC/B;AAAA,IACF;AAEA,QAAI,SAAS,KAAK;AAChB,iBAAW;AACX,iBAAW;AACX;AAAA,IACF;AAEA,QAAI,SAAS,KAAK;AAChB,iBAAW;AACX,iBAAW;AACX;AAAA,IACF;AAEA,QAAI,SAAS,KAAK;AAChB,mBAAa;AACb,iBAAW;AACX;AAAA,IACF;AAEA,QAAI,SAAS,OAAO,SAAS,OAAO,SAAS,KAAK;AAChD;AACA,iBAAW;AACX;AAAA,IACF;AAEA,QAAI,SAAS,OAAO,SAAS,OAAO,SAAS,KAAK;AAChD;AACA,iBAAW;AACX;AAAA,IACF;AAEA,QAAI,SAAS,OAAO,UAAU,GAAG;AAC/B,WAAK,KAAK,QAAQ,KAAK,CAAC;AACxB,gBAAU;AACV;AAAA,IACF;AAEA,eAAW;AAAA,EACb;AAEA,MAAI,QAAQ,KAAK,GAAG;AAClB,SAAK,KAAK,QAAQ,KAAK,CAAC;AAAA,EAC1B;AAEA,SAAO;AACT;AAEA,SAAS,4BAA4B,gBAAwB,YAA4B;AACvF,MAAI,SAAS;AACb,MAAI,SAAS;AAEb,SAAO,SAAS,eAAe,QAAQ;AACrC,UAAM,QAAQ,eAAe,QAAQ,kBAAkB,MAAM;AAC7D,QAAI,UAAU,IAAI;AAChB,gBAAU,eAAe,MAAM,MAAM;AACrC;AAAA,IACF;AAEA,cAAU,eAAe,MAAM,QAAQ,KAAK;AAC5C,UAAM,YAAY,eAAe,QAAQ,KAAK,KAAK;AACnD,QAAI,cAAc,IAAI;AACpB,gBAAU,eAAe,MAAM,KAAK;AACpC;AAAA,IACF;AAEA,QAAI,QAAQ;AACZ,QAAI,WAAW;AACf,QAAI,WAAW;AACf,QAAI,aAAa;AACjB,QAAI,UAAU;AACd,QAAI,MAAM;AAEV,aAAS,IAAI,WAAW,IAAI,eAAe,QAAQ,KAAK;AACtD,YAAM,OAAO,eAAe,CAAC;AAE7B,UAAI,SAAS;AACX,kBAAU;AACV;AAAA,MACF;AAEA,UAAI,SAAS,MAAM;AACjB,kBAAU;AACV;AAAA,MACF;AAEA,UAAI,UAAU;AACZ,YAAI,SAAS,IAAK,YAAW;AAC7B;AAAA,MACF;AAEA,UAAI,UAAU;AACZ,YAAI,SAAS,IAAK,YAAW;AAC7B;AAAA,MACF;AAEA,UAAI,YAAY;AACd,YAAI,SAAS,IAAK,cAAa;AAC/B;AAAA,MACF;AAEA,UAAI,SAAS,KAAK;AAChB,mBAAW;AACX;AAAA,MACF;AAEA,UAAI,SAAS,KAAK;AAChB,mBAAW;AACX;AAAA,MACF;AAEA,UAAI,SAAS,KAAK;AAChB,qBAAa;AACb;AAAA,MACF;AAEA,UAAI,SAAS,IAAK;AAClB,UAAI,SAAS,IAAK;AAElB,UAAI,UAAU,GAAG;AACf,cAAM,IAAI;AACV;AAAA,MACF;AAAA,IACF;AAEA,QAAI,QAAQ,IAAI;AACd,gBAAU,eAAe,MAAM,KAAK;AACpC;AAAA,IACF;AAEA,UAAM,WAAW,eAAe,MAAM,OAAO,GAAG;AAChD,UAAM,WAAW,eAAe,MAAM,YAAY,GAAG,MAAM,CAAC;AAC5D,UAAM,OAAO,mBAAmB,QAAQ;AAExC,QAAI,KAAK,CAAC,GAAG,KAAK,MAAM,gBAAgB;AACtC,gBAAU;AACV,eAAS;AACT;AAAA,IACF;AAEA,QAAI,KAAK,WAAW,GAAG;AACrB,WAAK,KAAK,mBAAmB,UAAU,KAAK;AAAA,IAC9C,OAAO;AACL,YAAM,QAAQ,KAAK,CAAC,EAAE,KAAK;AAC3B,UAAI,UAAU,UAAU,UAAU,aAAa;AAC7C,aAAK,CAAC,IAAI,mBAAmB,UAAU;AAAA,MACzC,WAAW,MAAM,WAAW,GAAG,GAAG;AAChC,aAAK,CAAC,IAAI,MAAM,QAAQ,UAAU,mBAAmB,UAAU,KAAK;AAAA,MACtE,OAAO;AACL,aAAK,CAAC,IAAI,mBAAmB,UAAU,SAAS,KAAK;AAAA,MACvD;AAAA,IACF;AAEA,cAAU,KAAK,KAAK,KAAK,IAAI,CAAC;AAC9B,aAAS;AAAA,EACX;AAEA,SAAO;AACT;AA4BO,SAAS,eAAe;AAC7B,QAAM,SAAS,aAAa,qBAAqB;AAEjD,SAAO;AAAA,IACL,MAAM;AAAA,IACN,UAAU,MAAc,IAAY;AAClC,UAAI,CAAC,OAAO,EAAE,EAAG;AAGjB,YAAM,cAAc,KACjB,QAAQ,OAAO,MAAM,EACrB,QAAQ,MAAM,KAAK,EACnB,QAAQ,OAAO,KAAK;AAGvB,aAAO;AAAA,QACL,MAAM,oBAAoB,WAAW;AAAA,QACrC,KAAK;AAAA,MACP;AAAA,IACF;AAAA,EACF;AACF;AAEe,SAAR,eAAgC;AACrC,QAAM,SAAS,aAAa,SAAS;AACrC,QAAM,mBAAmB,QAAQ,IAAI,6BAA6B;AAGlE,QAAM,aAAa,cAAc,YAAY,GAAG;AAChD,QAAM,YAAY,KAAK,QAAQ,UAAU;AAEzC,QAAM,cAAc,mBAAmB,kBAAkB;AACzD,QAAM,UAAU,GAAG;AAAA,IACjB,KAAK,KAAK,WAAW,WAAW;AAAA,IAChC;AAAA,EACF;AACA,QAAM,SAAS,SAAS,OAAO;AAC/B,QAAM,QAAQ,QAAQ,IAAI,aAAa;AACvC,QAAM,eAAe;AACrB,MAAI,qBAAqB;AAEzB,QAAM,uBAAuB;AAAA,IAC3B;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAEA,SAAO;AAAA,IACL,MAAM;AAAA,IACN,UAAU,MAAc,IAAY;AAClC,UAAI,CAAC,OAAO,EAAE,EAAG,QAAO;AACxB,UAAI,CAAC,oBAAoB;AACvB,6BAAqB;AACrB,cAAM,aAAa;AACnB,YAAI,kBAAkB;AACpB,kBAAQ,KAAK,2CAA2C,UAAU,EAAE;AAAA,QACtE,OAAO;AACL,kBAAQ,KAAK,2EAA2E,UAAU,EAAE;AAAA,QACtG;AAAA,MACF;AAGA,YAAM,cAAc,KAAK,MAAM,8BAA8B;AAC7D,UAAI,gBAAgB,cAAc,YAAY,CAAC,EAAE,KAAK,IAAI;AAG1D,YAAM,gBAAgB,KAAK,MAAM,mCAAmC;AACpE,UAAI,eAAe;AACnB,UAAI,WAAW;AAEf,UAAI,eAAe;AACjB,cAAM,kBAAkB,cAAc,CAAC,EAAE,KAAK;AAC9C,uBAAe,cAAc,CAAC,EAAE,KAAK;AAGrC,mBAAW,mBAAmB,KAAK,eAAe;AAAA,MACpD;AAGA,UAAI,WAAW,KACZ,QAAQ,8BAA8B,EAAE,EACxC,QAAQ,iCAAiC,EAAE,EAC3C,QAAQ,cAAc,EAAE;AAE3B,UAAI;AACJ,UAAI;AACF,yBAAiB,OAAO,MAAM,QAAQ;AAAA,MACxC,SAAS,OAAO;AACd,cAAM,WAAW,iBAAiB,UAAU,KAAK;AACjD,cAAM,IAAI,MAAM,kCAAkC,EAAE;AAAA,EAAM,QAAQ,EAAE;AAAA,MACtE;AAGA,uBAAiB,eAAe;AAEhC,UAAI,iBAAoB,mBAAgB,eAAe;AAAA,QACrD,iBAAiB;AAAA,UACf,QAAW,cAAW;AAAA,QACxB;AAAA,MACF,CAAC,EAAE;AAGH,uBAAiB,eAAe,MAAM,YAAY,EAAE,CAAC;AAGrD,YAAM,SAAS,MAAM,gBAAgB;AAAA,QACnC,YAAY;AAAA,QACZ,aAAa;AAAA,MACf,CAAC;AAGD,YAAM,UAAU,OAAO,KAAK;AAAA,QAC1B,CAAC,SAAS,KAAK,SAAS;AAAA,MAC1B;AAGA,YAAM,gBAAgB,OAAO,KAC1B,OAAO,CAAC,SAAS,KAAK,SAAS,mBAAmB,EAClD,IAAI,CAAC,SAAS,eAAe,MAAM,KAAK,OAAO,KAAK,GAAG,CAAC,EACxD,KAAK,IAAI;AAEZ,UAAI,cAAc,QACf,IAAI,CAAC,QAAQ;AACZ,YAAI,aAAa,eAAe,MAAM,IAAI,OAAO,IAAI,GAAG;AACxD,YAAI,SAAS,WAAW,SAAS,qBAAqB,GAAG;AACvD,uBAAa,WAAW;AAAA,YACtB;AAAA,YACA,SAAS,OAAO;AAAA,UAClB;AAAA,QACF;AACA,eAAO;AAAA,MACT,CAAC,EACA,KAAK,IAAI;AAGZ,YAAM,kBAAkB,CAAC,KAAK,YAAY,QAAQ,MAAM;AAGxD,YAAM,iBAAiB,gBAAgB;AAAA,QACrC,CAAC,eACC,CAAC,QAAQ;AAAA,UACP,CAAC,QACC,IAAI,cACJ,IAAI,WAAW;AAAA,YACb,CAAC,SACC,KAAK,SAAS,qBACd,KAAK,YACL,UAAU,KAAK,YACf,KAAK,SAAS,SAAS;AAAA,UAC3B;AAAA,QACJ;AAAA,MACJ;AAGA,UAAI,eAAe,SAAS,GAAG;AAC7B,cAAM,uBAAuB,YAAY,eAAe;AAAA,UACtD;AAAA,QACF,CAAC,WAAW,QAAQ,IAAI,OAAO,MAAM,gBAAgB;AACrD,sBAAc,GAAG,oBAAoB;AAAA,EAAK,WAAW;AAAA,MACvD;AAGA,YAAM,mBAAmB,qBAAqB;AAAA,QAAO,CAAC,cACpD,eAAe,SAAS,KAAK,SAAS,EAAE;AAAA,MAC1C;AAGA,uBAAiB,QAAQ,CAAC,cAAc;AACtC,cAAM,kBAAkB,YAAY,SAAS,WAC3C,QAAQ,IAAI,OAAO,MAAM,gBAC3B;AACA,YAAI,CAAC,YAAY,SAAS,eAAe,GAAG;AAC1C,wBAAc,GAAG,eAAe;AAAA,EAAK,WAAW;AAAA,QAClD;AAAA,MACF,CAAC;AAGD,UAAI,wBAAwB;AAC5B,UAAI,aAAa;AAEjB,UAAI,YAAY,cAAc;AAE5B,cAAM,WAAW,aAAa,EAAE;AAChC,qBAAa;AACb,gCAAwB,SAAS,cAAc,UAAU;AAGzD,yBAAiB,4BAA4B,gBAAgB,UAAU;AAAA,MACzE;AAIA,YAAM,sBAAsB,sBACzB,QAAQ,OAAO,MAAM,EACrB,QAAQ,MAAM,KAAK,EACnB,QAAQ,OAAO,KAAK,EACpB,QAAQ,OAAO,KAAK;AAGvB,YAAM,UAAU,YAAY,GAAG,QAAQ,iBAAiB,GAAG,CAAC;AAI5D,YAAM,qBAAqB,eACzB;AAAA,mEACoE,OAAO;AAAA;AAAA,uBAEnD,OAAO;AAAA,gCACE,mBAAmB;AAAA;AAAA;AAAA,IAGlD;AAIJ,YAAM,SAAS,OAAO;AAAA,QACpB,WAAW;AAAA,iDAC8B,QAAQ,IAAI,OAAO,MAAM,gBAAgB;AAAA,QAClF,kBAAkB;AAAA;AAAA;AAAA;AAAA,UAIhB,aAAa;AAAA,sBACD,cAAc;AAAA;AAAA;AAAA;AAK9B,aAAO;AAAA,QACL,MAAM;AAAA,QACN,KAAK;AAAA,MACP;AAAA,IACF;AAAA,EACF;AACF;","names":[]}
|
package/package.json
CHANGED
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@canvasengine/compiler",
|
|
3
|
-
"version": "2.0.0-beta.
|
|
3
|
+
"version": "2.0.0-beta.50",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
7
|
+
"files": [
|
|
8
|
+
"dist"
|
|
9
|
+
],
|
|
7
10
|
"scripts": {
|
|
8
|
-
"build": "tsup",
|
|
11
|
+
"build": "tsup && cp grammar2.pegjs ../../docs/public/grammar.pegjs",
|
|
9
12
|
"dev": "tsup --watch"
|
|
10
13
|
},
|
|
11
14
|
"type": "module",
|