@canvasengine/compiler 2.0.0-beta.41 → 2.0.0-beta.43

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.
@@ -291,14 +291,14 @@ simpleDynamicPart "simple dynamic part"
291
291
  }
292
292
  / "{" _ expr:attributeValue _ "}" {
293
293
  // Handle single brace expressions like {item.name} or {@text}
294
- if (expr.trim().match(/^@?[a-zA-Z_][a-zA-Z0-9_.]*$/)) {
294
+ if (expr.trim().match(/^(@?[a-zA-Z_][a-zA-Z0-9_]*)(\.@?[a-zA-Z_][a-zA-Z0-9_]*)*$/)) {
295
295
  let foundSignal = false;
296
- const computedValue = expr.replace(/@?[a-zA-Z_][a-zA-Z0-9_]*(?!:)/g, (match) => {
296
+ const computedValue = expr.replace(/@?([a-zA-Z_][a-zA-Z0-9_]*)\b(?!\s*:)/g, (match, p1) => {
297
297
  if (match.startsWith('@')) {
298
- return match.substring(1);
298
+ return p1;
299
299
  }
300
300
  foundSignal = true;
301
- return `${match}()`;
301
+ return `${p1}()`;
302
302
  });
303
303
  if (foundSignal) {
304
304
  return `computed(() => ${computedValue})`;
@@ -743,24 +743,97 @@ dotFunctionChain
743
743
 
744
744
  condition "condition expression"
745
745
  = functionCall
746
+ / functionCallWithArgs
746
747
  / text_condition:$([^)]*) {
747
748
  const originalText = text_condition.trim();
748
749
 
750
+ // Handle expressions with @ literals (like @item.@id)
751
+ // First, process dot notation expressions with @ literals
752
+ let processedText = originalText;
753
+ const dotNotationReplacements = new Map();
754
+ let replacementCounter = 0;
755
+
756
+ // Process dot notation expressions like @item.@id, @item.id, item.@id
757
+ // Only process expressions that contain at least one @
758
+ processedText = processedText.replace(/(@[a-zA-Z_][a-zA-Z0-9_]*)(\.@?[a-zA-Z_][a-zA-Z0-9_]*)+|([a-zA-Z_][a-zA-Z0-9_]*)(\.@[a-zA-Z_][a-zA-Z0-9_]*)+/g, (match) => {
759
+ // Split by dots to handle each part separately
760
+ const parts = match.split('.');
761
+ const allLiterals = parts.every(part => part.trim().startsWith('@'));
762
+
763
+ let replacement;
764
+ if (allLiterals) {
765
+ // All parts are literals, just remove @ prefixes (no signal transformation)
766
+ replacement = parts.map(part => part.trim().replace('@', '')).join('.');
767
+ } else {
768
+ // Transform each part individually
769
+ // Note: In conditions with operators, even @ literals in the first part
770
+ // should be transformed to signals for comparison
771
+ replacement = parts.map((part, index) => {
772
+ const trimmedPart = part.trim();
773
+ if (trimmedPart.startsWith('@')) {
774
+ // For the first part in conditions with operators, we still want to transform to signal
775
+ // For later parts, keep as literal
776
+ if (index === 0) {
777
+ // First part: remove @ but will be transformed to signal later
778
+ return trimmedPart.substring(1);
779
+ } else {
780
+ // Later parts: remove @ and keep as literal (no signal)
781
+ return trimmedPart.substring(1);
782
+ }
783
+ } else {
784
+ // Don't transform keywords
785
+ if (['true', 'false', 'null'].includes(trimmedPart)) {
786
+ return trimmedPart;
787
+ }
788
+ // Check if already a function call
789
+ if (trimmedPart.includes('(')) {
790
+ return trimmedPart;
791
+ }
792
+ // Transform to signal
793
+ return `${trimmedPart}()`;
794
+ }
795
+ }).join('.');
796
+ }
797
+
798
+ // Store replacement and use a temporary marker
799
+ const marker = `__DOT_NOTATION_${replacementCounter++}__`;
800
+ dotNotationReplacements.set(marker, replacement);
801
+ return marker;
802
+ });
803
+
804
+ // Now handle standalone @ identifiers (not in dot notation)
805
+ processedText = processedText.replace(/@([a-zA-Z_][a-zA-Z0-9_]*)\b(?!\s*\.)/g, (match, p1) => {
806
+ return p1; // Remove @ prefix for standalone literals
807
+ });
808
+
749
809
  // Transform simple identifiers to function calls like "foo" to "foo()"
750
810
  // This regex matches identifiers not followed by an opening parenthesis.
751
811
  // This transformation should only apply if we are wrapping in 'computed'.
752
- if (originalText.includes('!') || originalText.includes('&&') || originalText.includes('||') ||
753
- originalText.includes('>=') || originalText.includes('<=') || originalText.includes('===') ||
754
- originalText.includes('!==') || originalText.includes('==') || originalText.includes('!=') ||
755
- originalText.includes('>') || originalText.includes('<')) {
756
- const transformedText = originalText.replace(/\b([a-zA-Z_][a-zA-Z0-9_]*)\b(?!\s*\()/g, (match, p1, offset) => {
812
+ if (processedText.includes('!') || processedText.includes('&&') || processedText.includes('||') ||
813
+ processedText.includes('>=') || processedText.includes('<=') || processedText.includes('===') ||
814
+ processedText.includes('!==') || processedText.includes('==') || processedText.includes('!=') ||
815
+ processedText.includes('>') || processedText.includes('<')) {
816
+ // Replace dot notation markers with their processed values BEFORE transforming identifiers
817
+ // This way, expressions like @item.id become item.id() and then item() is transformed
818
+ let textWithReplacements = processedText;
819
+ dotNotationReplacements.forEach((value, marker) => {
820
+ textWithReplacements = textWithReplacements.replace(new RegExp(marker.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'), 'g'), value);
821
+ });
822
+
823
+ const transformedText = textWithReplacements.replace(/\b([a-zA-Z_][a-zA-Z0-9_]*)\b(?!\s*\()/g, (match, p1, offset) => {
757
824
  // Do not transform keywords (true, false, null) or numeric literals
758
825
  if (['true', 'false', 'null'].includes(match) || /^\d+(\.\d+)?$/.test(match)) {
759
826
  return match;
760
827
  }
828
+
829
+ // Check if this is a marker (starts with __DOT_NOTATION_)
830
+ if (match.startsWith('__DOT_NOTATION_')) {
831
+ return match; // Don't transform markers
832
+ }
833
+
761
834
  // Check if the match is inside quotes
762
- const beforeMatch = originalText.substring(0, offset);
763
- const afterMatch = originalText.substring(offset + match.length);
835
+ const beforeMatch = processedText.substring(0, offset);
836
+ const afterMatch = processedText.substring(offset + match.length);
764
837
  const singleQuotesBefore = (beforeMatch.match(/'/g) || []).length;
765
838
  const doubleQuotesBefore = (beforeMatch.match(/"/g) || []).length;
766
839
 
@@ -769,13 +842,64 @@ condition "condition expression"
769
842
  return match;
770
843
  }
771
844
 
845
+ // Check if this identifier is part of a dot notation expression
846
+ const charBefore = offset > 0 ? textWithReplacements[offset - 1] : '';
847
+ const charAfter = offset + match.length < textWithReplacements.length ? textWithReplacements[offset + match.length] : '';
848
+
849
+ // If there's a dot before or after, this is part of dot notation
850
+ if (charBefore === '.' || charAfter === '.') {
851
+ // Check if this dot notation expression was a marker (had @ in original)
852
+ const beforeContext = originalText.substring(Math.max(0, offset - 20), offset);
853
+ const afterContext = originalText.substring(offset, Math.min(originalText.length, offset + match.length + 20));
854
+ const fullContext = beforeContext + afterContext;
855
+
856
+ // Check if this identifier had @ in the original
857
+ const hadAt = fullContext.includes('@' + match) || fullContext.match(new RegExp('@' + match.replace(/[.*+?^${}()|[\]\\]/g, '\\$&') + '\\b'));
858
+
859
+ if (hadAt) {
860
+ // Check if ALL parts of the dot notation had @ (all literals)
861
+ // Find the full dot notation expression in the original
862
+ const dotExprMatch = originalText.match(/(@?[a-zA-Z_][a-zA-Z0-9_]*)(\.@?[a-zA-Z_][a-zA-Z0-9_]*)+/);
863
+ if (dotExprMatch) {
864
+ const dotExpr = dotExprMatch[0];
865
+ const allPartsHadAt = dotExpr.split('.').every(part => part.trim().startsWith('@'));
866
+ if (allPartsHadAt) {
867
+ // All parts were literals (@item.@id), don't transform
868
+ return match;
869
+ }
870
+ }
871
+
872
+ // Only some parts had @ (@item.id or item.@id)
873
+ if (charAfter === '.') {
874
+ // First part: transform to signal even if it had @
875
+ return `${match}()`;
876
+ } else if (charBefore === '.') {
877
+ // Later part: already processed in marker, don't retransform
878
+ return match;
879
+ }
880
+ }
881
+
882
+ // In conditions with operators, transform dot notation expressions to signals
883
+ // (e.g., user.role becomes user().role())
884
+ // This applies to regular dot notation, not markers (which are already processed)
885
+ return `${match}()`;
886
+ }
887
+
772
888
  return `${match}()`;
773
889
  });
890
+
774
891
  return `computed(() => ${transformedText})`;
775
892
  }
776
- // For simple conditions (no !, &&, ||), return the original text as is.
777
- // Cases like `myFunction()` are handled by the `functionCall` rule.
778
- return originalText;
893
+ // For simple conditions (no !, &&, ||), return the processed text as is.
894
+ // Cases like `myFunction()` are handled by the `functionCallWithArgs` rule.
895
+
896
+ // Replace dot notation markers with their processed values
897
+ let finalText = processedText;
898
+ dotNotationReplacements.forEach((value, marker) => {
899
+ finalText = finalText.replace(new RegExp(marker.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'), 'g'), value);
900
+ });
901
+
902
+ return finalText;
779
903
  }
780
904
 
781
905
  functionCall "function call"
@@ -783,16 +907,95 @@ functionCall "function call"
783
907
  return `${name}(${args || ''})`;
784
908
  }
785
909
 
910
+ functionCallWithArgs "function call with complex args"
911
+ = name:identifier "(" args:complexFunctionArgs? ")" {
912
+ return `${name}(${args || ''})`;
913
+ }
914
+
786
915
  functionArgs
787
916
  = arg:functionArg rest:("," _ functionArg)* {
788
917
  return [arg].concat(rest.map(r => r[2])).join(', ');
789
918
  }
790
919
 
920
+ complexFunctionArgs
921
+ = arg:complexFunctionArg rest:("," _ complexFunctionArg)* {
922
+ return [arg].concat(rest.map(r => r[2])).join(', ');
923
+ }
924
+
791
925
  functionArg
792
926
  = _ value:(identifier / number / string) _ {
793
927
  return value;
794
928
  }
795
929
 
930
+ complexFunctionArg "complex function argument"
931
+ = _ value:complexArgExpression _ {
932
+ // Process @ literals and transform identifiers to signals
933
+ // Handle dot notation with @ literals like @item.@id, @item.id, item.@id
934
+ // Similar logic to simpleDynamicPart but for function arguments
935
+
936
+ let processed = value.trim();
937
+ const original = processed;
938
+
939
+ // Check if it's a dot notation expression
940
+ if (processed.match(/^(@?[a-zA-Z_][a-zA-Z0-9_]*)(\.@?[a-zA-Z_][a-zA-Z0-9_]*)*$/)) {
941
+ // Split by dots to handle each part separately
942
+ const parts = processed.split('.');
943
+ const allLiterals = parts.every(part => part.trim().startsWith('@'));
944
+
945
+ let computedValue;
946
+
947
+ if (allLiterals) {
948
+ // All parts are literals, just remove @ prefixes
949
+ computedValue = parts.map(part => part.trim().replace('@', '')).join('.');
950
+ } else {
951
+ // Transform each part individually
952
+ computedValue = parts.map(part => {
953
+ const trimmedPart = part.trim();
954
+ if (trimmedPart.startsWith('@')) {
955
+ return trimmedPart.substring(1); // Remove @ prefix for literals
956
+ } else {
957
+ // Don't transform keywords
958
+ if (['true', 'false', 'null'].includes(trimmedPart)) {
959
+ return trimmedPart;
960
+ }
961
+ // Check if it's already a function call
962
+ if (trimmedPart.includes('(')) {
963
+ return trimmedPart;
964
+ }
965
+ // Transform to signal
966
+ return `${trimmedPart}()`;
967
+ }
968
+ }).join('.');
969
+ }
970
+
971
+ return computedValue;
972
+ }
973
+
974
+ // Handle standalone identifiers (not dot notation)
975
+ // If it starts with @, remove @ prefix (literal)
976
+ if (processed.startsWith('@')) {
977
+ return processed.substring(1);
978
+ }
979
+
980
+ // Don't transform keywords or numbers
981
+ if (['true', 'false', 'null'].includes(processed) || /^\d+(\.\d+)?$/.test(processed)) {
982
+ return processed;
983
+ }
984
+
985
+ // Check if it's already a function call
986
+ if (processed.includes('(')) {
987
+ return processed;
988
+ }
989
+
990
+ // Transform identifier to signal
991
+ return `${processed}()`;
992
+ }
993
+
994
+ complexArgExpression "complex argument expression"
995
+ = $([^,)]* ("(" [^)]* ")" [^,)]*)*) {
996
+ return text().trim();
997
+ }
998
+
796
999
  number
797
1000
  = [0-9]+ ("." [0-9]+)? { return text(); }
798
1001
 
package/dist/index.js CHANGED
@@ -8,6 +8,21 @@ 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
+ }
11
26
  function showErrorMessage(template, error) {
12
27
  if (!error.location) {
13
28
  return `Syntax error: ${error.message}`;
@@ -22,6 +37,72 @@ ${errorLine}
22
37
  ${pointer}
23
38
  `;
24
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
+ }
25
106
  function shaderLoader() {
26
107
  const filter = createFilter(/\.(frag|vert|wgsl)$/);
27
108
  return {
@@ -54,6 +135,7 @@ function canvasengine() {
54
135
  "Viewport",
55
136
  "Graphics",
56
137
  "Container",
138
+ "FocusContainer",
57
139
  "ImageMap",
58
140
  "NineSliceSprite",
59
141
  "Rect",
@@ -76,7 +158,15 @@ function canvasengine() {
76
158
  if (!filter(id)) return null;
77
159
  const scriptMatch = code.match(/<script>([\s\S]*?)<\/script>/);
78
160
  let scriptContent = scriptMatch ? scriptMatch[1].trim() : "";
79
- let template = code.replace(/<script>[\s\S]*?<\/script>/, "").replace(/^\s+|\s+$/g, "");
161
+ const styleTagMatch = code.match(/<style([^>]*)>([\s\S]*?)<\/style>/);
162
+ let styleContent = "";
163
+ let isScoped = false;
164
+ if (styleTagMatch) {
165
+ const styleAttributes = styleTagMatch[1].trim();
166
+ styleContent = styleTagMatch[2].trim();
167
+ isScoped = /scoped(?:\s|>|$)/.test(styleAttributes);
168
+ }
169
+ let template = code.replace(/<script>[\s\S]*?<\/script>/, "").replace(/<style[^>]*>[\s\S]*?<\/style>/, "").replace(/^\s+|\s+$/g, "");
80
170
  let parsedTemplate;
81
171
  try {
82
172
  parsedTemplate = parser.parse(template);
@@ -135,10 +225,41 @@ ${importsCode}`;
135
225
  ${importsCode}`;
136
226
  }
137
227
  });
228
+ let processedStyleContent = styleContent;
229
+ let scopeClass = "";
230
+ if (isScoped && styleContent) {
231
+ const fileHash = generateHash(id);
232
+ scopeClass = fileHash;
233
+ processedStyleContent = scopeCSS(styleContent, scopeClass);
234
+ parsedTemplate = parsedTemplate.replace(
235
+ /h\(DOMContainer\s*,\s*(\{([^}]*)\}|null)\s*(,\s*[^)]*)?\)/g,
236
+ (match, propsPart, propsContent, childrenPart) => {
237
+ if (propsPart === "null") {
238
+ return `h(DOMContainer, { _scopeClass: '${scopeClass}' }${childrenPart || ""})`;
239
+ } else {
240
+ return `h(DOMContainer, { _scopeClass: '${scopeClass}', ${propsContent || ""} }${childrenPart || ""})`;
241
+ }
242
+ }
243
+ );
244
+ parsedTemplate = parsedTemplate.replace(
245
+ /h\(DOMContainer\s*\)(?!\s*\()/g,
246
+ `h(DOMContainer, { _scopeClass: '${scopeClass}' })`
247
+ );
248
+ }
249
+ const escapedStyleContent = processedStyleContent.replace(/\\/g, "\\\\").replace(/'/g, "\\'").replace(/\n/g, "\\n").replace(/\r/g, "\\r");
250
+ const styleId = `ce-style-${id.replace(/[^a-zA-Z0-9]/g, "-")}`;
251
+ const styleInjectionCode = styleContent ? `// Inject CSS styles into the document head
252
+ if (typeof document !== 'undefined' && !document.getElementById('${styleId}')) {
253
+ const styleElement = document.createElement('style');
254
+ styleElement.id = '${styleId}';
255
+ styleElement.textContent = '${escapedStyleContent}';
256
+ document.head.appendChild(styleElement);
257
+ }
258
+ ` : "";
138
259
  const output = String.raw`
139
260
  ${importsCode}
140
261
  import { useProps, useDefineProps } from ${isDev ? `'${DEV_SRC}'` : "'canvasengine'"}
141
-
262
+ ${styleInjectionCode}
142
263
  export default function component($$props) {
143
264
  const $props = useProps($$props)
144
265
  const defineProps = useDefineProps($$props)
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\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\"),\n \"utf8\"\n );\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 \"DOMElement\",\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\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":[]}
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\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\"),\n \"utf8\"\n );\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 \"FocusContainer\",\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 \"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\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 // Pattern: h(DOMContainer, { ... }) or h(DOMContainer) or h(DOMContainer, null, ...)\n parsedTemplate = parsedTemplate.replace(\n /h\\(DOMContainer\\s*,\\s*(\\{([^}]*)\\}|null)\\s*(,\\s*[^)]*)?\\)/g,\n (match, propsPart, propsContent, childrenPart) => {\n if (propsPart === 'null') {\n // h(DOMContainer, null, ...) -> h(DOMContainer, { _scopeClass: '...' }, ...)\n return `h(DOMContainer, { _scopeClass: '${scopeClass}' }${childrenPart || ''})`;\n } else {\n // h(DOMContainer, { ... }, ...) -> h(DOMContainer, { _scopeClass: '...', ... }, ...)\n // Need to insert _scopeClass at the beginning of the props object\n return `h(DOMContainer, { _scopeClass: '${scopeClass}', ${propsContent || ''} }${childrenPart || ''})`;\n }\n }\n );\n \n // Also handle h(DOMContainer) without props\n parsedTemplate = parsedTemplate.replace(\n /h\\(DOMContainer\\s*\\)(?!\\s*\\()/g,\n `h(DOMContainer, { _scopeClass: '${scopeClass}' })`\n );\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":"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","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@canvasengine/compiler",
3
- "version": "2.0.0-beta.41",
3
+ "version": "2.0.0-beta.43",
4
4
  "description": "",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",