round-core 0.0.9 → 0.1.1

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/index.js CHANGED
@@ -1450,6 +1450,9 @@ function Link(props = {}) {
1450
1450
  const onClick = (e) => {
1451
1451
  if (typeof props.onClick === "function") props.onClick(e);
1452
1452
  if (e.defaultPrevented) return;
1453
+ if (props.target === "_blank") return;
1454
+ const strHref = String(href);
1455
+ if (strHref.includes("://") || strHref.startsWith("mailto:") || strHref.startsWith("tel:")) return;
1453
1456
  if (!spa || reload) return;
1454
1457
  if (e.button !== 0) return;
1455
1458
  if (e.metaKey || e.ctrlKey || e.shiftKey || e.altKey) return;
@@ -1,295 +1,382 @@
1
1
  import fs from "node:fs";
2
2
  import path from "node:path";
3
- function transform(code) {
3
+ function transform(code, initialDepth = 0) {
4
+ let result = "";
5
+ let i = 0;
6
+ let jsxDepth = initialDepth;
4
7
  function parseBlock(str, startIndex) {
5
8
  let open = 0;
6
9
  let startBlockIndex = -1;
7
- let endBlockIndex = -1;
8
- let inSingle = false;
9
- let inDouble = false;
10
- let inTemplate = false;
11
- let inCommentLine = false;
12
- let inCommentMulti = false;
13
- for (let i = startIndex; i < str.length; i++) {
14
- const ch = str[i];
15
- const prev2 = i > 0 ? str[i - 1] : "";
16
- const next = i < str.length - 1 ? str[i + 1] : "";
17
- if (inCommentLine) {
18
- if (ch === "\n" || ch === "\r") inCommentLine = false;
10
+ let inSingle2 = false, inDouble2 = false, inTemplate2 = false;
11
+ let inCommentLine2 = false, inCommentMulti2 = false;
12
+ for (let j = startIndex; j < str.length; j++) {
13
+ const ch = str[j];
14
+ const prev = j > 0 ? str[j - 1] : "";
15
+ const next = j < str.length - 1 ? str[j + 1] : "";
16
+ if (inCommentLine2) {
17
+ if (ch === "\n" || ch === "\r") inCommentLine2 = false;
19
18
  continue;
20
19
  }
21
- if (inCommentMulti) {
20
+ if (inCommentMulti2) {
22
21
  if (ch === "*" && next === "/") {
23
- inCommentMulti = false;
24
- i++;
22
+ inCommentMulti2 = false;
23
+ j++;
25
24
  }
26
25
  continue;
27
26
  }
28
- if (inTemplate) {
29
- if (ch === "`" && prev2 !== "\\") inTemplate = false;
27
+ if (inTemplate2) {
28
+ if (ch === "`" && prev !== "\\") inTemplate2 = false;
30
29
  continue;
31
30
  }
32
- if (inSingle) {
33
- if (ch === "'" && prev2 !== "\\") inSingle = false;
31
+ if (inSingle2) {
32
+ if (ch === "'" && prev !== "\\") inSingle2 = false;
34
33
  continue;
35
34
  }
36
- if (inDouble) {
37
- if (ch === '"' && prev2 !== "\\") inDouble = false;
35
+ if (inDouble2) {
36
+ if (ch === '"' && prev !== "\\") inDouble2 = false;
38
37
  continue;
39
38
  }
40
39
  if (ch === "/" && next === "/") {
41
- inCommentLine = true;
42
- i++;
40
+ inCommentLine2 = true;
41
+ j++;
43
42
  continue;
44
43
  }
45
44
  if (ch === "/" && next === "*") {
46
- inCommentMulti = true;
47
- i++;
45
+ inCommentMulti2 = true;
46
+ j++;
48
47
  continue;
49
48
  }
50
49
  if (ch === "`") {
51
- inTemplate = true;
50
+ inTemplate2 = true;
52
51
  continue;
53
52
  }
54
53
  if (ch === "'") {
55
- inSingle = true;
54
+ inSingle2 = true;
56
55
  continue;
57
56
  }
58
57
  if (ch === '"') {
59
- inDouble = true;
58
+ inDouble2 = true;
60
59
  continue;
61
60
  }
62
61
  if (ch === "{") {
63
- if (open === 0) startBlockIndex = i;
62
+ if (open === 0) startBlockIndex = j;
64
63
  open++;
65
64
  } else if (ch === "}") {
66
65
  open--;
67
66
  if (open === 0) {
68
- endBlockIndex = i;
69
- return { start: startBlockIndex, end: endBlockIndex };
67
+ return { start: startBlockIndex, end: j };
70
68
  }
71
69
  }
72
70
  }
73
71
  return null;
74
72
  }
75
- let result = code;
76
- function consumeWhitespace(str, i) {
77
- while (i < str.length && /\s/.test(str[i])) i++;
78
- return i;
73
+ function consumeWhitespace(str, idx) {
74
+ while (idx < str.length && /\s/.test(str[idx])) idx++;
75
+ return idx;
79
76
  }
80
- function parseIfChain(str, ifIndex) {
81
- const head = str.slice(ifIndex);
82
- const m = head.match(/^if\s*\((.*?)\)\s*\{/);
83
- if (!m) return null;
84
- let i = ifIndex;
77
+ function extractCondition(str, startIndex) {
78
+ if (str[startIndex] !== "(") return null;
79
+ let depth = 1;
80
+ let j = startIndex + 1;
81
+ let inSingle2 = false, inDouble2 = false, inTemplate2 = false;
82
+ while (j < str.length && depth > 0) {
83
+ const ch = str[j], prev = str[j - 1] || "";
84
+ if (!inDouble2 && !inTemplate2 && ch === "'" && prev !== "\\") inSingle2 = !inSingle2;
85
+ else if (!inSingle2 && !inTemplate2 && ch === '"' && prev !== "\\") inDouble2 = !inDouble2;
86
+ else if (!inSingle2 && !inDouble2 && ch === "`" && prev !== "\\") inTemplate2 = !inTemplate2;
87
+ if (!inSingle2 && !inDouble2 && !inTemplate2) {
88
+ if (ch === "(") depth++;
89
+ else if (ch === ")") depth--;
90
+ }
91
+ j++;
92
+ }
93
+ if (depth !== 0) return null;
94
+ return { cond: str.substring(startIndex + 1, j - 1), end: j };
95
+ }
96
+ function handleIf(currI, isBare = false) {
97
+ let startPtr = currI;
98
+ if (!isBare) {
99
+ startPtr = consumeWhitespace(code, currI + 1);
100
+ }
101
+ if (!code.startsWith("if", startPtr)) return null;
102
+ let ptr = startPtr + 2;
103
+ ptr = consumeWhitespace(code, ptr);
104
+ if (code[ptr] !== "(") return null;
85
105
  const cases = [];
86
106
  let elseContent = null;
107
+ let currentPtr = ptr;
108
+ let first = true;
87
109
  while (true) {
88
- const cur = str.slice(i);
89
- const mm = cur.match(/^if\s*\((.*?)\)\s*\{/);
90
- if (!mm) return null;
91
- let cond = mm[1];
92
- const trimmedCond = String(cond).trim();
93
- const isSimplePath = /^[A-Za-z_$][\w$]*(\.[A-Za-z_$][\w$]*)*$/.test(trimmedCond);
94
- if (isSimplePath && !trimmedCond.endsWith(")")) {
95
- cond = `((typeof (${trimmedCond}) === 'function' && typeof (${trimmedCond}).peek === 'function' && ('value' in (${trimmedCond}))) ? (${trimmedCond})() : (${trimmedCond}))`;
96
- }
97
- const blockStart = i + mm[0].length - 1;
98
- const block = parseBlock(str, blockStart);
110
+ if (!first) {
111
+ if (!code.startsWith("if", currentPtr)) break;
112
+ currentPtr += 2;
113
+ currentPtr = consumeWhitespace(code, currentPtr);
114
+ }
115
+ first = false;
116
+ const condRes = extractCondition(code, currentPtr);
117
+ if (!condRes) return null;
118
+ currentPtr = consumeWhitespace(code, condRes.end);
119
+ if (code[currentPtr] !== "{") return null;
120
+ const block = parseBlock(code, currentPtr);
99
121
  if (!block) return null;
100
- const content = str.substring(block.start + 1, block.end);
101
- cases.push({ cond, content });
102
- i = block.end + 1;
103
- i = consumeWhitespace(str, i);
104
- if (!str.startsWith("else", i)) {
122
+ const rawContent = code.substring(block.start + 1, block.end);
123
+ const transformedContent = transform(rawContent, 1);
124
+ cases.push({ cond: condRes.cond, content: transformedContent });
125
+ currentPtr = block.end + 1;
126
+ currentPtr = consumeWhitespace(code, currentPtr);
127
+ if (code.startsWith("else", currentPtr)) {
128
+ currentPtr += 4;
129
+ currentPtr = consumeWhitespace(code, currentPtr);
130
+ if (code.startsWith("if", currentPtr)) {
131
+ continue;
132
+ } else if (code[currentPtr] === "{") {
133
+ const elseBlock = parseBlock(code, currentPtr);
134
+ if (!elseBlock) return null;
135
+ const rawElse = code.substring(elseBlock.start + 1, elseBlock.end);
136
+ elseContent = transform(rawElse, 1);
137
+ currentPtr = elseBlock.end + 1;
138
+ break;
139
+ } else {
140
+ return null;
141
+ }
142
+ } else {
105
143
  break;
106
144
  }
107
- i += 4;
108
- i = consumeWhitespace(str, i);
109
- if (str.startsWith("if", i)) {
110
- continue;
111
- }
112
- if (str[i] !== "{") return null;
113
- const elseBlock = parseBlock(str, i);
114
- if (!elseBlock) return null;
115
- elseContent = str.substring(elseBlock.start + 1, elseBlock.end);
116
- i = elseBlock.end + 1;
117
- break;
118
- }
119
- const end = i;
145
+ }
146
+ let endIdx = currentPtr;
147
+ if (!isBare) {
148
+ endIdx = consumeWhitespace(code, endIdx);
149
+ if (code[endIdx] !== "}") return null;
150
+ endIdx++;
151
+ }
120
152
  let expr = "";
121
153
  for (let idx = 0; idx < cases.length; idx++) {
122
154
  const c = cases[idx];
123
- const body = `<Fragment>${c.content}</Fragment>`;
124
- if (idx === 0) {
125
- expr = `(${c.cond}) ? (${body}) : `;
126
- } else {
127
- expr += `(${c.cond}) ? (${body}) : `;
155
+ let cond = c.cond.trim();
156
+ const isSimplePath = /^[A-Za-z_$][\w$]*(\.[A-Za-z_$][\w$]*)*$/.test(cond);
157
+ if (isSimplePath && !cond.endsWith(")")) {
158
+ cond = `((typeof (${cond}) === 'function' && typeof (${cond}).peek === 'function' && ('value' in (${cond}))) ? (${cond})() : (${cond}))`;
128
159
  }
160
+ const body = `<Fragment>${c.content}</Fragment>`;
161
+ expr += `(${cond}) ? (${body}) : `;
129
162
  }
130
- if (elseContent !== null) {
131
- expr += `(<Fragment>${elseContent}</Fragment>)`;
132
- } else {
133
- expr += "null";
134
- }
135
- const replacement = `(() => ${expr})`;
136
- return { start: ifIndex, end, replacement };
163
+ expr += elseContent ? `(<Fragment>${elseContent}</Fragment>)` : "null";
164
+ return { end: endIdx, replacement: `{(() => ${expr})}` };
137
165
  }
138
- function parseIfStatement(str, ifIndex) {
139
- if (!str.startsWith("if", ifIndex)) return null;
140
- const chain = parseIfChain(str, ifIndex);
141
- if (!chain) return null;
142
- return {
143
- start: chain.start,
144
- end: chain.end,
145
- replacement: `{${chain.replacement}}`
146
- };
166
+ function handleFor(currI, isBare = false) {
167
+ let ptr = currI;
168
+ if (!isBare) ptr = consumeWhitespace(code, currI + 1);
169
+ if (!code.startsWith("for", ptr)) return null;
170
+ ptr += 3;
171
+ ptr = consumeWhitespace(code, ptr);
172
+ const condRes = extractCondition(code, ptr);
173
+ if (!condRes) return null;
174
+ const forCond = condRes.cond;
175
+ const inMatch = forCond.match(/^\s*(\S+)\s+in\s+(.+)$/);
176
+ if (!inMatch) return null;
177
+ const item = inMatch[1].trim();
178
+ const list = inMatch[2].trim();
179
+ ptr = consumeWhitespace(code, condRes.end);
180
+ if (code[ptr] !== "{") return null;
181
+ const block = parseBlock(code, ptr);
182
+ if (!block) return null;
183
+ const rawContent = code.substring(block.start + 1, block.end);
184
+ const transformedContent = transform(rawContent, 1);
185
+ let endIdx = block.end + 1;
186
+ if (!isBare) {
187
+ endIdx = consumeWhitespace(code, endIdx);
188
+ if (code[endIdx] !== "}") return null;
189
+ endIdx++;
190
+ }
191
+ const replacement = `{(() => ${list}.map(${item} => (<Fragment>${transformedContent}</Fragment>)))}`;
192
+ return { end: endIdx, replacement };
147
193
  }
148
- function parseIfExpression(str, exprStart) {
149
- if (str[exprStart] !== "{") return null;
150
- let i = consumeWhitespace(str, exprStart + 1);
151
- if (!str.startsWith("if", i)) return null;
152
- const outer = parseBlock(str, exprStart);
153
- if (!outer) return null;
154
- const chain = parseIfChain(str, i);
155
- if (!chain) return null;
156
- return {
157
- start: exprStart,
158
- end: outer.end + 1,
159
- replacement: `{${chain.replacement}}`
160
- };
194
+ function handleSwitch(currI, isBare = false) {
195
+ let ptr = currI;
196
+ if (!isBare) ptr = consumeWhitespace(code, currI + 1);
197
+ if (!code.startsWith("switch", ptr)) return null;
198
+ ptr += 6;
199
+ ptr = consumeWhitespace(code, ptr);
200
+ const condRes = extractCondition(code, ptr);
201
+ if (!condRes) return null;
202
+ const cond = condRes.cond;
203
+ ptr = consumeWhitespace(code, condRes.end);
204
+ if (code[ptr] !== "{") return null;
205
+ const block = parseBlock(code, ptr);
206
+ if (!block) return null;
207
+ const rawContent = code.substring(block.start + 1, block.end);
208
+ const transformedInner = transform(rawContent, 0);
209
+ const finalContent = transformedInner.replace(/(case\s+.*?:|default:)([\s\S]*?)(?=case\s+.*?:|default:|$)/g, (m, label, body) => {
210
+ const trimmed = body.trim();
211
+ if (!trimmed) return m;
212
+ if (trimmed.startsWith("return ")) return m;
213
+ return `${label} return (<Fragment>${body}</Fragment>);`;
214
+ });
215
+ let endIdx = block.end + 1;
216
+ if (!isBare) {
217
+ endIdx = consumeWhitespace(code, endIdx);
218
+ if (code[endIdx] !== "}") return null;
219
+ endIdx++;
220
+ }
221
+ const replacement = `{function() { __ROUND_SWITCH_TOKEN__(${cond}) { ${finalContent} } }}`;
222
+ return { end: endIdx, replacement };
161
223
  }
162
- let prev = null;
163
- while (prev !== result) {
164
- prev = result;
165
- while (true) {
166
- const match = result.match(/\{\s*if\s*\(/);
167
- if (!match) break;
168
- const matchIndex = match.index;
169
- const parsed = parseIfExpression(result, matchIndex);
170
- if (!parsed) {
171
- console.warn("Unbalanced IF expression found, skipping transformation.");
172
- break;
224
+ let inSingle = false, inDouble = false, inTemplate = false;
225
+ let inCommentLine = false, inCommentMulti = false;
226
+ while (i < code.length) {
227
+ const ch = code[i];
228
+ const next = i < code.length - 1 ? code[i + 1] : "";
229
+ const prev = i > 0 ? code[i - 1] : "";
230
+ if (inCommentLine) {
231
+ result += ch;
232
+ if (ch === "\n" || ch === "\r") inCommentLine = false;
233
+ i++;
234
+ continue;
235
+ }
236
+ if (inCommentMulti) {
237
+ result += ch;
238
+ if (ch === "*" && next === "/") {
239
+ inCommentMulti = false;
240
+ result += "/";
241
+ i += 2;
242
+ continue;
173
243
  }
174
- const before = result.substring(0, parsed.start);
175
- const after = result.substring(parsed.end);
176
- result = before + parsed.replacement + after;
244
+ i++;
245
+ continue;
177
246
  }
178
- while (true) {
179
- const match = result.match(/(^|[\n\r])\s*if\s*\(/m);
180
- if (!match) break;
181
- const ifIndex = match.index + match[0].lastIndexOf("if");
182
- const parsed = parseIfStatement(result, ifIndex);
183
- if (!parsed) break;
184
- const before = result.substring(0, parsed.start);
185
- const after = result.substring(parsed.end);
186
- result = before + parsed.replacement + after;
247
+ if (inTemplate) {
248
+ result += ch;
249
+ if (ch === "`" && prev !== "\\") inTemplate = false;
250
+ i++;
251
+ continue;
187
252
  }
188
- while (true) {
189
- const match = result.match(/\{\s*for\s*\((.*?)\s+in\s+(.*?)\)\s*\{/);
190
- if (!match) break;
191
- const item = match[1];
192
- const list = match[2];
193
- const exprStart = match.index;
194
- const outer = parseBlock(result, exprStart);
195
- if (!outer) break;
196
- let i = consumeWhitespace(result, exprStart + 1);
197
- const head = result.slice(i);
198
- const mm = head.match(/^for\s*\((.*?)\s+in\s+(.*?)\)\s*\{/);
199
- if (!mm) break;
200
- const forStart = i;
201
- const blockStart = forStart + mm[0].length - 1;
202
- const block = parseBlock(result, blockStart);
203
- if (!block) break;
204
- const content = result.substring(block.start + 1, block.end);
205
- const replacement = `{(() => ${list}.map(${item} => (<Fragment>${content}</Fragment>)))}`;
206
- const before = result.substring(0, exprStart);
207
- const after = result.substring(outer.end + 1);
208
- result = before + replacement + after;
253
+ if (inSingle) {
254
+ result += ch;
255
+ if (ch === "'" && prev !== "\\") inSingle = false;
256
+ i++;
257
+ continue;
209
258
  }
210
- while (true) {
211
- const match = result.match(/(^|[\n\r])\s*for\s*\((.*?)\s+in\s+(.*?)\)\s*\{/m);
212
- if (!match) break;
213
- const exprStart = match.index + match[0].lastIndexOf("for");
214
- const item = match[2];
215
- const list = match[3];
216
- const forHead = result.slice(exprStart);
217
- const mm = forHead.match(/^for\s*\((.*?)\s+in\s+(.*?)\)\s*\{/);
218
- if (!mm) break;
219
- const blockStart = exprStart + mm[0].length - 1;
220
- const block = parseBlock(result, blockStart);
221
- if (!block) break;
222
- const content = result.substring(block.start + 1, block.end);
223
- const replacement = `{(() => ${list}.map(${item} => (<Fragment>${content}</Fragment>)))}`;
224
- const before = result.substring(0, exprStart);
225
- const after = result.substring(block.end + 1);
226
- result = before + replacement + after;
259
+ if (inDouble) {
260
+ result += ch;
261
+ if (ch === '"' && prev !== "\\") inDouble = false;
262
+ i++;
263
+ continue;
227
264
  }
228
- while (true) {
229
- const match = result.match(/\{\s*switch\s*\(/);
230
- if (!match) break;
231
- const exprStart = match.index;
232
- const outer = parseBlock(result, exprStart);
233
- if (!outer) break;
234
- let i = consumeWhitespace(result, exprStart + 1);
235
- const head = result.slice(i);
236
- const mm = head.match(/^switch\s*\((.*?)\)\s*\{/);
237
- if (!mm) break;
238
- const cond = mm[1];
239
- const blockStart = i + mm[0].length - 1;
240
- const block = parseBlock(result, blockStart);
241
- if (!block) break;
242
- const content = result.substring(block.start + 1, block.end);
243
- const transformedContent = content.replace(/(case\s+.*?:|default:)([\s\S]*?)(?=case\s+.*?:|default:|$)/g, (m, label, body) => {
244
- const trimmedBody = body.trim();
245
- if (!trimmedBody) return m;
246
- if (trimmedBody.startsWith("return ")) return m;
247
- return `${label} return (<Fragment>${body}</Fragment>);`;
248
- });
249
- const replacement = `{(() => { __ROUND_SWITCH__(${cond}) { ${transformedContent} } })}`;
250
- const before = result.substring(0, exprStart);
251
- const after = result.substring(outer.end + 1);
252
- result = before + replacement + after;
265
+ if (ch === "/" && next === "/") {
266
+ inCommentLine = true;
267
+ result += "//";
268
+ i += 2;
269
+ continue;
253
270
  }
254
- while (true) {
255
- const match = result.match(/(^|[\n\r])\s*switch\s*\(/m);
256
- if (!match) break;
257
- const switchStart = match.index + match[0].lastIndexOf("switch");
258
- const head = result.slice(switchStart);
259
- const mm = head.match(/^switch\s*\((.*?)\)\s*\{/);
260
- if (!mm) break;
261
- const cond = mm[1];
262
- const blockStart = switchStart + mm[0].length - 1;
263
- const block = parseBlock(result, blockStart);
264
- if (!block) break;
265
- const content = result.substring(block.start + 1, block.end);
266
- const transformedContent = content.replace(/(case\s+.*?:|default:)([\s\S]*?)(?=case\s+.*?:|default:|$)/g, (m, label, body) => {
267
- const trimmedBody = body.trim();
268
- if (!trimmedBody) return m;
269
- if (trimmedBody.startsWith("return ")) return m;
270
- return `${label} return (<Fragment>${body}</Fragment>);`;
271
- });
272
- const replacement = `{(() => { __ROUND_SWITCH__(${cond}) { ${transformedContent} } })}`;
273
- const before = result.substring(0, switchStart);
274
- const after = result.substring(block.end + 1);
275
- result = before + replacement + after;
271
+ if (ch === "/" && next === "*") {
272
+ inCommentMulti = true;
273
+ result += "/*";
274
+ i += 2;
275
+ continue;
276
+ }
277
+ if (ch === "`") {
278
+ inTemplate = true;
279
+ result += ch;
280
+ i++;
281
+ continue;
276
282
  }
283
+ if (ch === "'") {
284
+ inSingle = true;
285
+ result += ch;
286
+ i++;
287
+ continue;
288
+ }
289
+ if (ch === '"') {
290
+ inDouble = true;
291
+ result += ch;
292
+ i++;
293
+ continue;
294
+ }
295
+ if (ch === "<") {
296
+ const isTag = /[a-zA-Z0-9_$]/.test(next) || next === ">";
297
+ if (isTag) jsxDepth++;
298
+ }
299
+ if (ch === "<" && next === "/") {
300
+ if (jsxDepth > 0) jsxDepth--;
301
+ }
302
+ if (ch === "/" && next === ">") {
303
+ if (jsxDepth > 0) jsxDepth--;
304
+ }
305
+ if (jsxDepth > 0) {
306
+ let processed = false;
307
+ if (ch === "{") {
308
+ let ptr = consumeWhitespace(code, i + 1);
309
+ if (code.startsWith("if", ptr)) {
310
+ const res = handleIf(i, false);
311
+ if (res) {
312
+ result += res.replacement;
313
+ i = res.end;
314
+ processed = true;
315
+ }
316
+ } else if (code.startsWith("for", ptr)) {
317
+ const res = handleFor(i, false);
318
+ if (res) {
319
+ result += res.replacement;
320
+ i = res.end;
321
+ processed = true;
322
+ }
323
+ } else if (code.startsWith("switch", ptr)) {
324
+ const res = handleSwitch(i, false);
325
+ if (res) {
326
+ result += res.replacement;
327
+ i = res.end;
328
+ processed = true;
329
+ }
330
+ }
331
+ } else if (ch === "i" && code.startsWith("if", i)) {
332
+ let ptr = consumeWhitespace(code, i + 2);
333
+ if (code[ptr] === "(") {
334
+ const res = handleIf(i, true);
335
+ if (res) {
336
+ result += res.replacement;
337
+ i = res.end;
338
+ processed = true;
339
+ }
340
+ }
341
+ } else if (ch === "f" && code.startsWith("for", i)) {
342
+ let ptr = consumeWhitespace(code, i + 3);
343
+ if (code[ptr] === "(") {
344
+ const res = handleFor(i, true);
345
+ if (res) {
346
+ result += res.replacement;
347
+ i = res.end;
348
+ processed = true;
349
+ }
350
+ }
351
+ } else if (ch === "s" && code.startsWith("switch", i)) {
352
+ let ptr = consumeWhitespace(code, i + 6);
353
+ if (code[ptr] === "(") {
354
+ const res = handleSwitch(i, true);
355
+ if (res) {
356
+ result += res.replacement;
357
+ i = res.end;
358
+ processed = true;
359
+ }
360
+ }
361
+ }
362
+ if (processed) continue;
363
+ }
364
+ result += ch;
365
+ i++;
277
366
  }
278
367
  function findJsxTagEnd(str, startIndex) {
279
- let inSingle = false;
280
- let inDouble = false;
281
- let inTemplate = false;
368
+ let inSingle2 = false, inDouble2 = false, inTemplate2 = false;
282
369
  let braceDepth = 0;
283
- for (let i = startIndex; i < str.length; i++) {
284
- const ch = str[i];
285
- const prevCh = i > 0 ? str[i - 1] : "";
286
- if (!inDouble && !inTemplate && ch === "'" && prevCh !== "\\") inSingle = !inSingle;
287
- else if (!inSingle && !inTemplate && ch === '"' && prevCh !== "\\") inDouble = !inDouble;
288
- else if (!inSingle && !inDouble && ch === "`" && prevCh !== "\\") inTemplate = !inTemplate;
289
- if (inSingle || inDouble || inTemplate) continue;
290
- if (ch === "{") braceDepth++;
291
- else if (ch === "}") braceDepth = Math.max(0, braceDepth - 1);
292
- else if (ch === ">" && braceDepth === 0) return i;
370
+ for (let k = startIndex; k < str.length; k++) {
371
+ const c = str[k];
372
+ const p = k > 0 ? str[k - 1] : "";
373
+ if (!inDouble2 && !inTemplate2 && c === "'" && p !== "\\") inSingle2 = !inSingle2;
374
+ else if (!inSingle2 && !inTemplate2 && c === '"' && p !== "\\") inDouble2 = !inDouble2;
375
+ else if (!inSingle2 && !inDouble2 && c === "`" && p !== "\\") inTemplate2 = !inTemplate2;
376
+ if (inSingle2 || inDouble2 || inTemplate2) continue;
377
+ if (c === "{") braceDepth++;
378
+ else if (c === "}") braceDepth = Math.max(0, braceDepth - 1);
379
+ else if (c === ">" && braceDepth === 0) return k;
293
380
  }
294
381
  return -1;
295
382
  }
@@ -306,38 +393,25 @@ function transform(code) {
306
393
  cursor = openEnd + 1;
307
394
  continue;
308
395
  }
309
- let depth = 1;
310
- let i = openEnd + 1;
311
- let closeStart = -1;
312
- while (i < out.length) {
313
- const nextOpen = out.indexOf("<Suspense", i);
314
- const nextClose = out.indexOf("</Suspense>", i);
315
- if (nextClose === -1) break;
316
- if (nextOpen !== -1 && nextOpen < nextClose) {
317
- const innerOpenEnd = findJsxTagEnd(out, nextOpen);
318
- if (innerOpenEnd === -1) break;
319
- const innerOpenText = out.slice(nextOpen, innerOpenEnd + 1);
320
- if (!/\/>\s*$/.test(innerOpenText)) depth++;
321
- i = innerOpenEnd + 1;
322
- continue;
323
- }
324
- depth--;
325
- if (depth === 0) {
326
- closeStart = nextClose;
327
- break;
328
- }
329
- i = nextClose + "</Suspense>".length;
396
+ let depth = 1, k = openEnd + 1, closeStart = -1;
397
+ while (k < out.length) {
398
+ if (out.slice(k).startsWith("<Suspense")) {
399
+ depth++;
400
+ k += 9;
401
+ } else if (out.slice(k).startsWith("</Suspense>")) {
402
+ depth--;
403
+ if (depth === 0) {
404
+ closeStart = k;
405
+ break;
406
+ }
407
+ k += 11;
408
+ } else k++;
330
409
  }
331
410
  if (closeStart === -1) break;
332
411
  const inner = out.slice(openEnd + 1, closeStart);
333
- const innerTrim = inner.trim();
334
- if (innerTrim.startsWith("{() =>")) {
335
- cursor = closeStart + "</Suspense>".length;
336
- continue;
337
- }
338
- const wrapped = `{() => (<Fragment>${inner}</Fragment>)}`;
412
+ const wrapped = `{(() => (<Fragment>${inner}</Fragment>))}`;
339
413
  out = out.slice(0, openEnd + 1) + wrapped + out.slice(closeStart);
340
- cursor = closeStart + wrapped.length + "</Suspense>".length;
414
+ cursor = closeStart + wrapped.length + 11;
341
415
  }
342
416
  return out;
343
417
  }
@@ -351,48 +425,39 @@ function transform(code) {
351
425
  if (lt === -1) break;
352
426
  const openEnd = findJsxTagEnd(out, lt);
353
427
  if (openEnd === -1) break;
354
- const openTagText = out.slice(lt, openEnd + 1);
355
- if (/\/>\s*$/.test(openTagText)) {
428
+ const tagText = out.slice(lt, openEnd + 1);
429
+ if (/\/>\s*$/.test(tagText)) {
356
430
  cursor = openEnd + 1;
357
431
  continue;
358
432
  }
359
- const m = openTagText.match(/^<\s*([A-Za-z_$][\w$]*\.Provider)\b/);
433
+ const m = tagText.match(/^<\s*([A-Za-z_$][\w$]*\.Provider)\b/);
360
434
  if (!m) {
361
435
  cursor = openEnd + 1;
362
436
  continue;
363
437
  }
364
438
  const tagName = m[1];
365
439
  const closeTag = `</${tagName}>`;
366
- let depth = 1;
367
- let i = openEnd + 1;
368
- let closeStart = -1;
369
- while (i < out.length) {
370
- const nextOpen = out.indexOf(`<${tagName}`, i);
371
- const nextClose = out.indexOf(closeTag, i);
372
- if (nextClose === -1) break;
373
- if (nextOpen !== -1 && nextOpen < nextClose) {
374
- const innerOpenEnd = findJsxTagEnd(out, nextOpen);
375
- if (innerOpenEnd === -1) break;
376
- const innerOpenText = out.slice(nextOpen, innerOpenEnd + 1);
377
- if (!/\/>\s*$/.test(innerOpenText)) depth++;
378
- i = innerOpenEnd + 1;
440
+ let depth = 1, k = openEnd + 1, closeStart = -1;
441
+ while (k < out.length) {
442
+ const nOpen = out.indexOf(`<${tagName}`, k);
443
+ const nClose = out.indexOf(closeTag, k);
444
+ if (nClose === -1) break;
445
+ if (nOpen !== -1 && nOpen < nClose) {
446
+ const innerEnd = findJsxTagEnd(out, nOpen);
447
+ if (innerEnd !== -1 && !/\/>\s*$/.test(out.slice(nOpen, innerEnd + 1))) depth++;
448
+ k = innerEnd + 1;
379
449
  continue;
380
450
  }
381
451
  depth--;
382
452
  if (depth === 0) {
383
- closeStart = nextClose;
453
+ closeStart = nClose;
384
454
  break;
385
455
  }
386
- i = nextClose + closeTag.length;
456
+ k = nClose + closeTag.length;
387
457
  }
388
458
  if (closeStart === -1) break;
389
459
  const inner = out.slice(openEnd + 1, closeStart);
390
- const innerTrim = inner.trim();
391
- if (innerTrim.startsWith("{() =>")) {
392
- cursor = closeStart + closeTag.length;
393
- continue;
394
- }
395
- const wrapped = `{() => (<Fragment>${inner}</Fragment>)}`;
460
+ const wrapped = `{(() => (<Fragment>${inner}</Fragment>))}`;
396
461
  out = out.slice(0, openEnd + 1) + wrapped + out.slice(closeStart);
397
462
  cursor = closeStart + wrapped.length + closeTag.length;
398
463
  }
@@ -401,7 +466,7 @@ function transform(code) {
401
466
  result = transformSuspenseBlocks(result);
402
467
  result = transformProviderBlocks(result);
403
468
  result = result.replace(/\{\s*([A-Za-z_$][\w$]*)\s*\(\s*\)\s*\}/g, "{() => $1()}").replace(/=\{\s*([A-Za-z_$][\w$]*)\s*\(\s*\)\s*\}/g, "={() => $1()}");
404
- return result.replace(/__ROUND_SWITCH__/g, "switch");
469
+ return result.replace(/__ROUND_SWITCH_TOKEN__/g, "switch");
405
470
  }
406
471
  function normalizePath(p) {
407
472
  return p.replaceAll("\\", "/");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "round-core",
3
- "version": "0.0.9",
3
+ "version": "0.1.1",
4
4
  "description": "A lightweight frontend framework for SPA with signals and fine grained reactivity",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",