poe-code 14.0.64 → 14.0.66

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 (73) hide show
  1. package/dist/index.js +8832 -7273
  2. package/dist/index.js.map +4 -4
  3. package/dist/metafile.json +1 -1
  4. package/package.json +1 -1
  5. package/packages/safe-js/dist/chunks/{chunk-3EXDJDQM.js → chunk-MKTUVVEB.js} +2 -2
  6. package/packages/safe-js/dist/chunks/{chunk-XO7B4P27.js → chunk-YKISHTWT.js} +4474 -2978
  7. package/packages/safe-js/dist/chunks/chunk-YKISHTWT.js.map +7 -0
  8. package/packages/safe-js/dist/cli.js +2 -2
  9. package/packages/safe-js/dist/core.js +1 -1
  10. package/packages/safe-js/dist/index.js +2 -2
  11. package/packages/safe-js/dist/index.js.map +1 -1
  12. package/packages/safe-js/dist/interp/accessors.d.ts +9 -0
  13. package/packages/safe-js/dist/interp/accessors.js +68 -0
  14. package/packages/safe-js/dist/interp/async.d.ts +13 -2
  15. package/packages/safe-js/dist/interp/async.js +19 -9
  16. package/packages/safe-js/dist/interp/classes.d.ts +4 -0
  17. package/packages/safe-js/dist/interp/classes.js +182 -0
  18. package/packages/safe-js/dist/interp/exceptions.d.ts +1 -1
  19. package/packages/safe-js/dist/interp/exceptions.js +51 -9
  20. package/packages/safe-js/dist/interp/globals/collections.js +53 -16
  21. package/packages/safe-js/dist/interp/globals/console-json.js +41 -26
  22. package/packages/safe-js/dist/interp/globals/object-array.d.ts +2 -1
  23. package/packages/safe-js/dist/interp/globals/object-array.js +230 -69
  24. package/packages/safe-js/dist/interp/globals/object.js +13 -2
  25. package/packages/safe-js/dist/interp/globals/primitives.js +16 -5
  26. package/packages/safe-js/dist/interp/interpreter.d.ts +2 -2
  27. package/packages/safe-js/dist/interp/interpreter.js +168 -61
  28. package/packages/safe-js/dist/interp/iteration.js +13 -0
  29. package/packages/safe-js/dist/interp/methods/array.d.ts +1 -1
  30. package/packages/safe-js/dist/interp/methods/array.js +368 -109
  31. package/packages/safe-js/dist/interp/methods/function.d.ts +1 -1
  32. package/packages/safe-js/dist/interp/methods/function.js +56 -20
  33. package/packages/safe-js/dist/interp/methods/regex.js +1 -1
  34. package/packages/safe-js/dist/interp/object-model.d.ts +1 -0
  35. package/packages/safe-js/dist/interp/object-model.js +48 -10
  36. package/packages/safe-js/dist/interp/patterns.d.ts +3 -3
  37. package/packages/safe-js/dist/interp/patterns.js +36 -17
  38. package/packages/safe-js/dist/interp/promise.d.ts +1 -1
  39. package/packages/safe-js/dist/interp/promise.js +103 -63
  40. package/packages/safe-js/dist/interp/string-coercion.d.ts +1 -0
  41. package/packages/safe-js/dist/interp/string-coercion.js +47 -37
  42. package/packages/safe-js/dist/interp/values.d.ts +4 -2
  43. package/packages/safe-js/dist/interp/values.js +26 -1
  44. package/packages/safe-js/dist/lint/class-elements.d.ts +5 -0
  45. package/packages/safe-js/dist/lint/class-elements.js +20 -0
  46. package/packages/safe-js/dist/lint/rules/AS-async-not-needed.js +16 -0
  47. package/packages/safe-js/dist/lint/rules/AS-destructure-null-default.js +9 -0
  48. package/packages/safe-js/dist/lint/rules/AS-export-import-meta.js +9 -0
  49. package/packages/safe-js/dist/lint/rules/AS-floating-promise.js +9 -0
  50. package/packages/safe-js/dist/lint/rules/AS-frontmatter-field-unused.js +9 -0
  51. package/packages/safe-js/dist/lint/rules/AS-jsdoc-type.js +9 -0
  52. package/packages/safe-js/dist/lint/rules/AS-large-literal.js +9 -0
  53. package/packages/safe-js/dist/lint/rules/AS-missing-async.js +16 -0
  54. package/packages/safe-js/dist/lint/rules/AS-mutating-frozen.js +9 -0
  55. package/packages/safe-js/dist/lint/rules/AS-needless-template.js +9 -0
  56. package/packages/safe-js/dist/lint/rules/AS-shadow-global.js +12 -0
  57. package/packages/safe-js/dist/lint/rules/AS-unbounded-loop.js +11 -0
  58. package/packages/safe-js/dist/lint/rules/AS-unreachable.js +9 -0
  59. package/packages/safe-js/dist/lint/rules/AS-unused-import.js +16 -2
  60. package/packages/safe-js/dist/lint/rules/AS001.js +0 -1
  61. package/packages/safe-js/dist/lint/rules/AS003.js +16 -2
  62. package/packages/safe-js/dist/lint/rules/AS006-007.js +16 -2
  63. package/packages/safe-js/dist/lint/rules/AS009.js +20 -1
  64. package/packages/safe-js/dist/lint/rules/AS010.js +9 -0
  65. package/packages/safe-js/dist/lint/rules/AS011.js +9 -0
  66. package/packages/safe-js/dist/lint/rules/AS015.js +9 -0
  67. package/packages/safe-js/dist/parse/function-source.d.ts +2 -2
  68. package/packages/safe-js/dist/parse/parser.d.ts +42 -2
  69. package/packages/safe-js/dist/parse/parser.js +208 -35
  70. package/packages/safe-js/dist/parse/tokenizer.js +3 -0
  71. package/packages/safe-js/dist/parse.d.ts +1 -1
  72. package/packages/safe-js/dist/chunks/chunk-XO7B4P27.js.map +0 -7
  73. /package/packages/safe-js/dist/chunks/{chunk-3EXDJDQM.js.map → chunk-MKTUVVEB.js.map} +0 -0
