@nocturnium/svelte-ide 1.0.1 → 1.0.2
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.
|
@@ -45,8 +45,19 @@ export declare class JavaScriptTokenizer {
|
|
|
45
45
|
*/
|
|
46
46
|
private tryMatchRegex;
|
|
47
47
|
private tokenizeString;
|
|
48
|
-
|
|
49
|
-
|
|
48
|
+
/**
|
|
49
|
+
* Scan the string portion of a template literal, starting at `startPos`. Emits
|
|
50
|
+
* one `string.template` token for the run of literal characters and stops at one
|
|
51
|
+
* of three boundaries:
|
|
52
|
+
* - a closing backtick → ends the literal (clears template state);
|
|
53
|
+
* - a `${` → emits the `${` delimiter and enters interpolation
|
|
54
|
+
* (templateDepth = 1) so the expression is tokenized as code by the caller;
|
|
55
|
+
* - end of line → the literal spans lines and continues next line.
|
|
56
|
+
*
|
|
57
|
+
* `isStart` is true when this is the opening backtick (vs. a continuation of a
|
|
58
|
+
* multi-line literal or the resumption after a `${…}` interpolation).
|
|
59
|
+
*/
|
|
60
|
+
private scanTemplateString;
|
|
50
61
|
private tokenizeJSXTag;
|
|
51
62
|
}
|
|
52
63
|
export declare function createJavaScriptTokenizer(): JavaScriptTokenizer;
|
|
@@ -263,22 +263,39 @@ export class JavaScriptTokenizer {
|
|
|
263
263
|
return { lineNumber, tokens, text: line, state };
|
|
264
264
|
}
|
|
265
265
|
}
|
|
266
|
-
// Handle template literal continuation
|
|
267
|
-
if (state.inTemplateLiteral && (state.templateDepth ?? 0) > 0) {
|
|
268
|
-
const result = this.tokenizeTemplateLiteralContinuation(line, pos, state);
|
|
269
|
-
tokens.push(...result.tokens);
|
|
270
|
-
pos = result.pos;
|
|
271
|
-
if (pos >= line.length) {
|
|
272
|
-
return { lineNumber, tokens, text: line, state };
|
|
273
|
-
}
|
|
274
|
-
}
|
|
275
266
|
while (pos < line.length) {
|
|
267
|
+
// Template literals: scan the string portion (between the backticks and
|
|
268
|
+
// `${` / `}`) as a single string.template token. The interpolation
|
|
269
|
+
// expression is tokenized as ordinary code below, tracking brace depth in
|
|
270
|
+
// state.templateDepth so the closing backtick is recognised. This fixes the
|
|
271
|
+
// leak where an unclosed template state bled onto every following line.
|
|
272
|
+
const inStringPortion = state.inTemplateLiteral && (state.templateDepth ?? 0) === 0;
|
|
273
|
+
const startsTemplate = !state.inTemplateLiteral && line[pos] === '`';
|
|
274
|
+
if (inStringPortion || startsTemplate) {
|
|
275
|
+
const result = this.scanTemplateString(line, pos, state, startsTemplate);
|
|
276
|
+
tokens.push(...result.tokens);
|
|
277
|
+
pos = result.pos;
|
|
278
|
+
continue;
|
|
279
|
+
}
|
|
276
280
|
const remaining = line.slice(pos);
|
|
277
281
|
const token = this.getNextToken(remaining, pos, state);
|
|
278
282
|
if (token) {
|
|
279
283
|
tokens.push(token);
|
|
280
284
|
this.updateLastToken(token, state);
|
|
281
285
|
pos = token.end;
|
|
286
|
+
// Track brace nesting inside a ${...} interpolation so we know when it
|
|
287
|
+
// closes and we return to the template's string portion. Braces inside
|
|
288
|
+
// strings/comments are separate token types, so they aren't miscounted.
|
|
289
|
+
if (state.inTemplateLiteral &&
|
|
290
|
+
(state.templateDepth ?? 0) > 0 &&
|
|
291
|
+
token.type === 'punctuation.brace') {
|
|
292
|
+
if (token.text === '{') {
|
|
293
|
+
state.templateDepth = (state.templateDepth ?? 0) + 1;
|
|
294
|
+
}
|
|
295
|
+
else if (token.text === '}') {
|
|
296
|
+
state.templateDepth = Math.max(0, (state.templateDepth ?? 1) - 1);
|
|
297
|
+
}
|
|
298
|
+
}
|
|
282
299
|
}
|
|
283
300
|
else {
|
|
284
301
|
// No match - shouldn't happen but handle gracefully
|
|
@@ -314,10 +331,10 @@ export class JavaScriptTokenizer {
|
|
|
314
331
|
return createToken('comment.block', text, pos);
|
|
315
332
|
}
|
|
316
333
|
}
|
|
317
|
-
// Template literals
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
334
|
+
// Template literals are handled in tokenizeLine's main loop
|
|
335
|
+
// (scanTemplateString) so the string portions and the ${...} interpolation
|
|
336
|
+
// expression are tokenized separately. A backtick only reaches here while
|
|
337
|
+
// inside an interpolation (a nested template); fall through to consume it.
|
|
321
338
|
// Regular strings
|
|
322
339
|
if (text.startsWith('"') || text.startsWith("'")) {
|
|
323
340
|
return this.tokenizeString(text, pos, text[0]);
|
|
@@ -552,59 +569,55 @@ export class JavaScriptTokenizer {
|
|
|
552
569
|
// Unterminated string at end of line
|
|
553
570
|
return createToken('string', text, pos);
|
|
554
571
|
}
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
if (text[i] === '$' && text[i + 1] === '{') {
|
|
569
|
-
// Template expression - for simplicity, tokenize up to this point
|
|
570
|
-
if (result.length > 1) {
|
|
571
|
-
// Return string part first
|
|
572
|
-
state.inTemplateLiteral = true;
|
|
573
|
-
state.templateDepth = (state.templateDepth ?? 0) + 1;
|
|
574
|
-
return createToken('string.template', result, pos);
|
|
575
|
-
}
|
|
576
|
-
}
|
|
577
|
-
result += text[i];
|
|
578
|
-
i++;
|
|
579
|
-
}
|
|
580
|
-
// Multi-line template literal
|
|
581
|
-
state.inTemplateLiteral = true;
|
|
582
|
-
return createToken('string.template', result, pos);
|
|
583
|
-
}
|
|
584
|
-
tokenizeTemplateLiteralContinuation(line, startPos, state) {
|
|
585
|
-
const tokens = [];
|
|
572
|
+
/**
|
|
573
|
+
* Scan the string portion of a template literal, starting at `startPos`. Emits
|
|
574
|
+
* one `string.template` token for the run of literal characters and stops at one
|
|
575
|
+
* of three boundaries:
|
|
576
|
+
* - a closing backtick → ends the literal (clears template state);
|
|
577
|
+
* - a `${` → emits the `${` delimiter and enters interpolation
|
|
578
|
+
* (templateDepth = 1) so the expression is tokenized as code by the caller;
|
|
579
|
+
* - end of line → the literal spans lines and continues next line.
|
|
580
|
+
*
|
|
581
|
+
* `isStart` is true when this is the opening backtick (vs. a continuation of a
|
|
582
|
+
* multi-line literal or the resumption after a `${…}` interpolation).
|
|
583
|
+
*/
|
|
584
|
+
scanTemplateString(line, startPos, state, isStart) {
|
|
586
585
|
let pos = startPos;
|
|
587
586
|
let result = '';
|
|
587
|
+
if (isStart) {
|
|
588
|
+
state.inTemplateLiteral = true;
|
|
589
|
+
state.templateDepth = 0;
|
|
590
|
+
result = '`';
|
|
591
|
+
pos += 1;
|
|
592
|
+
}
|
|
588
593
|
while (pos < line.length) {
|
|
589
|
-
|
|
594
|
+
const ch = line[pos];
|
|
595
|
+
if (ch === '\\' && pos + 1 < line.length) {
|
|
590
596
|
result += line.slice(pos, pos + 2);
|
|
591
597
|
pos += 2;
|
|
592
598
|
continue;
|
|
593
599
|
}
|
|
594
|
-
if (
|
|
600
|
+
if (ch === '`') {
|
|
595
601
|
result += '`';
|
|
596
|
-
tokens.push(createToken('string.template', result, startPos));
|
|
597
602
|
state.inTemplateLiteral = false;
|
|
598
|
-
state.templateDepth =
|
|
599
|
-
return { tokens, pos: pos + 1 };
|
|
603
|
+
state.templateDepth = 0;
|
|
604
|
+
return { tokens: [createToken('string.template', result, startPos)], pos: pos + 1 };
|
|
600
605
|
}
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
+
if (ch === '$' && line[pos + 1] === '{') {
|
|
607
|
+
const tokens = [];
|
|
608
|
+
if (result) {
|
|
609
|
+
tokens.push(createToken('string.template', result, startPos));
|
|
610
|
+
}
|
|
611
|
+
tokens.push(createToken('string.template', '${', startPos + result.length));
|
|
612
|
+
state.templateDepth = 1;
|
|
613
|
+
return { tokens, pos: pos + 2 };
|
|
614
|
+
}
|
|
615
|
+
result += ch;
|
|
616
|
+
pos += 1;
|
|
606
617
|
}
|
|
607
|
-
|
|
618
|
+
// End of line inside the string portion → multi-line template literal.
|
|
619
|
+
state.inTemplateLiteral = true;
|
|
620
|
+
return { tokens: result ? [createToken('string.template', result, startPos)] : [], pos };
|
|
608
621
|
}
|
|
609
622
|
tokenizeJSXTag(text, pos, _state) {
|
|
610
623
|
// Simple JSX tag detection
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nocturnium/svelte-ide",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.2",
|
|
4
4
|
"description": "Svelte 5 code editor and IDE building blocks — custom editor, syntax highlighting, code folding, multi-cursor, LSP client, and optional realtime collaboration.",
|
|
5
5
|
"author": "Nocturnium & Jordan Dziat <hello@nocturnium.ai> (https://nocturnium.ai)",
|
|
6
6
|
"license": "MIT",
|