@ttsc/playground 0.19.3 → 0.20.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.
Files changed (44) hide show
  1. package/README.md +6 -0
  2. package/lib/src/npm/collectExternalPackageNames.js +436 -73
  3. package/lib/src/npm/collectExternalPackageNames.js.map +1 -1
  4. package/lib/src/npm/installPlaygroundDependencies.d.ts +5 -3
  5. package/lib/src/npm/installPlaygroundDependencies.js +230 -27
  6. package/lib/src/npm/installPlaygroundDependencies.js.map +1 -1
  7. package/lib/src/npm/internal/npmRegistry.d.ts +13 -2
  8. package/lib/src/npm/internal/npmRegistry.js +73 -50
  9. package/lib/src/npm/internal/npmRegistry.js.map +1 -1
  10. package/lib/src/npm/packageNameFromSpecifier.js +17 -4
  11. package/lib/src/npm/packageNameFromSpecifier.js.map +1 -1
  12. package/lib/src/react/PlaygroundShell.js +68 -61
  13. package/lib/src/react/PlaygroundShell.js.map +1 -1
  14. package/lib/src/react/createCompilerClient.d.ts +3 -3
  15. package/lib/src/react/createCompilerClient.js +32 -54
  16. package/lib/src/react/createCompilerClient.js.map +1 -1
  17. package/lib/src/sandbox/createSandboxRequire.js +117 -54
  18. package/lib/src/sandbox/createSandboxRequire.js.map +1 -1
  19. package/lib/src/structures/IPlaygroundDependencyInstallOptions.d.ts +13 -1
  20. package/lib/src/structures/IPlaygroundDependencyInstallResult.d.ts +4 -0
  21. package/lib/src/structures/IPlaygroundDependencyPackage.d.ts +2 -0
  22. package/lib/src/structures/IPlaygroundDependencyRequest.d.ts +9 -0
  23. package/lib/src/structures/IPlaygroundDependencyRequest.js +3 -0
  24. package/lib/src/structures/IPlaygroundDependencyRequest.js.map +1 -0
  25. package/lib/src/structures/IPlaygroundInstalledDependency.d.ts +12 -0
  26. package/lib/src/structures/IPlaygroundInstalledDependency.js +3 -0
  27. package/lib/src/structures/IPlaygroundInstalledDependency.js.map +1 -0
  28. package/lib/src/structures/index.d.ts +2 -0
  29. package/lib/src/structures/index.js +2 -0
  30. package/lib/src/structures/index.js.map +1 -1
  31. package/package.json +6 -4
  32. package/src/npm/collectExternalPackageNames.ts +503 -68
  33. package/src/npm/installPlaygroundDependencies.ts +288 -29
  34. package/src/npm/internal/npmRegistry.ts +99 -38
  35. package/src/npm/packageNameFromSpecifier.ts +16 -3
  36. package/src/react/PlaygroundShell.tsx +86 -72
  37. package/src/react/createCompilerClient.ts +37 -51
  38. package/src/sandbox/createSandboxRequire.ts +140 -49
  39. package/src/structures/IPlaygroundDependencyInstallOptions.ts +13 -1
  40. package/src/structures/IPlaygroundDependencyInstallResult.ts +4 -0
  41. package/src/structures/IPlaygroundDependencyPackage.ts +2 -0
  42. package/src/structures/IPlaygroundDependencyRequest.ts +9 -0
  43. package/src/structures/IPlaygroundInstalledDependency.ts +13 -0
  44. package/src/structures/index.ts +2 -0
