juxscript 1.1.56 → 1.1.57

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.
@@ -8,7 +8,7 @@ export interface ParsedLine {
8
8
  */
9
9
  declare function escapeHtml(text: string): string;
10
10
  /**
11
- * Parse code into lines with simple syntax highlighting
11
+ * Parse code into lines - CHARACTER-BY-CHARACTER TOKENIZATION
12
12
  */
13
13
  export declare function parseCode(code: string, language?: string): ParsedLine[];
14
14
  /**
@@ -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;AAuCD;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,UAAU,EAAE,UAAU,GAAG,MAAM,CAEnE;AAED;;GAEG;AACH,wBAAgB,qBAAqB,IAAI,MAAM,CA8D9C;;;;;;;AAED,wBAKE"}
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"}
@@ -24,47 +24,90 @@ function escapeHtml(text) {
24
24
  .replace(/'/g, ''');
25
25
  }
26
26
  /**
27
- * Parse code into lines with simple syntax highlighting
27
+ * Parse code into lines - CHARACTER-BY-CHARACTER TOKENIZATION
28
28
  */
29
29
  export function parseCode(code, language = 'javascript') {
30
30
  const lines = code.split('\n');
31
31
  return lines.map((line, index) => ({
32
32
  lineNumber: index + 1,
33
- html: highlightLine(line),
33
+ html: tokenizeLine(line),
34
34
  raw: line
35
35
  }));
36
36
  }
37
37
  /**
38
- * Highlight a single line - token-by-token approach to avoid nested spans
38
+ * Tokenize a single line character-by-character
39
39
  */
40
- function highlightLine(line) {
40
+ function tokenizeLine(line) {
41
41
  if (!line.trim())
42
42
  return ' ';
43
- // ✅ Split line into tokens (words, operators, whitespace)
44
- const tokens = line.match(/\w+|[^\w\s]|\s+/g) || [];
45
43
  let result = '';
46
- tokens.forEach(token => {
47
- // Skip empty tokens
48
- if (!token)
49
- return;
50
- // Whitespace - preserve as-is
51
- if (/^\s+$/.test(token)) {
52
- result += token;
53
- return;
44
+ let i = 0;
45
+ const len = line.length;
46
+ while (i < len) {
47
+ const char = line[i];
48
+ // Whitespace - preserve
49
+ if (/\s/.test(char)) {
50
+ result += char;
51
+ i++;
52
+ continue;
54
53
  }
55
- // Escape the token
56
- const escaped = escapeHtml(token);
57
- // Keywords
58
- if (KEYWORDS.has(token)) {
59
- result += `<span class="token-keyword">${escaped}</span>`;
54
+ // Word (identifier or keyword)
55
+ if (/[a-zA-Z_$]/.test(char)) {
56
+ const word = consumeWord(line, i);
57
+ const escaped = escapeHtml(word);
58
+ if (KEYWORDS.has(word)) {
59
+ result += `<span class="token-keyword">${escaped}</span>`;
60
+ }
61
+ else {
62
+ result += escaped;
63
+ }
64
+ i += word.length;
65
+ continue;
60
66
  }
61
- // Everything else - plain text
62
- else {
63
- result += escaped;
67
+ // Number
68
+ if (/\d/.test(char)) {
69
+ const num = consumeNumber(line, i);
70
+ result += `<span class="token-number">${escapeHtml(num)}</span>`;
71
+ i += num.length;
72
+ continue;
64
73
  }
65
- });
74
+ // Everything else - just escape and append
75
+ result += escapeHtml(char);
76
+ i++;
77
+ }
66
78
  return result || ' ';
67
79
  }
80
+ /**
81
+ * Consume a complete word (identifier)
82
+ */
83
+ function consumeWord(line, start) {
84
+ let i = start;
85
+ while (i < line.length && /[a-zA-Z0-9_$]/.test(line[i])) {
86
+ i++;
87
+ }
88
+ return line.substring(start, i);
89
+ }
90
+ /**
91
+ * Consume a complete number
92
+ */
93
+ function consumeNumber(line, start) {
94
+ let i = start;
95
+ let hasDot = false;
96
+ while (i < line.length) {
97
+ const char = line[i];
98
+ if (/\d/.test(char)) {
99
+ i++;
100
+ }
101
+ else if (char === '.' && !hasDot) {
102
+ hasDot = true;
103
+ i++;
104
+ }
105
+ else {
106
+ break;
107
+ }
108
+ }
109
+ return line.substring(start, i);
110
+ }
68
111
  /**
69
112
  * Render a parsed line
70
113
  */
@@ -76,7 +119,7 @@ export function renderLineWithTokens(parsedLine) {
76
119
  */
77
120
  export function getSyntaxHighlightCSS() {
78
121
  return `
79
- /* Simple Syntax Highlighting */
122
+ /* Simple Code Highlighting */
80
123
  .jux-code {
81
124
  font-family: 'Fira Code', 'Consolas', 'Monaco', monospace;
82
125
  font-size: 14px;
@@ -130,10 +173,13 @@ export function getSyntaxHighlightCSS() {
130
173
  display: none;
131
174
  }
132
175
 
133
- /* Token colors - JUST KEYWORDS */
176
+ /* Token colors */
134
177
  .token-keyword {
135
178
  color: #c678dd;
136
179
  font-weight: 600;
180
+ }
181
+ .token-number {
182
+ color: #d19a66;
137
183
  }
138
184
  `;
139
185
  }
@@ -32,55 +32,103 @@ function escapeHtml(text: string): string {
32
32
  }
33
33
 
34
34
  /**
35
- * Parse code into lines with simple syntax highlighting
35
+ * Parse code into lines - CHARACTER-BY-CHARACTER TOKENIZATION
36
36
  */
37
37
  export function parseCode(code: string, language: string = 'javascript'): ParsedLine[] {
38
38
  const lines = code.split('\n');
39
39
 
40
40
  return lines.map((line, index) => ({
41
41
  lineNumber: index + 1,
42
- html: highlightLine(line),
42
+ html: tokenizeLine(line),
43
43
  raw: line
44
44
  }));
45
45
  }
46
46
 
47
47
  /**
48
- * Highlight a single line - token-by-token approach to avoid nested spans
48
+ * Tokenize a single line character-by-character
49
49
  */
50
- function highlightLine(line: string): string {
50
+ function tokenizeLine(line: string): string {
51
51
  if (!line.trim()) return ' ';
52
52
 
53
- // ✅ Split line into tokens (words, operators, whitespace)
54
- const tokens = line.match(/\w+|[^\w\s]|\s+/g) || [];
55
-
56
53
  let result = '';
54
+ let i = 0;
55
+ const len = line.length;
57
56
 
58
- tokens.forEach(token => {
59
- // Skip empty tokens
60
- if (!token) return;
57
+ while (i < len) {
58
+ const char = line[i];
61
59
 
62
- // Whitespace - preserve as-is
63
- if (/^\s+$/.test(token)) {
64
- result += token;
65
- return;
60
+ // Whitespace - preserve
61
+ if (/\s/.test(char)) {
62
+ result += char;
63
+ i++;
64
+ continue;
66
65
  }
67
66
 
68
- // Escape the token
69
- const escaped = escapeHtml(token);
67
+ // Word (identifier or keyword)
68
+ if (/[a-zA-Z_$]/.test(char)) {
69
+ const word = consumeWord(line, i);
70
+ const escaped = escapeHtml(word);
71
+
72
+ if (KEYWORDS.has(word)) {
73
+ result += `<span class="token-keyword">${escaped}</span>`;
74
+ } else {
75
+ result += escaped;
76
+ }
70
77
 
71
- // Keywords
72
- if (KEYWORDS.has(token)) {
73
- result += `<span class="token-keyword">${escaped}</span>`;
78
+ i += word.length;
79
+ continue;
74
80
  }
75
- // Everything else - plain text
76
- else {
77
- result += escaped;
81
+
82
+ // Number
83
+ if (/\d/.test(char)) {
84
+ const num = consumeNumber(line, i);
85
+ result += `<span class="token-number">${escapeHtml(num)}</span>`;
86
+ i += num.length;
87
+ continue;
78
88
  }
79
- });
89
+
90
+ // Everything else - just escape and append
91
+ result += escapeHtml(char);
92
+ i++;
93
+ }
80
94
 
81
95
  return result || ' ';
82
96
  }
83
97
 
98
+ /**
99
+ * Consume a complete word (identifier)
100
+ */
101
+ function consumeWord(line: string, start: number): string {
102
+ let i = start;
103
+ while (i < line.length && /[a-zA-Z0-9_$]/.test(line[i])) {
104
+ i++;
105
+ }
106
+ return line.substring(start, i);
107
+ }
108
+
109
+ /**
110
+ * Consume a complete number
111
+ */
112
+ function consumeNumber(line: string, start: number): string {
113
+ let i = start;
114
+ let hasDot = false;
115
+
116
+ while (i < line.length) {
117
+ const char = line[i];
118
+
119
+ if (/\d/.test(char)) {
120
+ i++;
121
+ } else if (char === '.' && !hasDot) {
122
+ hasDot = true;
123
+ i++;
124
+ } else {
125
+ break;
126
+ }
127
+ }
128
+
129
+ return line.substring(start, i);
130
+ }
131
+
84
132
  /**
85
133
  * Render a parsed line
86
134
  */
@@ -93,7 +141,7 @@ export function renderLineWithTokens(parsedLine: ParsedLine): string {
93
141
  */
94
142
  export function getSyntaxHighlightCSS(): string {
95
143
  return `
96
- /* Simple Syntax Highlighting */
144
+ /* Simple Code Highlighting */
97
145
  .jux-code {
98
146
  font-family: 'Fira Code', 'Consolas', 'Monaco', monospace;
99
147
  font-size: 14px;
@@ -147,10 +195,13 @@ export function getSyntaxHighlightCSS(): string {
147
195
  display: none;
148
196
  }
149
197
 
150
- /* Token colors - JUST KEYWORDS */
198
+ /* Token colors */
151
199
  .token-keyword {
152
200
  color: #c678dd;
153
201
  font-weight: 600;
202
+ }
203
+ .token-number {
204
+ color: #d19a66;
154
205
  }
155
206
  `;
156
207
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "juxscript",
3
- "version": "1.1.56",
3
+ "version": "1.1.57",
4
4
  "type": "module",
5
5
  "description": "A JavaScript UX authorship platform",
6
6
  "main": "index.js",