@canvasengine/compiler 2.0.0-beta.2 → 2.0.0-beta.20

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,42 @@
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(): {
28
+ name: string;
29
+ transform(code: string, id: string): {
30
+ code: string;
31
+ map: null;
32
+ } | undefined;
33
+ };
34
+ declare function canvasengine(): {
35
+ name: string;
36
+ transform(code: string, id: string): {
37
+ code: string;
38
+ map: null;
39
+ } | undefined;
40
+ };
41
+
42
+ export { canvasengine as default, shaderLoader };
package/dist/index.js ADDED
@@ -0,0 +1,158 @@
1
+ // index.ts
2
+ import { createFilter } from "vite";
3
+ import { parse } from "acorn";
4
+ import fs from "fs";
5
+ import pkg from "peggy";
6
+ import path from "path";
7
+ import * as ts from "typescript";
8
+ import { fileURLToPath } from "url";
9
+ var { generate } = pkg;
10
+ var DEV_SRC = "../../src";
11
+ function showErrorMessage(template, error) {
12
+ if (!error.location) {
13
+ return `Syntax error: ${error.message}`;
14
+ }
15
+ const lines = template.split("\n");
16
+ const { line, column } = error.location.start;
17
+ const errorLine = lines[line - 1] || "";
18
+ const pointer = " ".repeat(column - 1) + "^";
19
+ return `Syntax error at line ${line}, column ${column}: ${error.message}
20
+
21
+ ${errorLine}
22
+ ${pointer}
23
+ `;
24
+ }
25
+ function shaderLoader() {
26
+ const filter = createFilter(/\.(frag|vert|wgsl)$/);
27
+ return {
28
+ name: "vite-plugin-shader-loader",
29
+ transform(code, id) {
30
+ if (!filter(id)) return;
31
+ const escapedCode = code.replace(/\\/g, "\\\\").replace(/`/g, "\\`").replace(/\$/g, "\\$");
32
+ return {
33
+ code: `export default \`${escapedCode}\`;`,
34
+ map: null
35
+ };
36
+ }
37
+ };
38
+ }
39
+ function canvasengine() {
40
+ const filter = createFilter("**/*.ce");
41
+ const __filename = fileURLToPath(import.meta.url);
42
+ const __dirname = path.dirname(__filename);
43
+ const grammar = fs.readFileSync(
44
+ path.join(__dirname, "grammar.pegjs").replace("dist/grammar.pegjs", "grammar.pegjs"),
45
+ "utf8"
46
+ );
47
+ const parser = generate(grammar);
48
+ const isDev = process.env.NODE_ENV === "dev";
49
+ const FLAG_COMMENT = "/*--[TPL]--*/";
50
+ const PRIMITIVE_COMPONENTS = [
51
+ "Canvas",
52
+ "Sprite",
53
+ "Text",
54
+ "Viewport",
55
+ "Graphics",
56
+ "Container",
57
+ "ImageMap",
58
+ "NineSliceSprite",
59
+ "Rect",
60
+ "Circle",
61
+ "Ellipse",
62
+ "Triangle",
63
+ "TilingSprite",
64
+ "svg",
65
+ "Video",
66
+ "Mesh",
67
+ "Svg",
68
+ "DOMContainer"
69
+ ];
70
+ return {
71
+ name: "vite-plugin-ce",
72
+ transform(code, id) {
73
+ if (!filter(id)) return;
74
+ const scriptMatch = code.match(/<script>([\s\S]*?)<\/script>/);
75
+ let scriptContent = scriptMatch ? scriptMatch[1].trim() : "";
76
+ let template = code.replace(/<script>[\s\S]*?<\/script>/, "").replace(/^\s+|\s+$/g, "");
77
+ let parsedTemplate;
78
+ try {
79
+ parsedTemplate = parser.parse(template);
80
+ } catch (error) {
81
+ const errorMsg = showErrorMessage(template, error);
82
+ throw new Error(`Error parsing template in file ${id}:
83
+ ${errorMsg}`);
84
+ }
85
+ scriptContent += FLAG_COMMENT + parsedTemplate;
86
+ let transpiledCode = ts.transpileModule(scriptContent, {
87
+ compilerOptions: {
88
+ module: ts.ModuleKind.Preserve
89
+ }
90
+ }).outputText;
91
+ transpiledCode = transpiledCode.split(FLAG_COMMENT)[0];
92
+ const parsed = parse(transpiledCode, {
93
+ sourceType: "module",
94
+ ecmaVersion: 2020
95
+ });
96
+ const imports = parsed.body.filter(
97
+ (node) => node.type === "ImportDeclaration"
98
+ );
99
+ const nonImportCode = parsed.body.filter((node) => node.type !== "ImportDeclaration").map((node) => transpiledCode.slice(node.start, node.end)).join("\n");
100
+ let importsCode = imports.map((imp) => {
101
+ let importCode = transpiledCode.slice(imp.start, imp.end);
102
+ if (isDev && importCode.includes("from 'canvasengine'")) {
103
+ importCode = importCode.replace(
104
+ "from 'canvasengine'",
105
+ `from '${DEV_SRC}'`
106
+ );
107
+ }
108
+ return importCode;
109
+ }).join("\n");
110
+ const requiredImports = ["h", "computed", "cond", "loop"];
111
+ const missingImports = requiredImports.filter(
112
+ (importName) => !imports.some(
113
+ (imp) => imp.specifiers && imp.specifiers.some(
114
+ (spec) => spec.type === "ImportSpecifier" && spec.imported && "name" in spec.imported && spec.imported.name === importName
115
+ )
116
+ )
117
+ );
118
+ if (missingImports.length > 0) {
119
+ const additionalImportCode = `import { ${missingImports.join(
120
+ ", "
121
+ )} } from ${isDev ? `'${DEV_SRC}'` : "'canvasengine'"};`;
122
+ importsCode = `${additionalImportCode}
123
+ ${importsCode}`;
124
+ }
125
+ const primitiveImports = PRIMITIVE_COMPONENTS.filter(
126
+ (component) => parsedTemplate.includes(`h(${component}`)
127
+ );
128
+ primitiveImports.forEach((component) => {
129
+ const importStatement = `import { ${component} } from ${isDev ? `'${DEV_SRC}'` : "'canvasengine'"};`;
130
+ if (!importsCode.includes(importStatement)) {
131
+ importsCode = `${importStatement}
132
+ ${importsCode}`;
133
+ }
134
+ });
135
+ const output = String.raw`
136
+ ${importsCode}
137
+ import { useProps, useDefineProps } from ${isDev ? `'${DEV_SRC}'` : "'canvasengine'"}
138
+
139
+ export default function component($$props) {
140
+ const $props = useProps($$props)
141
+ const defineProps = useDefineProps($$props)
142
+ ${nonImportCode}
143
+ let $this = ${parsedTemplate}
144
+ return $this
145
+ }
146
+ `;
147
+ return {
148
+ code: output,
149
+ map: null
150
+ };
151
+ }
152
+ };
153
+ }
154
+ export {
155
+ canvasengine as default,
156
+ shaderLoader
157
+ };
158
+ //# sourceMappingURL=index.js.map
@@ -0,0 +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\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 * 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\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 \"Ellipse\",\n \"Triangle\",\n \"TilingSprite\",\n \"svg\",\n \"Video\",\n \"Mesh\",\n \"Svg\",\n \"DOMContainer\"\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 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 // 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":[]}