package/README.md CHANGED
@@ -127,6 +127,8 @@ The typia pack itself is built by the site (typically with a `pack-typia-sources
127
127
 
128
128
  When the user types `import {v4} from "uuid"`, the shell auto-fetches `uuid` (and its transitive deps) from the npm registry, unpacks the tgz in the browser, and mounts the files into the wasm MemFS, no proxy server needed.
129
129
 
130
+ Discovery covers static quoted specifiers in imports, exports, dynamic imports, `require(...)`, and direct `require?.(...)` calls, using their cooked JavaScript string values while ignoring comments, regular expressions, template quasis, and computed arguments.
131
+
130
132
  ```ts
131
133
  import {
132
134
  collectExternalPackageNames,
@@ -140,6 +142,10 @@ const installed = await installPlaygroundDependencies(names, {
140
142
  // mount installed.compilerFiles into the wasm MemFS via service.installDependencies
141
143
  ```
142
144
 
145
+ For an additive edit, pass the prior call's `resolvedDependencies` as `installedDependencies`; the installer validates every new range against the mounted registry identity and exact version, and it returns only newly downloaded tarballs in `packages` plus the complete updated exact state in `resolvedDependencies`.
146
+
147
+ When a direct source import is removed, solve the complete current root list without `installedDependencies` and atomically replace the compiler, editor, and runtime file maps so files from the obsolete graph cannot survive.
148
+
143
149
  `PlaygroundShell` wires this automatically on every keystroke, debounced 900 ms, with an abort signal on source change.
144
150
 
145
151
  ## Tailwind setup
@@ -20,7 +20,7 @@ function collectExternalPackageNames(source, ignoredPackages = BUILT_IN_PLAYGROU
20
20
  /**
21
21
  * Collect the string specifiers of every executable module-loading construct in
22
22
  * `source`: `import`/`export ... from`, side-effect `import "x"`, dynamic
23
- * `import("x")`, and `require("x")` calls.
23
+ * `import("x")`, `require("x")`, and `require?.("x")` calls.
24
24
  *
25
25
  * The scan tokenizes `source` first so import/export/require lookalikes that
26
26
  * live inside comments, string or template contents, or regular-expression
@@ -34,7 +34,10 @@ function collectModuleSpecifiers(source) {
34
34
  const out = [];
35
35
  const asString = (token) => token && token.kind === "string" ? token.value : null;
36
36
  const isOpenParen = (token) => token !== undefined && token.kind === "punct" && token.value === "(";
37
- const isMemberAccess = (token) => token !== undefined && token.kind === "punct" && token.value === ".";
37
+ const isMemberAccess = (token) => token !== undefined &&
38
+ token.kind === "punct" &&
39
+ (token.value === "." || token.value === "?.");
40
+ const isOptionalChain = (token) => token !== undefined && token.kind === "punct" && token.value === "?.";
38
41
  for (let i = 0; i < tokens.length; i++) {
39
42
  const token = tokens[i];
40
43
  if (!token || token.kind !== "word")
@@ -43,8 +46,9 @@ function collectModuleSpecifiers(source) {
43
46
  // `obj.require(...)` is an unrelated method call, not CommonJS require.
44
47
  if (isMemberAccess(tokens[i - 1]))
45
48
  continue;
46
- if (isOpenParen(tokens[i + 1])) {
47
- const spec = asString(tokens[i + 2]);
49
+ const optional = isOptionalChain(tokens[i + 1]) && isOpenParen(tokens[i + 2]);
50
+ if (isOpenParen(tokens[i + 1]) || optional) {
51
+ const spec = asString(tokens[i + (optional ? 3 : 2)]);
48
52
  if (spec !== null)
49
53
  out.push(spec);
50
54
  }
@@ -114,11 +118,159 @@ const REGEX_PRECEDING_KEYWORDS = new Set([
114
118
  "void",
115
119
  "do",
116
120
  "else",
121
+ "extends",
117
122
  "yield",
118
123
  "await",
119
124
  "case",
120
125
  "throw",
121
126
  ]);
127
+ const CONTROL_HEADER_KEYWORDS = new Set([
128
+ "if",
129
+ "while",
130
+ "for",
131
+ "with",
132
+ "switch",
133
+ "catch",
134
+ ]);
135
+ const BLOCK_PRECEDING_KEYWORDS = new Set(["else", "try", "finally", "do"]);
136
+ /**
137
+ * Retain just enough delimiter context to distinguish a regex statement after a
138
+ * control header or block from division after an expression value. The
139
+ * collector is not a parser: this state only decides whether a following slash
140
+ * is opaque regex text or executable code worth scanning for module calls.
141
+ */
142
+ class LexicalContext {
143
+ tokens = [];
144
+ parens = [];
145
+ braces = [];
146
+ pendingFunctionExpression;
147
+ pendingClassExpressions = [];
148
+ isRegexAllowed() {
149
+ return isRegexAllowedAfter(this.tokens[this.tokens.length - 1]);
150
+ }
151
+ pushWord(value) {
152
+ if (value === "function" &&
153
+ !isMemberAccess(this.tokens[this.tokens.length - 1]))
154
+ this.pendingFunctionExpression = isExpressionPosition(this.tokens);
155
+ else if (value === "class" &&
156
+ !isMemberAccess(this.tokens[this.tokens.length - 1]))
157
+ this.pendingClassExpressions.push(isExpressionPosition(this.tokens));
158
+ this.tokens.push({ kind: "word", value });
159
+ }
160
+ pushOther() {
161
+ this.tokens.push({ kind: "other" });
162
+ }
163
+ pushPunct(value) {
164
+ if (value === ":") {
165
+ const previous = this.tokens[this.tokens.length - 1];
166
+ if (previous?.kind === "word" &&
167
+ !isMemberAccess(this.tokens[this.tokens.length - 2])) {
168
+ if (previous.value === "function")
169
+ this.pendingFunctionExpression = undefined;
170
+ else if (previous.value === "class")
171
+ this.pendingClassExpressions.pop();
172
+ }
173
+ }
174
+ if (value === "(") {
175
+ const functionIsExpression = this.pendingFunctionExpression;
176
+ this.pendingFunctionExpression = undefined;
177
+ this.parens.push(functionIsExpression === undefined
178
+ ? {
179
+ kind: isControlHeader(this.tokens) ? "control" : "normal",
180
+ }
181
+ : { kind: "function", functionIsExpression });
182
+ this.tokens.push({ kind: "punct", value });
183
+ return;
184
+ }
185
+ if (value === ")") {
186
+ const context = this.parens.pop();
187
+ this.tokens.push({
188
+ kind: "punct",
189
+ value,
190
+ regexAllowedAfter: context?.kind === "control",
191
+ functionBodyIsExpression: context?.kind === "function"
192
+ ? context.functionIsExpression
193
+ : undefined,
194
+ });
195
+ return;
196
+ }
197
+ if (value === "{") {
198
+ this.braces.push(this.braceAllowsRegexAfter());
199
+ this.tokens.push({ kind: "punct", value });
200
+ return;
201
+ }
202
+ if (value === "}") {
203
+ this.tokens.push({
204
+ kind: "punct",
205
+ value,
206
+ regexAllowedAfter: this.braces.pop() ?? false,
207
+ });
208
+ return;
209
+ }
210
+ this.tokens.push({ kind: "punct", value });
211
+ }
212
+ braceAllowsRegexAfter() {
213
+ const previous = this.tokens[this.tokens.length - 1];
214
+ if (previous?.kind === "punct" &&
215
+ previous.value === ")" &&
216
+ previous.functionBodyIsExpression !== undefined)
217
+ return !previous.functionBodyIsExpression;
218
+ if (this.classBodyPrecedes(previous))
219
+ return !this.pendingClassExpressions.pop();
220
+ if (!previous)
221
+ return true;
222
+ if (previous.kind === "word")
223
+ return BLOCK_PRECEDING_KEYWORDS.has(previous.value);
224
+ if (previous.kind !== "punct")
225
+ return false;
226
+ if (previous.value === ")")
227
+ return previous.regexAllowedAfter === true;
228
+ return (previous.value === ";" || previous.value === "{" || previous.value === "}");
229
+ }
230
+ classBodyPrecedes(previous) {
231
+ if (this.pendingClassExpressions.length === 0 || this.parens.length !== 0)
232
+ return false;
233
+ if (!previous)
234
+ return false;
235
+ if (previous.kind === "word" || previous.kind === "other")
236
+ return true;
237
+ return (previous.kind === "punct" &&
238
+ (previous.value === ")" ||
239
+ previous.value === "]" ||
240
+ previous.value === "}"));
241
+ }
242
+ }
243
+ function isControlHeader(tokens) {
244
+ const previous = tokens[tokens.length - 1];
245
+ const beforePrevious = tokens[tokens.length - 2];
246
+ if (previous?.kind === "word" &&
247
+ CONTROL_HEADER_KEYWORDS.has(previous.value) &&
248
+ !isMemberAccess(beforePrevious))
249
+ return true;
250
+ return (previous?.kind === "word" &&
251
+ previous.value === "await" &&
252
+ beforePrevious?.kind === "word" &&
253
+ beforePrevious.value === "for");
254
+ }
255
+ function isMemberAccess(token) {
256
+ return (token?.kind === "punct" && (token.value === "." || token.value === "?."));
257
+ }
258
+ function isExpressionPosition(tokens) {
259
+ let index = tokens.length - 1;
260
+ // `async function` inherits the context before `async`: it is a declaration
261
+ // at a statement boundary and an expression after an assignment or return.
262
+ const latest = tokens[index];
263
+ if (latest?.kind === "word" && latest.value === "async")
264
+ index--;
265
+ const previous = tokens[index];
266
+ if (!previous)
267
+ return false;
268
+ if (previous.kind === "word")
269
+ return REGEX_PRECEDING_KEYWORDS.has(previous.value);
270
+ if (previous.kind !== "punct")
271
+ return false;
272
+ return ![")", "]", "}", ";", "{", "++", "--"].includes(previous.value);
273
+ }
122
274
  /**
123
275
  * Lexically tokenize `source` into the coarse token stream the specifier
124
276
  * collector needs. Comments are dropped; strings, templates, regex literals,
@@ -126,23 +278,14 @@ const REGEX_PRECEDING_KEYWORDS = new Set([
126
278
  * grammar match.
127
279
  */
128
280
  function tokenize(source) {
129
- const tokens = [];
281
+ const context = new LexicalContext();
282
+ const tokens = context.tokens;
130
283
  const n = source.length;
131
284
  const isIdStart = (c) => (c >= "a" && c <= "z") || (c >= "A" && c <= "Z") || c === "_" || c === "$";
132
285
  const isIdPart = (c) => isIdStart(c) || (c >= "0" && c <= "9");
133
286
  const isDigit = (c) => c >= "0" && c <= "9";
134
287
  // A `/` opens a regex only in operator/statement position — never right after
135
288
  // a value (identifier, number, string, template, regex, `)` or `]`).
136
- const regexAllowed = () => {
137
- const prev = tokens[tokens.length - 1];
138
- if (!prev)
139
- return true;
140
- if (prev.kind === "string" || prev.kind === "other")
141
- return false;
142
- if (prev.kind === "word")
143
- return REGEX_PRECEDING_KEYWORDS.has(prev.value);
144
- return prev.value !== ")" && prev.value !== "]";
145
- };
146
289
  let i = 0;
147
290
  while (i < n) {
148
291
  const c = source[i];
@@ -172,83 +315,47 @@ function tokenize(source) {
172
315
  continue;
173
316
  }
174
317
  // Regular-expression literal.
175
- if (c === "/" && regexAllowed()) {
176
- i++;
177
- let inClass = false;
178
- while (i < n) {
179
- const d = source[i];
180
- if (d === "\\") {
181
- i += 2;
182
- continue;
183
- }
184
- if (d === "\n")
185
- break;
186
- if (d === "[")
187
- inClass = true;
188
- else if (d === "]")
189
- inClass = false;
190
- else if (d === "/" && !inClass) {
191
- i++;
192
- break;
193
- }
194
- i++;
195
- }
196
- while (i < n && isIdPart(source[i]))
197
- i++; // flags
198
- tokens.push({ kind: "other" });
318
+ if (c === "/" && context.isRegexAllowed()) {
319
+ i = skipRegularExpression(source, i, isIdPart);
320
+ context.pushOther();
199
321
  continue;
200
322
  }
201
323
  // String literal.
202
324
  if (c === '"' || c === "'") {
203
- i++;
204
- let value = "";
205
- while (i < n) {
206
- const d = source[i];
207
- if (d === "\\") {
208
- value += source[i + 1] ?? "";
209
- i += 2;
210
- continue;
211
- }
212
- if (d === c) {
213
- i++;
214
- break;
215
- }
216
- if (d === "\n")
217
- break; // unterminated single-line string
218
- value += d;
219
- i++;
220
- }
221
- tokens.push({ kind: "string", value });
325
+ const quoted = readQuotedString(source, i, c);
326
+ i = quoted.end;
327
+ if (quoted.value === null)
328
+ context.pushOther();
329
+ else
330
+ tokens.push({ kind: "string", value: quoted.value });
222
331
  continue;
223
332
  }
224
- // Template literal. Contents (including `${...}` expressions) are treated as
225
- // opaque: a template specifier is not statically resolvable.
333
+ // Template quasis are opaque, but `${...}` substitutions are executable
334
+ // JavaScript and must receive the same lexical treatment as top-level code.
226
335
  if (c === "`") {
227
336
  i++;
228
- let depth = 0;
229
337
  while (i < n) {
230
338
  const d = source[i];
231
339
  if (d === "\\") {
232
340
  i += 2;
233
341
  continue;
234
342
  }
235
- if (depth === 0 && d === "`") {
343
+ if (d === "`") {
236
344
  i++;
237
345
  break;
238
346
  }
239
347
  if (d === "$" && source[i + 1] === "{") {
240
- depth++;
241
- i += 2;
242
- continue;
243
- }
244
- if (depth > 0 && d === "}") {
245
- depth--;
246
- i++;
348
+ const start = i + 2;
349
+ const end = findTemplateSubstitutionEnd(source, start);
350
+ context.pushOther();
351
+ tokens.push(...tokenize(source.slice(start, end)));
352
+ context.pushOther();
353
+ i = end < n ? end + 1 : end;
247
354
  continue;
248
355
  }
249
356
  i++;
250
357
  }
251
- tokens.push({ kind: "other" });
358
+ context.pushOther();
252
359
  continue;
253
360
  }
254
361
  // Identifier / keyword.
@@ -256,7 +363,7 @@ function tokenize(source) {
256
363
  let j = i + 1;
257
364
  while (j < n && isIdPart(source[j]))
258
365
  j++;
259
- tokens.push({ kind: "word", value: source.slice(i, j) });
366
+ context.pushWord(source.slice(i, j));
260
367
  i = j;
261
368
  continue;
262
369
  }
@@ -265,14 +372,270 @@ function tokenize(source) {
265
372
  let j = i + 1;
266
373
  while (j < n && /[0-9a-fA-FxXoObBeE._]/.test(source[j]))
267
374
  j++;
268
- tokens.push({ kind: "other" });
375
+ context.pushOther();
269
376
  i = j;
270
377
  continue;
271
378
  }
379
+ // Compound punctuation whose identity affects the following slash or
380
+ // direct optional-call recognition.
381
+ if ((c === "+" || c === "-") && source[i + 1] === c) {
382
+ context.pushPunct(c + c);
383
+ i += 2;
384
+ continue;
385
+ }
386
+ if (c === "?" && source[i + 1] === "." && !isDigit(source[i + 2] ?? "")) {
387
+ context.pushPunct("?.");
388
+ i += 2;
389
+ continue;
390
+ }
272
391
  // Single punctuation character.
273
- tokens.push({ kind: "punct", value: c });
392
+ context.pushPunct(c);
274
393
  i++;
275
394
  }
276
395
  return tokens;
277
396
  }
