juxscript 1.1.57 → 1.1.58

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.
@@ -1 +1 @@
1
- {"version":3,"file":"codeparser.d.ts","sourceRoot":"","sources":["codeparser.ts"],"names":[],"mappings":"AAeA,MAAM,WAAW,UAAU;IACvB,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;CACf;AAED;;GAEG;AACH,iBAAS,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAOxC;AAED;;GAEG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,GAAE,MAAqB,GAAG,UAAU,EAAE,CAQrF;AAuFD;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,UAAU,EAAE,UAAU,GAAG,MAAM,CAEnE;AAED;;GAEG;AACH,wBAAgB,qBAAqB,IAAI,MAAM,CAiE9C;;;;;;;AAED,wBAKE"}
1
+ {"version":3,"file":"codeparser.d.ts","sourceRoot":"","sources":["codeparser.ts"],"names":[],"mappings":"AA2DA,MAAM,WAAW,UAAU;IACvB,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;CACf;AAED;;GAEG;AACH,iBAAS,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAOxC;AAED;;GAEG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,GAAE,MAAqB,GAAG,UAAU,EAAE,CAQrF;AAiLD;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,UAAU,EAAE,UAAU,GAAG,MAAM,CAEnE;AAED;;GAEG;AACH,wBAAgB,qBAAqB,IAAI,MAAM,CAkG9C;;;;;;;AAED,wBAKE"}
@@ -12,6 +12,43 @@ const KEYWORDS = new Set([
12
12
  '!=', '!==', '+', '-', '*', '/', '%', '++', '--', '&&', '||', '!', '<', '>',
13
13
  '<=', '>=', '=>', '...', '.', ',', '(', ')', '{', '}', '[', ']', ':', '?'
14
14
  ]);
15
+ /**
16
+ * Categorized token sets for semantic highlighting
17
+ */
18
+ // Control flow keywords (loops, conditionals, etc.)
19
+ const CONTROL_FLOW = new Set([
20
+ 'if', 'else', 'switch', 'case', 'default',
21
+ 'for', 'while', 'do', 'break', 'continue',
22
+ 'return', 'throw', 'try', 'catch', 'finally'
23
+ ]);
24
+ // Declaration keywords
25
+ const DECLARATIONS = new Set([
26
+ 'const', 'let', 'var', 'function', 'class',
27
+ 'import', 'export', 'from', 'as',
28
+ 'interface', 'type', 'enum', 'namespace',
29
+ 'static', 'get', 'set', 'extends'
30
+ ]);
31
+ // Operator keywords
32
+ const OPERATORS = new Set([
33
+ 'new', 'delete', 'typeof', 'instanceof',
34
+ 'void', 'await', 'yield', 'in', 'of'
35
+ ]);
36
+ // Special keywords
37
+ const SPECIAL = new Set([
38
+ 'this', 'super', 'async', 'debugger', 'with'
39
+ ]);
40
+ // JUX-specific keywords
41
+ const JUX_KEYWORDS = new Set([
42
+ 'jux', 'state', 'registry', 'render', 'bind', 'sync'
43
+ ]);
44
+ // Combine all keywords for quick lookup
45
+ const ALL_KEYWORDS = new Set([
46
+ ...CONTROL_FLOW,
47
+ ...DECLARATIONS,
48
+ ...OPERATORS,
49
+ ...SPECIAL,
50
+ ...JUX_KEYWORDS
51
+ ]);
15
52
  /**
16
53
  * Escape HTML entities
17
54
  */
@@ -35,7 +72,41 @@ export function parseCode(code, language = 'javascript') {
35
72
  }));
36
73
  }