@@ -2,3 +2,4 @@ import type { Budget } from "./budget.js";
2
2
  import { type SandboxCallContext, type SandboxValue } from "./values.js";
3
3
  export declare function sandboxNumber(value: SandboxValue, budget: Budget, context?: SandboxCallContext): number | Promise<number>;
4
4
  export declare function sandboxString(value: SandboxValue, budget: Budget, context?: SandboxCallContext, joining?: Set<object>): string | Promise<string>;
5
+ export declare function joinSandboxArray(value: SandboxValue & object, length: number, separator: string, budget: Budget, context?: SandboxCallContext, joining?: Set<object>): Promise<string>;
@@ -1,4 +1,5 @@
1
1
  import { sandboxErrorTypes } from "../error/shape.js";
2
+ import { readPropertyDescriptor } from "./accessors.js";
2
3
  import { dateString, dateTime, isSandboxDate } from "./date.js";
3
4
  import { invokeBuiltinClosure } from "./builtin-call.js";
4
5
  import { float32Storage, isFloat32Array } from "./float32.js";
@@ -13,6 +14,7 @@ import { boxedValue, isSandboxBox } from "./boxed.js";
13
14
  import { isSandboxClosure, isSandboxPromise, isSandboxMap, isSandboxSet, isSandboxRegex, isSandboxGenerator } from "./values.js";
14
15
  const defaultStringHook = Symbol("defaultStringHook");
15
16
  const defaultValueHook = Symbol("defaultValueHook");