397
+ function findTemplateSubstitutionEnd(source, start) {
398
+ let depth = 1;
399
+ const context = new LexicalContext();
400
+ const isIdentifierStart = (character) => /[A-Za-z_$]/.test(character);
401
+ const isIdentifierPart = (character) => /[A-Za-z0-9_$]/.test(character);
402
+ for (let i = start; i < source.length; i++) {
403
+ const c = source[i];
404
+ if (/\s/.test(c))
405
+ continue;
406
+ if (c === "\\") {
407
+ i++;
408
+ continue;
409
+ }
410
+ if (c === "'" || c === '"') {
411
+ i = skipQuoted(source, i, c);
412
+ context.tokens.push({ kind: "string", value: "" });
413
+ continue;
414
+ }
415
+ if (c === "`") {
416
+ i = skipTemplate(source, i);
417
+ context.pushOther();
418
+ continue;
419
+ }
420
+ if (c === "/" && source[i + 1] === "/") {
421
+ i += 2;
422
+ while (i < source.length && source[i] !== "\n")
423
+ i++;
424
+ continue;
425
+ }
426
+ if (c === "/" && source[i + 1] === "*") {
427
+ i += 2;
428
+ while (i < source.length && !(source[i] === "*" && source[i + 1] === "/"))
429
+ i++;
430
+ i++;
431
+ continue;
432
+ }
433
+ if (c === "/" && context.isRegexAllowed()) {
434
+ i = skipRegularExpression(source, i, (character) => /[A-Za-z0-9_$]/.test(character));
435
+ i--;
436
+ context.pushOther();
437
+ continue;
438
+ }
439
+ if (isIdentifierStart(c)) {
440
+ let end = i + 1;
441
+ while (end < source.length && isIdentifierPart(source[end]))
442
+ end++;
443
+ context.pushWord(source.slice(i, end));
444
+ i = end - 1;
445
+ continue;
446
+ }
447
+ if (c >= "0" && c <= "9") {
448
+ let end = i + 1;
449
+ while (end < source.length && /[0-9a-fA-FxXoObBeE._]/.test(source[end]))
450
+ end++;
451
+ context.pushOther();
452
+ i = end - 1;
453
+ continue;
454
+ }
455
+ if ((c === "+" || c === "-") && source[i + 1] === c) {
456
+ context.pushPunct(c + c);
457
+ i++;
458
+ continue;
459
+ }
460
+ if (c === "?" &&
461
+ source[i + 1] === "." &&
462
+ !/[0-9]/.test(source[i + 2] ?? "")) {
463
+ context.pushPunct("?.");
464
+ i++;
465
+ continue;
466
+ }
467
+ if (c === "{")
468
+ depth++;
469
+ else if (c === "}" && --depth === 0)
470
+ return i;
471
+ context.pushPunct(c);
472
+ }
473
+ return source.length;
474
+ }
475
+ function isRegexAllowedAfter(previous) {
476
+ if (!previous)
477
+ return true;
478
+ if (previous.kind === "string" || previous.kind === "other")
479
+ return false;
480
+ if (previous.kind === "word")
481
+ return REGEX_PRECEDING_KEYWORDS.has(previous.value);
482
+ if (previous.value === ")" || previous.value === "}")
483
+ return previous.regexAllowedAfter === true;
484
+ return (previous.value !== "]" && previous.value !== "++" && previous.value !== "--");
485
+ }
486
+ /** Read one quoted literal and compute its JavaScript StringValue. */
487
+ function readQuotedString(source, start, quote) {
488
+ let value = "";
489
+ for (let index = start + 1; index < source.length;) {
490
+ const character = source[index];
491
+ if (character === quote) {
492
+ return { end: index + 1, value };
493
+ }
494
+ if (isLineTerminator(character)) {
495
+ return { end: index, value: null };
496
+ }
497
+ if (character !== "\\") {
498
+ value += character;
499
+ index++;
500
+ continue;
501
+ }
502
+ const escaped = source[index + 1];
503
+ if (escaped === undefined) {
504
+ return { end: source.length, value: null };
505
+ }
506
+ if (isLineTerminator(escaped)) {
507
+ index += escaped === "\r" && source[index + 2] === "\n" ? 3 : 2;
508
+ continue;
509
+ }
510
+ const simple = SIMPLE_STRING_ESCAPES[escaped];
511
+ if (simple !== undefined) {
512
+ value += simple;
513
+ index += 2;
514
+ continue;
515
+ }
516
+ if (escaped === "0") {
517
+ if (/[0-9]/.test(source[index + 2] ?? "")) {
518
+ return invalidQuotedString(source, start, quote);
519
+ }
520
+ value += "\0";
521
+ index += 2;
522
+ continue;
523
+ }
524
+ if (escaped >= "1" && escaped <= "9") {
525
+ return invalidQuotedString(source, start, quote);
526
+ }
527
+ if (escaped === "x") {
528
+ const digits = source.slice(index + 2, index + 4);
529
+ if (digits.length !== 2 || !/^[0-9a-fA-F]{2}$/.test(digits)) {
530
+ return invalidQuotedString(source, start, quote);
531
+ }
532
+ value += String.fromCharCode(Number.parseInt(digits, 16));
533
+ index += 4;
534
+ continue;
535
+ }
536
+ if (escaped === "u") {
537
+ if (source[index + 2] === "{") {
538
+ const close = source.indexOf("}", index + 3);
539
+ const digits = close < 0 ? "" : source.slice(index + 3, close);
540
+ const significantDigits = digits.replace(/^0+/, "") || "0";
541
+ const codePoint = Number.parseInt(digits, 16);
542
+ if (close < 0 ||
543
+ !/^[0-9a-fA-F]+$/.test(digits) ||
544
+ significantDigits.length > 6 ||
545
+ codePoint > 0x10ffff) {
546
+ return invalidQuotedString(source, start, quote);
547
+ }
548
+ value += String.fromCodePoint(codePoint);
549
+ index = close + 1;
550
+ continue;
551
+ }
552
+ const digits = source.slice(index + 2, index + 6);
553
+ if (digits.length !== 4 || !/^[0-9a-fA-F]{4}$/.test(digits)) {
554
+ return invalidQuotedString(source, start, quote);
555
+ }
556
+ value += String.fromCharCode(Number.parseInt(digits, 16));
557
+ index += 6;
558
+ continue;
559
+ }
560
+ // IdentityEscape / NonEscapeCharacter: the slash is discarded and the
561
+ // escaped source character contributes directly to the StringValue.
562
+ value += escaped;
563
+ index += 2;
564
+ }
565
+ return { end: source.length, value: null };
566
+ }
567
+ const SIMPLE_STRING_ESCAPES = {
568
+ "'": "'",
569
+ '"': '"',
570
+ "\\": "\\",
571
+ b: "\b",
572
+ f: "\f",
573
+ n: "\n",
574
+ r: "\r",
575
+ t: "\t",
576
+ v: "\v",
577
+ };
578
+ function invalidQuotedString(source, start, quote) {
579
+ const end = skipQuoted(source, start, quote);
580
+ return {
581
+ end: end < source.length && source[end] === quote ? end + 1 : end,
582
+ value: null,
583
+ };
584
+ }
585
+ function isLineTerminator(character) {
586
+ return (character === "\n" ||
587
+ character === "\r" ||
588
+ character === "\u2028" ||
589
+ character === "\u2029");
590
+ }
591
+ function skipRegularExpression(source, start, isIdentifierPart) {
592
+ let index = start + 1;
593
+ let inClass = false;
594
+ while (index < source.length) {
595
+ const character = source[index];
596
+ if (character === "\\") {
597
+ index += 2;
598
+ continue;
599
+ }
600
+ if (character === "\n")
601
+ break;
602
+ if (character === "[")
603
+ inClass = true;
604
+ else if (character === "]")
605
+ inClass = false;
606
+ else if (character === "/" && !inClass) {
607
+ index++;
608
+ break;
609
+ }
610
+ index++;
611
+ }
612
+ while (index < source.length && isIdentifierPart(source[index]))
613
+ index++;
614
+ return index;
615
+ }
616
+ function skipQuoted(source, start, quote) {
617
+ for (let i = start + 1; i < source.length; i++) {
618
+ if (source[i] === "\\") {
619
+ i++;
620
+ continue;
621
+ }
622
+ if (source[i] === quote || isLineTerminator(source[i]))
623
+ return i;
624
+ }
625
+ return source.length;
626
+ }
627
+ function skipTemplate(source, start) {
628
+ for (let i = start + 1; i < source.length; i++) {
629
+ if (source[i] === "\\") {
630
+ i++;
631
+ continue;
632
+ }
633
+ if (source[i] === "`")
634
+ return i;
635
+ if (source[i] === "$" && source[i + 1] === "{") {
636
+ i = findTemplateSubstitutionEnd(source, i + 2);
637
+ }
638
+ }
639
+ return source.length;
640
+ }
278
641
  //# sourceMappingURL=collectExternalPackageNames.js.map