37
74
  /**
38
- * Tokenize a single line character-by-character
75
+ * Get the appropriate CSS class for a keyword
76
+ */
77
+ function getKeywordClass(word) {
78
+ if (CONTROL_FLOW.has(word))
79
+ return 'token-control';
80
+ if (DECLARATIONS.has(word))
81
+ return 'token-declaration';
82
+ if (OPERATORS.has(word))
83
+ return 'token-operator-keyword';
84
+ if (SPECIAL.has(word))
85
+ return 'token-special';
86
+ if (JUX_KEYWORDS.has(word))
87
+ return 'token-jux';
88
+ return 'token-keyword'; // fallback
89
+ }
90
+ /**
91
+ * Check if character is a structural punctuation (braces, brackets, parens)
92
+ */
93
+ function isStructural(char) {
94
+ return '(){}[]'.includes(char);
95
+ }
96
+ /**
97
+ * Check if character is a delimiter (semicolon, comma, colon)
98
+ */
99
+ function isDelimiter(char) {
100
+ return ';,:'.includes(char);
101
+ }
102
+ /**
103
+ * Check if character is an operator
104
+ */
105
+ function isOperator(char) {
106
+ return '+-*/%=<>!&|^~?'.includes(char);
107
+ }
108
+ /**
109
+ * Tokenize a single line character-by-character with semantic categories
39
110
  */