17
+ const joiningArrays = new WeakSet();
16
18
  export function sandboxNumber(value, budget, context) {
17
19
  if (value === null || typeof value !== "object") {
18
20
  if (typeof value === "function")
@@ -30,18 +32,44 @@ export function sandboxString(value, budget, context, joining = new Set()) {
30
32
  return objectToPrimitive(value, budget, context, joining, "string")
31
33
  .then(primitive => budget.allocateString(String(primitive)));
32
34
  }
35
+ export async function joinSandboxArray(value, length, separator, budget, context, joining = new Set()) {
36
+ if (joiningArrays.has(value))
37
+ return "";
38
+ joiningArrays.add(value);
39
+ let text = "";
40
+ const release = retainValues(budget, () => [value, text, separator]);
41
+ try {
42
+ for (let index = 0; index < length; index++) {
43
+ budget.visitNode();
44
+ const element = await readCoercionProperty(value, String(index), context);
45
+ const part = element === null || element === undefined
46
+ ? ""
47
+ : await sandboxString(element, budget, context, joining);
48
+ text = budget.allocateString(text + (index === 0 ? "" : separator) + part);
49
+ }
50
+ return text;
51
+ }
52
+ finally {
53
+ release();
54
+ joiningArrays.delete(value);
55
+ }
56
+ }
33
57
  async function objectToPrimitive(value, budget, context, joining, hint) {
34
58
  const leaveCall = budget.enterCall();
35
59
  try {
36
60
  budget.visitNode();
37
61
  for (const name of hint === "string" ? ["toString", "valueOf"] : ["valueOf", "toString"]) {
38
- const hook = conversionHook(value, name, budget);
62
+ const hook = await conversionHook(value, name, budget, context);
39
63
  let result;
40
64
  if (hook === defaultStringHook) {
41
65
  result = await defaultToString(value, budget, context, joining);
42
66
  }
43
67
  else if (hook === defaultValueHook) {
44
- result = isSandboxDate(value) ? dateTime(value) : isSandboxBox(value) ? boxedValue(value) : value;
68
+ result = isSandboxDate(value)
69
+ ? dateTime(value)
70
+ : isSandboxBox(value)
71
+ ? boxedValue(value)
72
+ : value;
45
73
  }
46
74
  else {
47
75
  if (!isSandboxClosure(hook))
@@ -60,7 +88,7 @@ async function objectToPrimitive(value, budget, context, joining, hint) {
60
88
  leaveCall();
61
89
  }
62
90
  }
63
- function conversionHook(value, name, budget) {
91
+ function conversionHook(value, name, budget, context) {
64
92
  const implicitBuiltin = !hasExplicitSandboxPrototype(value) &&
65
93
  (Array.isArray(value) ||
66
94
  isSandboxDate(value) ||
@@ -80,9 +108,7 @@ function conversionHook(value, name, budget) {
80
108
  const properties = isGuestClosure(current) ? getGuestFunctionProperties(current) : current;
81
109
  const descriptor = properties === undefined ? undefined : Object.getOwnPropertyDescriptor(properties, name);
82
110
  if (descriptor !== undefined) {
83
- if (!Object.hasOwn(descriptor, "value"))
84
- throw new TypeError("String conversion requires sandbox data properties.");
85
- return descriptor.value;
111
+ return readPropertyDescriptor(descriptor, value, context);
86
112
  }
87
113
  const parent = getSandboxPrototype(current, budget);
88
114
  if (current === value &&
@@ -107,7 +133,9 @@ async function defaultToString(value, budget, context, joining) {
107
133
  if (isSandboxSet(value))
108
134
  return "[object Set]";
109
135
  if (isSandboxCollectionIterator(value))
110
- return collectionIteratorState(value).collectionKind === "map" ? "[object Map Iterator]" : "[object Set Iterator]";
136
+ return collectionIteratorState(value).collectionKind === "map"
137
+ ? "[object Map Iterator]"
138
+ : "[object Set Iterator]";
111
139
  if (isSandboxGenerator(value))
112
140
  return "[object Generator]";
113
141
  if (isSandboxRegex(value)) {
@@ -117,40 +145,23 @@ async function defaultToString(value, budget, context, joining) {
117
145
  return budget.allocateString(dateString(value));
118
146
  if (Array.isArray(value) || isFloat32Array(value)) {
119
147
  if (Object.hasOwn(value, "join")) {
120
- const join = ownDataValue(value, "join");
148
+ const join = await readCoercionProperty(value, "join", context);
121
149
  if (!isSandboxClosure(join))
122
150
  return isFloat32Array(value) ? "[object Float32Array]" : "[object Array]";
123
151
  return invokeBuiltinClosure(join, [], budget, context, value);
124
152
  }
125
- if (joining.has(value))
126
- return "";
127
- joining.add(value);
128
- let text = "";
129
- const release = retainValues(budget, () => [text]);
130
- try {
131
- const length = isFloat32Array(value) ? float32Storage(value).length : value.length;
132
- for (let index = 0; index < length; index++) {
133
- budget.visitNode();
134
- const element = ownDataValue(value, String(index));
135
- const part = element === null || element === undefined
136
- ? ""
137
- : await sandboxString(element, budget, context, joining);
138
- text = budget.allocateString(text + (index === 0 ? "" : ",") + part);
139
- }
140
- return text;
141
- }
142
- finally {
143
- release();
144
- joining.delete(value);
145
- }
153
+ const length = isFloat32Array(value) ? float32Storage(value).length : value.length;
154
+ return joinSandboxArray(value, length, ",", budget, context, joining);
146
155
  }
147
156
  if (sandboxErrorTypes.has(value)) {
148
- const nameValue = ownDataValue(value, "name");
157
+ const nameValue = await readCoercionProperty(value, "name", context);
149
158
  const name = nameValue === undefined ? "Error" : await sandboxString(nameValue, budget, context, joining);
150
159
  const release = retainValues(budget, () => [name]);
151
160
  try {
152
- const messageValue = ownDataValue(value, "message");
153
- const message = messageValue === undefined ? "" : await sandboxString(messageValue, budget, context, joining);
161
+ const messageValue = await readCoercionProperty(value, "message", context);
162
+ const message = messageValue === undefined
163
+ ? ""
164
+ : await sandboxString(messageValue, budget, context, joining);
154
165
  return name === "" ? message : message === "" ? name : `${name}: ${message}`;
155
166
  }
156
167
  finally {
@@ -159,10 +170,9 @@ async function defaultToString(value, budget, context, joining) {
159
170
  }
160
171
  return isSandboxPromise(value) ? "[object Promise]" : "[object Object]";
161
172
  }
162
- function ownDataValue(value, name) {
173
+ function readCoercionProperty(value, name, context) {
174
+ if (context?.getProperty !== undefined)
175
+ return context.getProperty(value, name);
163
176
  const descriptor = Object.getOwnPropertyDescriptor(value, name);
164
- if (descriptor !== undefined && !Object.hasOwn(descriptor, "value")) {
165
- throw new TypeError("String conversion requires sandbox data properties.");
166
- }
167
- return descriptor?.value;
177
+ return descriptor === undefined ? undefined : readPropertyDescriptor(descriptor, value, context);
168
178
  }
@@ -38,6 +38,7 @@ export type SandboxRegex = {
38
38
  readonly [sandboxRegexPattern]: RegexPattern;
39
39
  };
40
40
  export type SandboxCallContext = {
41
+ readonly newTarget?: SandboxClosure;
41
42
  readonly compilation?: CompileScope;
42
43
  readonly span?: {
43
44
  readonly end: {
@@ -53,9 +54,9 @@ export type SandboxCallContext = {
53
54
  };
54
55
  readonly stack: readonly string[];
55
56
  readonly thisValue: SandboxValue;
56
- readonly getProperty?: (value: SandboxValue, property: string | number) => SandboxValue;
57
+ readonly getProperty?: (value: SandboxValue, property: string | number) => SandboxValue | Promise<SandboxValue>;
57
58
  readonly reconcileData?: (value: SandboxValue) => void;
58
- readonly invokeClosure?: (closure: SandboxClosure, args: readonly SandboxValue[], thisValue: SandboxValue, construct?: boolean) => Promise<SandboxValue>;
59
+ readonly invokeClosure?: (closure: SandboxClosure, args: readonly SandboxValue[], thisValue: SandboxValue, construct?: boolean, newTarget?: SandboxClosure) => Promise<SandboxValue>;
59
60
  };
60
61
  export type SandboxClosure = {
61
62
  readonly sourceRange?: FunctionSource;
@@ -111,6 +112,7 @@ export declare function createSandboxClosure(input: {
111
112
  retainedValues?: () => Iterable<SandboxValue>;
112
113
  }): SandboxClosure;
113
114
  export declare function ownEnumerableSandboxEntries(value: SandboxValue, excludedKeys?: ReadonlySet<string>): Array<[string, SandboxValue]>;
115
+ export declare function ownEnumerableSandboxKeys(value: SandboxValue): string[];
114
116
  export declare function createSandboxPromise(promise: Promise<SandboxValue>, metadata?: {
115
117
  trackReplay?: boolean;
116
118
  synchronousPrefix?: Promise<void>;
@@ -1,4 +1,5 @@
1
1
  import { bindOtelSpan, getBoundOtelSpan } from "../observability/otel.js";
2
+ import { retainedAccessorClosures } from "./accessors.js";
2
3
  import { isSandboxMap, isSandboxSet, sandboxMapBrand, sandboxSetBrand } from "./collection-brands.js";
3
4
  import { collectionIteratorState, isSandboxCollectionIterator, restoreSandboxCollectionIterator, snapshotCollectionIterator } from "./collection-iterator.js";
4
5
  import { copyNativeDate, exportDate, isSandboxDate } from "./date.js";
@@ -100,6 +101,17 @@ export function ownEnumerableSandboxEntries(value, excludedKeys) {
100
101
  entries = Object.entries(Object(value));
101
102
  return excludedKeys === undefined ? entries : entries.filter(([key]) => !excludedKeys.has(key));
102
103
  }
104
+ export function ownEnumerableSandboxKeys(value) {
105
+ if (isGuestHostObject(value))
106
+ return getHostObjectKeys(value);
107
+ if (value === null || value === undefined)
108
+ throw new TypeError("Cannot convert undefined or null to object.");
109
+ if (isGuestClosure(value))
110
+ return Object.keys(value.properties ?? {});
111
+ if (isSandboxClosure(value) || isSandboxGenerator(value) || isSandboxMap(value) || isSandboxSet(value) || isSandboxPromise(value) || isSandboxRegex(value))
112
+ return [];
113
+ return Object.keys(Object(value));
114
+ }
103
115
  export function createSandboxPromise(promise, metadata = {}) {
104
116
  const original = metadata.trackReplay === false
105
117
  ? promise
@@ -254,6 +266,9 @@ export function measureSandboxData(values, options = {}) {
254
266
  usage += key.length + 1;
255
267
  if ("value" in descriptor)
256
268
  visit(descriptor.value, depth + 1);
269
+ else
270
+ for (const closure of retainedAccessorClosures(descriptor))
271
+ visit(closure, depth + 1);
257
272
  }
258
273
  return;
259
274
  }
@@ -289,6 +304,9 @@ export function measureSandboxData(values, options = {}) {
289
304
  usage += key.length + 1;
290
305
  if ("value" in descriptor)
291
306
  visit(descriptor.value, depth + 1);
307
+ else
308
+ for (const closure of retainedAccessorClosures(descriptor))
309
+ visit(closure, depth + 1);
292
310
  }
293
311
  return;
294
312
  }
@@ -333,6 +351,9 @@ export function measureSandboxData(values, options = {}) {
333
351
  usage += key.length + 1;
334
352
  if ("value" in descriptor)
335
353
  visit(descriptor.value, depth + 1);
354
+ else
355
+ for (const closure of retainedAccessorClosures(descriptor))
356
+ visit(closure, depth + 1);
336
357
  }
337
358
  }
338
359
  else
@@ -386,7 +407,11 @@ export function measureSandboxData(values, options = {}) {
386
407
  if (!descriptor.enumerable && !hasManagedDescriptors(value))
387
408
  continue;
388
409
  usage += key.length;
389
- visit("value" in descriptor ? descriptor.value : undefined, depth + 1);
410
+ if ("value" in descriptor)
411
+ visit(descriptor.value, depth + 1);
412
+ else
413
+ for (const closure of retainedAccessorClosures(descriptor))
414
+ visit(closure, depth + 1);
390
415
  }
391
416
  };
392
417
  for (const value of values)
@@ -0,0 +1,5 @@
1
+ import type { BlockStatement, ClassNode, Expression } from "../parse.js";
2
+ /** Visit both definition-time expressions and deferred element bodies. */
3
+ export declare function visitClassElements(node: ClassNode, expression: (node: Expression) => void, statement: (node: BlockStatement) => void): void;
4
+ /** Await in a computed key belongs to the defining function, unlike methods. */
5
+ export declare function classDefinitionContains(node: ClassNode, expression: (node: Expression) => boolean): boolean;
@@ -0,0 +1,20 @@
1
+ /** Visit both definition-time expressions and deferred element bodies. */
2
+ export function visitClassElements(node, expression, statement) {
3
+ if (node.superClass !== undefined)
4
+ expression(node.superClass);
5
+ for (const element of node.body.body) {
6
+ if (element.type === "StaticBlock") {
7
+ statement(element.body);
8
+ continue;
9
+ }
10
+ if (element.computed)
11
+ expression(element.key);
12
+ if (element.value !== undefined)
13
+ expression(element.value);
14
+ }
15
+ }
16
+ /** Await in a computed key belongs to the defining function, unlike methods. */
17
+ export function classDefinitionContains(node, expression) {
18
+ return (node.superClass !== undefined && expression(node.superClass)) ||
19
+ node.body.body.some(element => element.type !== "StaticBlock" && element.computed && expression(element.key));
20
+ }
@@ -1,3 +1,4 @@
1
+ import { classDefinitionContains, visitClassElements } from "../class-elements.js";
1
2
  import { parseModule } from "../../parse/parser.js";
2
3
  export const AS_ASYNC_NOT_NEEDED_MESSAGE = "Async functions without await should remove the async keyword.";
3
4
  export function AS_ASYNC_NOT_NEEDED(source, options = {}) {
@@ -32,6 +33,10 @@ class ASAsyncNotNeededScanner {
32
33
  }
33
34
  }
34
35
  visitStatement(node) {
36
+ if (node.type === "ClassDeclaration") {
37
+ visitClassElements(node, expression => this.visitExpression(expression), statement => this.visitStatement(statement));
38
+ return;
39
+ }
35
40
  switch (node.type) {
36
41
  case "FunctionDeclaration":
37
42
  this.visitFunctionExpression(node);
@@ -166,6 +171,10 @@ class ASAsyncNotNeededScanner {
166
171
  this.visitExpression(node.argument);
167
172
  }
168
173
  visitExpression(node) {
174
+ if (node.type === "ClassExpression") {
175
+ visitClassElements(node, expression => this.visitExpression(expression), statement => this.visitStatement(statement));
176
+ return;
177
+ }
169
178
  switch (node.type) {
170
179
  case "YieldExpression":
171
180
  if (node.argument !== undefined) {
@@ -406,6 +415,8 @@ function statementListContainsAwait(statements) {
406
415
  }
407
416
  function statementContainsAwait(node) {
408
417
  switch (node.type) {
418
+ case "ClassDeclaration":
419
+ return classDefinitionContains(node, expressionContainsAwait);
409
420
  case "BlockStatement":
410
421
  return statementListContainsAwait(node.body);
411
422
  case "ExpressionStatement":
@@ -468,6 +479,11 @@ function variableDeclarationContainsAwait(node) {
468
479
  }
469
480
  function expressionContainsAwait(node) {
470
481
  switch (node.type) {
482
+ case "ClassExpression":
483
+ return classDefinitionContains(node, expressionContainsAwait);
484
+ case "NewTargetExpression":
485
+ case "Super":
486
+ return false;
471
487
  case "AwaitExpression":
472
488
  return true;
473
489
  case "YieldExpression":
@@ -1,3 +1,4 @@
1
+ import { visitClassElements } from "../class-elements.js";
1
2
  import { parseModule } from "../../parse/parser.js";
2
3
  const MESSAGE = "Destructuring default values only apply to undefined, not null.";
3
4
  const HINT = "Handle null explicitly before destructuring or use ?? after binding.";
@@ -20,6 +21,10 @@ class ASDestructureNullDefaultScanner {
20
21
  }
21
22
  }
22
23
  visitStatement(node) {
24
+ if (node.type === "ClassDeclaration") {
25
+ visitClassElements(node, expression => this.visitExpression(expression), statement => this.visitStatement(statement));
26
+ return;
27
+ }
23
28
  switch (node.type) {
24
29
  case "FunctionDeclaration":
25
30
  this.visitArrowFunction(node);
@@ -147,6 +152,10 @@ class ASDestructureNullDefaultScanner {
147
152
  this.visitExpression(node.argument);
148
153
  }
149
154
  visitExpression(node) {
155
+ if (node.type === "ClassExpression") {
156
+ visitClassElements(node, expression => this.visitExpression(expression), statement => this.visitStatement(statement));
157
+ return;
158
+ }
150
159
  switch (node.type) {
151
160
  case "YieldExpression":
152
161
  if (node.argument !== undefined) {
@@ -1,3 +1,4 @@
1
+ import { visitClassElements } from "../class-elements.js";
1
2
  import { parseModule } from "../../parse/parser.js";
2
3
  export function AS_EXPORT_IMPORT_META(source, options = {}) {
3
4
  return new Scanner(options.filename ?? "<input>", new Set(options.allowedExportNames ?? []), options.defaultExport).scan(source);
@@ -35,6 +36,10 @@ class Scanner {
35
36
  }
36
37
  }
37
38
  visitStatement(node) {
39
+ if (node.type === "ClassDeclaration") {
40
+ visitClassElements(node, expression => this.visitExpression(expression), statement => this.visitStatement(statement));
41
+ return;
42
+ }
38
43
  switch (node.type) {
39
44
  case "FunctionDeclaration":
40
45
  for (const param of node.params) {
@@ -176,6 +181,10 @@ class Scanner {
176
181
  this.visitExpression(node.argument);
177
182
  }
178
183
  visitExpression(node) {
184
+ if (node.type === "ClassExpression") {
185
+ visitClassElements(node, expression => this.visitExpression(expression), statement => this.visitStatement(statement));
186
+ return;
187
+ }
179
188
  switch (node.type) {
180
189
  case "YieldExpression":
181
190
  if (node.argument !== undefined) {
@@ -1,3 +1,4 @@
1
+ import { visitClassElements } from "../class-elements.js";
1
2
  import { parseModule } from "../../parse/parser.js";
2
3
  import { normalizeModuleRegistrations } from "./module-registry.js";
3
4
  const AS_FLOATING_PROMISE_MESSAGE = "Promise-returning call is not awaited, returned, stored, or chained.";
@@ -28,6 +29,10 @@ class ASFloatingPromiseScanner {
28
29
  });
29
30
  }
30
31
  visitStatement(node) {
32
+ if (node.type === "ClassDeclaration") {
33
+ visitClassElements(node, expression => this.visitExpression(expression), statement => this.visitStatement(statement));
34
+ return;
35
+ }
31
36
  switch (node.type) {
32
37
  case "FunctionDeclaration":
33
38
  this.visitArrowFunction(node);
@@ -163,6 +168,10 @@ class ASFloatingPromiseScanner {
163
168
  this.visitExpression(node.argument);
164
169
  }
165
170
  visitExpression(node) {
171
+ if (node.type === "ClassExpression") {
172
+ visitClassElements(node, expression => this.visitExpression(expression), statement => this.visitStatement(statement));
173
+ return;
174
+ }
166
175
  switch (node.type) {
167
176
  case "YieldExpression":
168
177
  if (node.argument !== undefined) {
@@ -1,3 +1,4 @@
1
+ import { visitClassElements } from "../class-elements.js";
1
2
  import { parseModule } from "../../parse/parser.js";
2
3
  export function AS_FRONTMATTER_FIELD_UNUSED(source, options = {}) {
3
4
  if (options.frontmatterFields === undefined) {
@@ -34,6 +35,10 @@ class ASFrontmatterFieldUnusedScanner {
34
35
  }
35
36
  }
36
37
  visitStatement(node) {
38
+ if (node.type === "ClassDeclaration") {
39
+ visitClassElements(node, expression => this.visitExpression(expression), statement => this.visitStatement(statement));
40
+ return;
41
+ }
37
42
  switch (node.type) {
38
43
  case "FunctionDeclaration":
39
44
  this.visitArrowFunction(node);
@@ -162,6 +167,10 @@ class ASFrontmatterFieldUnusedScanner {
162
167
  this.visitExpression(node.argument);
163
168
  }
164
169
  visitExpression(node) {
170
+ if (node.type === "ClassExpression") {
171
+ visitClassElements(node, expression => this.visitExpression(expression), statement => this.visitStatement(statement));
172
+ return;
173
+ }
165
174
  switch (node.type) {
166
175
  case "YieldExpression":
167
176
  if (node.argument !== undefined) {
@@ -1,3 +1,4 @@
1
+ import { visitClassElements } from "../class-elements.js";
1
2
  import { parseModule } from "../../parse/parser.js";
2
3
  import { hasTypedModuleRegistrations } from "./module-registry.js";
3
4
  export function AS_JSDOC_TYPE(source, options = {}) {
@@ -27,6 +28,10 @@ class ASJsdocTypeScanner {
27
28
  }
28
29
  }
29
30
  visitStatement(node) {
31
+ if (node.type === "ClassDeclaration") {
32
+ visitClassElements(node, expression => this.visitExpression(expression), statement => this.visitStatement(statement));
33
+ return;
34
+ }
30
35
  switch (node.type) {
31
36
  case "FunctionDeclaration":
32
37
  this.visitArrowFunction(node);
@@ -166,6 +171,10 @@ class ASJsdocTypeScanner {
166
171
  }
167
172
  }
168
173
  visitExpression(node) {
174
+ if (node.type === "ClassExpression") {
175
+ visitClassElements(node, expression => this.visitExpression(expression), statement => this.visitStatement(statement));
176
+ return;
177
+ }
169
178
  switch (node.type) {
170
179
  case "YieldExpression":
171
180
  if (node.argument !== undefined) {
@@ -1,3 +1,4 @@
1
+ import { visitClassElements } from "../class-elements.js";
1
2
  import { parseModule } from "../../parse/parser.js";
2
3
  const DEFAULT_LARGE_LITERAL_THRESHOLD = 1000;
3
4
  export function AS_LARGE_LITERAL(source, options = {}) {
@@ -21,6 +22,10 @@ class ASLargeLiteralScanner {
21
22
  }
22
23
  }
23
24
  visitStatement(node) {
25
+ if (node.type === "ClassDeclaration") {
26
+ visitClassElements(node, expression => this.visitExpression(expression), statement => this.visitStatement(statement));
27
+ return;
28
+ }
24
29
  switch (node.type) {
25
30
  case "FunctionDeclaration":
26
31
  this.visitArrowFunction(node);
@@ -144,6 +149,10 @@ class ASLargeLiteralScanner {
144
149
  this.visitExpression(node.argument);
145
150
  }
146
151
  visitExpression(node) {
152
+ if (node.type === "ClassExpression") {
153
+ visitClassElements(node, expression => this.visitExpression(expression), statement => this.visitStatement(statement));
154
+ return;
155
+ }
147
156
  switch (node.type) {
148
157
  case "YieldExpression":
149
158
  if (node.argument !== undefined) {
@@ -1,3 +1,4 @@
1
+ import { classDefinitionContains, visitClassElements } from "../class-elements.js";
1
2
  import { parseModule } from "../../parse/parser.js";
2
3
  export const AS_MISSING_ASYNC_MESSAGE = "Functions that contain await must be marked async.";
3
4
  export function AS_MISSING_ASYNC(source, options = {}) {
@@ -27,6 +28,10 @@ class ASMissingAsyncScanner {
27
28
  }
28
29
  }
29
30
  visitStatement(node) {
31
+ if (node.type === "ClassDeclaration") {
32
+ visitClassElements(node, expression => this.visitExpression(expression), statement => this.visitStatement(statement));
33
+ return;
34
+ }
30
35
  switch (node.type) {
31
36
  case "FunctionDeclaration":
32
37
  this.visitFunctionExpression(node);
@@ -150,6 +155,10 @@ class ASMissingAsyncScanner {
150
155
  this.visitExpression(node.argument);
151
156
  }
152
157
  visitExpression(node) {
158
+ if (node.type === "ClassExpression") {
159
+ visitClassElements(node, expression => this.visitExpression(expression), statement => this.visitStatement(statement));
160
+ return;
161
+ }
153
162
  switch (node.type) {
154
163
  case "YieldExpression":
155
164
  if (node.argument !== undefined) {
@@ -377,6 +386,8 @@ function statementListContainsAwait(statements) {
377
386
  }
378
387
  function statementContainsAwait(node) {
379
388
  switch (node.type) {
389
+ case "ClassDeclaration":
390
+ return classDefinitionContains(node, expressionContainsAwait);
380
391
  case "BlockStatement":
381
392
  return statementListContainsAwait(node.body);
382
393
  case "ExpressionStatement":
@@ -439,6 +450,11 @@ function variableDeclarationContainsAwait(node) {
439
450
  }
440
451
  function expressionContainsAwait(node) {
441
452
  switch (node.type) {
453
+ case "ClassExpression":
454
+ return classDefinitionContains(node, expressionContainsAwait);
455
+ case "NewTargetExpression":
456
+ case "Super":
457
+ return false;
442
458
  case "AwaitExpression":
443
459
  return true;
444
460
  case "YieldExpression":
@@ -1,3 +1,4 @@
1
+ import { visitClassElements } from "../class-elements.js";
1
2
  import { parseModule } from "../../parse/parser.js";
2
3
  const MUTATING_ARRAY_METHODS = new Set([
3
4
  "copyWithin",
@@ -32,6 +33,10 @@ class ASMutatingFrozenScanner {
32
33
  });
33
34
  }
34
35
  visitStatement(node) {
36
+ if (node.type === "ClassDeclaration") {
37
+ visitClassElements(node, expression => this.visitExpression(expression), statement => this.visitStatement(statement));
38
+ return;
39
+ }
35
40
  switch (node.type) {
36
41
  case "FunctionDeclaration":
37
42
  this.visitArrowFunction(node);
@@ -172,6 +177,10 @@ class ASMutatingFrozenScanner {
172
177
  this.visitExpression(node.argument);
173
178
  }
174
179
  visitExpression(node) {
180
+ if (node.type === "ClassExpression") {
181
+ visitClassElements(node, expression => this.visitExpression(expression), statement => this.visitStatement(statement));
182
+ return;
183
+ }
175
184
  switch (node.type) {
176
185
  case "YieldExpression":
177
186
  if (node.argument !== undefined) {
@@ -1,3 +1,4 @@
1
+ import { visitClassElements } from "../class-elements.js";
1
2
  import { parseModule } from "../../parse/parser.js";
2
3
  export const AS_NEEDLESS_TEMPLATE_MESSAGE = "Template literals with only one interpolation should use the value or String(value).";
3
4
  export function AS_NEEDLESS_TEMPLATE(source, options = {}) {
@@ -44,6 +45,10 @@ class ASNeedlessTemplateScanner {
44
45
  }
45
46
  }
46
47
  visitStatement(node) {
48
+ if (node.type === "ClassDeclaration") {
49
+ visitClassElements(node, expression => this.visitExpression(expression), statement => this.visitStatement(statement));
50
+ return;
51
+ }
47
52
  switch (node.type) {
48
53
  case "FunctionDeclaration":
49
54
  this.visitArrowFunction(node);
@@ -170,6 +175,10 @@ class ASNeedlessTemplateScanner {
170
175
  this.visitExpression(node.argument);
171
176
  }
172
177
  visitExpression(node) {
178
+ if (node.type === "ClassExpression") {
179
+ visitClassElements(node, expression => this.visitExpression(expression), statement => this.visitStatement(statement));
180
+ return;
181
+ }
173
182
  switch (node.type) {
174
183
  case "YieldExpression":
175
184
  if (node.argument !== undefined) {
@@ -1,3 +1,4 @@
1
+ import { visitClassElements } from "../class-elements.js";
1
2
  import { parseModule } from "../../parse/parser.js";
2
3
  import { KNOWN_RUNTIME_GLOBALS } from "./known-globals.js";
3
4
  export function AS_SHADOW_GLOBAL(source, options = {}) {
@@ -21,6 +22,11 @@ class ASShadowGlobalScanner {
21
22
  }
22
23
  }
23
24
  visitStatement(node) {
25
+ if (node.type === "ClassDeclaration") {
26
+ this.reportIfGlobalShadow(node.id);
27
+ visitClassElements(node, expression => this.visitExpression(expression), statement => this.visitStatement(statement));
28
+ return;
29
+ }
24
30
  switch (node.type) {
25
31
  case "FunctionDeclaration":
26
32
  this.visitArrowFunctionExpression(node);
@@ -147,6 +153,12 @@ class ASShadowGlobalScanner {
147
153
  }
148
154
  }
149
155
  visitExpression(node) {
156
+ if (node.type === "ClassExpression") {
157
+ if (node.id !== undefined)
158
+ this.reportIfGlobalShadow(node.id);
159
+ visitClassElements(node, expression => this.visitExpression(expression), statement => this.visitStatement(statement));
160
+ return;
161
+ }
150
162
  switch (node.type) {
151
163
  case "YieldExpression":
152
164
  if (node.argument !== undefined) {
@@ -1,3 +1,4 @@
1
+ import { visitClassElements } from "../class-elements.js";
1
2
  import { parseModule } from "../../parse/parser.js";
2
3
  const MESSAGE = "Unbounded loop or generator source has no static exit with break, return, or throw.";
3
4
  export function AS_UNBOUNDED_LOOP(source, options = {}) {
@@ -20,6 +21,10 @@ class ASUnboundedLoopScanner {
20
21
  }
21
22
  }
22
23
  visitStatement(node) {
24
+ if (node.type === "ClassDeclaration") {
25
+ visitClassElements(node, expression => this.visitExpression(expression), statement => this.visitStatement(statement));
26
+ return;
27
+ }
23
28
  switch (node.type) {
24
29
  case "FunctionDeclaration":
25
30
  this.visitArrowFunction(node);
@@ -159,6 +164,10 @@ class ASUnboundedLoopScanner {
159
164
  this.visitExpression(node.argument);
160
165
  }
161
166
  visitExpression(node) {
167
+ if (node.type === "ClassExpression") {
168
+ visitClassElements(node, expression => this.visitExpression(expression), statement => this.visitStatement(statement));
169
+ return;
170
+ }
162
171
  switch (node.type) {
163
172
  case "YieldExpression":
164
173
  if (node.argument !== undefined) {
@@ -330,6 +339,8 @@ function isTrueLiteral(node) {
330
339
  }
331
340
  function bodyHasExit(node, exitingLabels, allowUnlabeledBreak) {
332
341
  switch (node.type) {
342
+ case "ClassDeclaration":
343
+ return false;
333
344
  case "BlockStatement":
334
345
  return node.body.some((statement) => bodyHasExit(statement, exitingLabels, allowUnlabeledBreak));
335
346
  case "IfStatement":