40
111
  function tokenizeLine(line) {
41
112
  if (!line.trim())
@@ -43,6 +114,10 @@ function tokenizeLine(line) {
43
114
  let result = '';
44
115
  let i = 0;
45
116
  const len = line.length;
117
+ // Check for comment at start
118
+ if (line.trim().startsWith('//')) {
119
+ return `<span class="token-comment">${escapeHtml(line)}</span>`;
120
+ }
46
121
  while (i < len) {
47
122
  const char = line[i];
48
123
  // Whitespace - preserve
@@ -51,12 +126,42 @@ function tokenizeLine(line) {
51
126
  i++;
52
127
  continue;
53
128
  }
129
+ // Comment (// or /* */)
130
+ if (char === '/' && i + 1 < len) {
131
+ if (line[i + 1] === '/') {
132
+ // Line comment - consume rest of line
133
+ const comment = line.slice(i);
134
+ result += `<span class="token-comment">${escapeHtml(comment)}</span>`;
135
+ break;
136
+ }
137
+ else if (line[i + 1] === '*') {
138
+ // Block comment start
139
+ const commentEnd = line.indexOf('*/', i + 2);
140
+ if (commentEnd !== -1) {
141
+ const comment = line.slice(i, commentEnd + 2);
142
+ result += `<span class="token-comment">${escapeHtml(comment)}</span>`;
143
+ i = commentEnd + 2;
144
+ continue;
145
+ }
146
+ }
147
+ }
148
+ // String literals (single, double, backtick)
149
+ if (char === '"' || char === "'" || char === '`') {
150
+ const stringEnd = line.indexOf(char, i + 1);
151
+ if (stringEnd !== -1) {
152
+ const str = line.slice(i, stringEnd + 1);
153
+ result += `<span class="token-string">${escapeHtml(str)}</span>`;
154
+ i = stringEnd + 1;
155
+ continue;
156
+ }
157
+ }
54
158
  // Word (identifier or keyword)
55
159
  if (/[a-zA-Z_$]/.test(char)) {
56
160
  const word = consumeWord(line, i);
57
161
  const escaped = escapeHtml(word);
58
- if (KEYWORDS.has(word)) {
59
- result += `<span class="token-keyword">${escaped}</span>`;
162
+ if (ALL_KEYWORDS.has(word)) {
163
+ const tokenClass = getKeywordClass(word);
164
+ result += `<span class="${tokenClass}">${escaped}</span>`;
60
165
  }
61
166
  else {
62
167
  result += escaped;
@@ -71,6 +176,24 @@ function tokenizeLine(line) {
71
176
  i += num.length;
72
177
  continue;
73
178
  }
179
+ // Structural punctuation (braces, brackets, parens)
180
+ if (isStructural(char)) {
181
+ result += `<span class="token-structural">${escapeHtml(char)}</span>`;
182
+ i++;
183
+ continue;
184
+ }
185
+ // Delimiters (semicolon, comma, colon)
186
+ if (isDelimiter(char)) {
187
+ result += `<span class="token-delimiter">${escapeHtml(char)}</span>`;
188
+ i++;
189
+ continue;
190
+ }
191
+ // Operators
192
+ if (isOperator(char)) {
193
+ result += `<span class="token-operator">${escapeHtml(char)}</span>`;
194
+ i++;
195
+ continue;
196
+ }
74
197
  // Everything else - just escape and append
75
198
  result += escapeHtml(char);
76
199
  i++;
@@ -119,7 +242,7 @@ export function renderLineWithTokens(parsedLine) {
119
242
  */
120
243
  export function getSyntaxHighlightCSS() {
121
244
  return `
122
- /* Simple Code Highlighting */
245
+ /* Semantic Code Highlighting */
123
246
  .jux-code {
124
247
  font-family: 'Fira Code', 'Consolas', 'Monaco', monospace;
125
248
  font-size: 14px;
@@ -173,13 +296,46 @@ export function getSyntaxHighlightCSS() {
173
296
  display: none;
174
297
  }
175
298
 
176
- /* Token colors */
177
- .token-keyword {
178
- color: #c678dd;
299
+ /* Token colors - Semantic categories */
300
+ .token-control {
301
+ color: #c678dd; /* Purple - control flow (if, for, return) */
179
302
  font-weight: 600;
180
303
  }
304
+ .token-declaration {
305
+ color: #61afef; /* Blue - declarations (const, let, function) */
306
+ font-weight: 600;
307
+ }
308
+ .token-operator-keyword {
309
+ color: #e06c75; /* Red - operator keywords (typeof, instanceof) */
310
+ font-weight: 600;
311
+ }
312
+ .token-special {
313
+ color: #e5c07b; /* Yellow - special keywords (this, super, async) */
314
+ font-weight: 600;
315
+ }
316
+ .token-jux {
317
+ color: #56b6c2; /* Cyan - JUX-specific (jux, state, render) */
318
+ font-weight: 700;
319
+ }
181
320
  .token-number {
182
- color: #d19a66;
321
+ color: #d19a66; /* Orange - numbers */
322
+ }
323
+ .token-string {
324
+ color: #98c379; /* Green - strings */
325
+ }
326
+ .token-comment {
327
+ color: #5c6370; /* Gray - comments */
328
+ font-style: italic;
329
+ }
330
+ .token-structural {
331
+ color: #abb2bf; /* Light gray - braces, brackets, parens */
332
+ font-weight: 600;
333
+ }
334
+ .token-delimiter {
335
+ color: #777; /* Dark gray - semicolons, commas, colons */
336
+ }
337
+ .token-operator {
338
+ color: #56b6c2; /* Cyan - operators (+, -, *, etc.) */
183
339
  }
184
340
  `;
185
341
  }
@@ -13,6 +13,50 @@ const KEYWORDS = new Set([
13
13
  '<=', '>=', '=>', '...', '.', ',', '(', ')', '{', '}', '[', ']', ':', '?'
14
14
  ]);
15
15
 
16
+ /**
17
+ * Categorized token sets for semantic highlighting
18
+ */
19
+
20
+ // Control flow keywords (loops, conditionals, etc.)
21
+ const CONTROL_FLOW = new Set([
22
+ 'if', 'else', 'switch', 'case', 'default',
23
+ 'for', 'while', 'do', 'break', 'continue',
24
+ 'return', 'throw', 'try', 'catch', 'finally'
25
+ ]);
26
+
27
+ // Declaration keywords
28
+ const DECLARATIONS = new Set([
29
+ 'const', 'let', 'var', 'function', 'class',
30
+ 'import', 'export', 'from', 'as',
31
+ 'interface', 'type', 'enum', 'namespace',
32
+ 'static', 'get', 'set', 'extends'
33
+ ]);
34
+
35
+ // Operator keywords
36
+ const OPERATORS = new Set([
37
+ 'new', 'delete', 'typeof', 'instanceof',
38
+ 'void', 'await', 'yield', 'in', 'of'
39
+ ]);
40
+
41
+ // Special keywords
42
+ const SPECIAL = new Set([
43
+ 'this', 'super', 'async', 'debugger', 'with'
44
+ ]);
45
+
46
+ // JUX-specific keywords
47
+ const JUX_KEYWORDS = new Set([
48
+ 'jux', 'state', 'registry', 'render', 'bind', 'sync'
49
+ ]);
50
+
51
+ // Combine all keywords for quick lookup
52
+ const ALL_KEYWORDS = new Set([
53
+ ...CONTROL_FLOW,
54
+ ...DECLARATIONS,
55
+ ...OPERATORS,
56
+ ...SPECIAL,
57
+ ...JUX_KEYWORDS
58
+ ]);
59
+
16
60
  export interface ParsedLine {
17
61
  lineNumber: number;
18
62
  html: string;
@@ -45,7 +89,40 @@ export function parseCode(code: string, language: string = 'javascript'): Parsed
45
89
  }
46
90
 
47
91
  /**
48
- * Tokenize a single line character-by-character
92
+ * Get the appropriate CSS class for a keyword
93
+ */
94
+ function getKeywordClass(word: string): string {
95
+ if (CONTROL_FLOW.has(word)) return 'token-control';
96
+ if (DECLARATIONS.has(word)) return 'token-declaration';
97
+ if (OPERATORS.has(word)) return 'token-operator-keyword';
98
+ if (SPECIAL.has(word)) return 'token-special';
99
+ if (JUX_KEYWORDS.has(word)) return 'token-jux';
100
+ return 'token-keyword'; // fallback
101
+ }
102
+
103
+ /**
104
+ * Check if character is a structural punctuation (braces, brackets, parens)
105
+ */
106
+ function isStructural(char: string): boolean {
107
+ return '(){}[]'.includes(char);
108
+ }
109
+
110
+ /**
111
+ * Check if character is a delimiter (semicolon, comma, colon)
112
+ */
113
+ function isDelimiter(char: string): boolean {
114
+ return ';,:'.includes(char);
115
+ }
116
+
117
+ /**
118
+ * Check if character is an operator
119
+ */
120
+ function isOperator(char: string): boolean {
121
+ return '+-*/%=<>!&|^~?'.includes(char);
122
+ }
123
+
124
+ /**
125
+ * Tokenize a single line character-by-character with semantic categories
49
126
  */
50
127
  function tokenizeLine(line: string): string {
51
128
  if (!line.trim()) return ' ';
@@ -54,6 +131,11 @@ function tokenizeLine(line: string): string {
54
131
  let i = 0;
55
132
  const len = line.length;
56
133
 
134
+ // Check for comment at start
135
+ if (line.trim().startsWith('//')) {
136
+ return `<span class="token-comment">${escapeHtml(line)}</span>`;
137
+ }
138
+
57
139
  while (i < len) {
58
140
  const char = line[i];
59
141
 
@@ -64,13 +146,44 @@ function tokenizeLine(line: string): string {
64
146
  continue;
65
147
  }
66
148
 
149
+ // Comment (// or /* */)
150
+ if (char === '/' && i + 1 < len) {
151
+ if (line[i + 1] === '/') {
152
+ // Line comment - consume rest of line
153
+ const comment = line.slice(i);
154
+ result += `<span class="token-comment">${escapeHtml(comment)}</span>`;
155
+ break;
156
+ } else if (line[i + 1] === '*') {
157
+ // Block comment start
158
+ const commentEnd = line.indexOf('*/', i + 2);
159
+ if (commentEnd !== -1) {
160
+ const comment = line.slice(i, commentEnd + 2);
161
+ result += `<span class="token-comment">${escapeHtml(comment)}</span>`;
162
+ i = commentEnd + 2;
163
+ continue;
164
+ }
165
+ }
166
+ }
167
+
168
+ // String literals (single, double, backtick)
169
+ if (char === '"' || char === "'" || char === '`') {
170
+ const stringEnd = line.indexOf(char, i + 1);
171
+ if (stringEnd !== -1) {
172
+ const str = line.slice(i, stringEnd + 1);
173
+ result += `<span class="token-string">${escapeHtml(str)}</span>`;
174
+ i = stringEnd + 1;
175
+ continue;
176
+ }
177
+ }
178
+
67
179
  // Word (identifier or keyword)
68
180
  if (/[a-zA-Z_$]/.test(char)) {
69
181
  const word = consumeWord(line, i);
70
182
  const escaped = escapeHtml(word);
71
183
 
72
- if (KEYWORDS.has(word)) {
73
- result += `<span class="token-keyword">${escaped}</span>`;
184
+ if (ALL_KEYWORDS.has(word)) {
185
+ const tokenClass = getKeywordClass(word);
186
+ result += `<span class="${tokenClass}">${escaped}</span>`;
74
187
  } else {
75
188
  result += escaped;
76
189
  }
@@ -87,6 +200,27 @@ function tokenizeLine(line: string): string {
87
200
  continue;
88
201
  }
89
202
 
203
+ // Structural punctuation (braces, brackets, parens)
204
+ if (isStructural(char)) {
205
+ result += `<span class="token-structural">${escapeHtml(char)}</span>`;
206
+ i++;
207
+ continue;
208
+ }
209
+
210
+ // Delimiters (semicolon, comma, colon)
211
+ if (isDelimiter(char)) {
212
+ result += `<span class="token-delimiter">${escapeHtml(char)}</span>`;
213
+ i++;
214
+ continue;
215
+ }
216
+
217
+ // Operators
218
+ if (isOperator(char)) {
219
+ result += `<span class="token-operator">${escapeHtml(char)}</span>`;
220
+ i++;
221
+ continue;
222
+ }
223
+
90
224
  // Everything else - just escape and append
91
225
  result += escapeHtml(char);
92
226
  i++;
@@ -141,7 +275,7 @@ export function renderLineWithTokens(parsedLine: ParsedLine): string {
141
275
  */
142
276
  export function getSyntaxHighlightCSS(): string {
143
277
  return `
144
- /* Simple Code Highlighting */
278
+ /* Semantic Code Highlighting */
145
279
  .jux-code {
146
280
  font-family: 'Fira Code', 'Consolas', 'Monaco', monospace;
147
281
  font-size: 14px;
@@ -195,13 +329,46 @@ export function getSyntaxHighlightCSS(): string {
195
329
  display: none;
196
330
  }
197
331
 
198
- /* Token colors */
199
- .token-keyword {
200
- color: #c678dd;
332
+ /* Token colors - Semantic categories */
333
+ .token-control {
334
+ color: #c678dd; /* Purple - control flow (if, for, return) */
335
+ font-weight: 600;
336
+ }
337
+ .token-declaration {
338
+ color: #61afef; /* Blue - declarations (const, let, function) */
339
+ font-weight: 600;
340
+ }
341
+ .token-operator-keyword {
342
+ color: #e06c75; /* Red - operator keywords (typeof, instanceof) */
201
343
  font-weight: 600;
202
344
  }
345
+ .token-special {
346
+ color: #e5c07b; /* Yellow - special keywords (this, super, async) */
347
+ font-weight: 600;
348
+ }
349
+ .token-jux {
350
+ color: #56b6c2; /* Cyan - JUX-specific (jux, state, render) */
351
+ font-weight: 700;
352
+ }
203
353
  .token-number {
204
- color: #d19a66;
354
+ color: #d19a66; /* Orange - numbers */
355
+ }
356
+ .token-string {
357
+ color: #98c379; /* Green - strings */
358
+ }
359
+ .token-comment {
360
+ color: #5c6370; /* Gray - comments */
361
+ font-style: italic;
362
+ }
363
+ .token-structural {
364
+ color: #abb2bf; /* Light gray - braces, brackets, parens */
365
+ font-weight: 600;
366
+ }
367
+ .token-delimiter {
368
+ color: #777; /* Dark gray - semicolons, commas, colons */
369
+ }
370
+ .token-operator {
371
+ color: #56b6c2; /* Cyan - operators (+, -, *, etc.) */
205
372
  }
206
373
  `;
207
374
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "juxscript",
3
- "version": "1.1.57",
3
+ "version": "1.1.58",
4
4
  "type": "module",
5
5
  "description": "A JavaScript UX authorship platform",
6
6
  "main": "index.js",