@scriptc/compiler 0.0.21 → 0.0.23

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 (92) hide show
  1. package/ambient/scriptc-node-fallback.d.ts +117 -37
  2. package/dist/backend/cc-cache.test.d.ts +1 -0
  3. package/dist/backend/cc-cache.test.js +2507 -0
  4. package/dist/backend/cc-cache.test.js.map +1 -0
  5. package/dist/backend/cc.d.ts +69 -11
  6. package/dist/backend/cc.js +1937 -222
  7. package/dist/backend/cc.js.map +1 -1
  8. package/dist/backend/emission/emit-async.js +3 -1
  9. package/dist/backend/emission/emit-async.js.map +1 -1
  10. package/dist/backend/emission/emit-exprs.d.ts +10 -0
  11. package/dist/backend/emission/emit-exprs.js +482 -18
  12. package/dist/backend/emission/emit-exprs.js.map +1 -1
  13. package/dist/backend/emission/emit-stmts.js +13 -5
  14. package/dist/backend/emission/emit-stmts.js.map +1 -1
  15. package/dist/backend/emission/emit-types.js +4 -1
  16. package/dist/backend/emission/emit-types.js.map +1 -1
  17. package/dist/backend/emission/emit-walkers.js +108 -7
  18. package/dist/backend/emission/emit-walkers.js.map +1 -1
  19. package/dist/backend/emission/emitter.d.ts +27 -1
  20. package/dist/backend/emission/emitter.js +84 -3
  21. package/dist/backend/emission/emitter.js.map +1 -1
  22. package/dist/backend/llvm/dyn.d.ts +1 -0
  23. package/dist/backend/llvm/dyn.js +305 -8
  24. package/dist/backend/llvm/dyn.js.map +1 -1
  25. package/dist/backend/llvm/emitter.js +831 -23
  26. package/dist/backend/llvm/emitter.js.map +1 -1
  27. package/dist/backend/llvm/shapes.js +3 -2
  28. package/dist/backend/llvm/shapes.js.map +1 -1
  29. package/dist/compat/fetch-profile.d.ts +118 -0
  30. package/dist/compat/fetch-profile.js +531 -0
  31. package/dist/compat/fetch-profile.js.map +1 -0
  32. package/dist/coverage/surface-manifest.js +69 -0
  33. package/dist/coverage/surface-manifest.js.map +1 -1
  34. package/dist/diagnostics/diagnostic.d.ts +10 -0
  35. package/dist/diagnostics/diagnostic.js +27 -1
  36. package/dist/diagnostics/diagnostic.js.map +1 -1
  37. package/dist/frontend/lowering/lower-builtins.d.ts +24 -15
  38. package/dist/frontend/lowering/lower-builtins.js +217 -69
  39. package/dist/frontend/lowering/lower-builtins.js.map +1 -1
  40. package/dist/frontend/lowering/lower-calls.js +41 -0
  41. package/dist/frontend/lowering/lower-calls.js.map +1 -1
  42. package/dist/frontend/lowering/lower-classes.js +32 -11
  43. package/dist/frontend/lowering/lower-classes.js.map +1 -1
  44. package/dist/frontend/lowering/lower-exprs.d.ts +3 -3
  45. package/dist/frontend/lowering/lower-exprs.js +87 -15
  46. package/dist/frontend/lowering/lower-exprs.js.map +1 -1
  47. package/dist/frontend/lowering/lower-generators.js +7 -1
  48. package/dist/frontend/lowering/lower-generators.js.map +1 -1
  49. package/dist/frontend/lowering/lower-island.d.ts +123 -7
  50. package/dist/frontend/lowering/lower-island.js +1976 -26
  51. package/dist/frontend/lowering/lower-island.js.map +1 -1
  52. package/dist/frontend/lowering/lower-modules.js +17 -1
  53. package/dist/frontend/lowering/lower-modules.js.map +1 -1
  54. package/dist/frontend/lowering/lower-stmts.js +33 -9
  55. package/dist/frontend/lowering/lower-stmts.js.map +1 -1
  56. package/dist/frontend/lowering/lowerer.d.ts +40 -0
  57. package/dist/frontend/lowering/lowerer.js +290 -18
  58. package/dist/frontend/lowering/lowerer.js.map +1 -1
  59. package/dist/frontend/lowering/surfaces.js +55 -12
  60. package/dist/frontend/lowering/surfaces.js.map +1 -1
  61. package/dist/frontend/program.d.ts +20 -4
  62. package/dist/frontend/program.js +391 -49
  63. package/dist/frontend/program.js.map +1 -1
  64. package/dist/frontend/resolve.d.ts +10 -0
  65. package/dist/frontend/resolve.js +37 -0
  66. package/dist/frontend/resolve.js.map +1 -1
  67. package/dist/frontend/ts7/enums.d.ts +9 -0
  68. package/dist/frontend/ts7/enums.js +8 -6
  69. package/dist/frontend/ts7/enums.js.map +1 -1
  70. package/dist/frontend/ts7/program.js +4 -1
  71. package/dist/frontend/ts7/program.js.map +1 -1
  72. package/dist/frontend/types.d.ts +16 -9
  73. package/dist/frontend/types.js +119 -38
  74. package/dist/frontend/types.js.map +1 -1
  75. package/dist/index.d.ts +7 -1
  76. package/dist/index.js +70 -14
  77. package/dist/index.js.map +1 -1
  78. package/dist/ir/nodes.d.ts +55 -26
  79. package/dist/ir/nodes.js +42 -29
  80. package/dist/ir/nodes.js.map +1 -1
  81. package/dist/ir/validate.js +106 -9
  82. package/dist/ir/validate.js.map +1 -1
  83. package/dist/library/int-infer.js +7 -1
  84. package/dist/library/int-infer.js.map +1 -1
  85. package/dist/library/int-infer.test.js +80 -0
  86. package/dist/library/int-infer.test.js.map +1 -1
  87. package/dist/library/sidecar-validate.js +5 -0
  88. package/dist/library/sidecar-validate.js.map +1 -1
  89. package/dist/library/sidecar.d.ts +3 -0
  90. package/dist/library/sidecar.js.map +1 -1
  91. package/package.json +2 -2
  92. package/surface-manifest.json +1097 -130
@@ -28,11 +28,10 @@
28
28
  * in tsc codes at all: cjsExportDiscardReason (lowering) names every
29
29
  * genuinely discarded export, so relaxing the checker's stricter
30
30
  * modeling loses nothing.
31
- * - isNodeEsmFile: 5.9.3 under bundler sets impliedNodeFormat ONLY for
32
- * .mjs/.cjs-family files (probed) and falls back to syntactic module
33
- * detection for .js/.ts; 7's client SourceFile has no impliedNodeFormat,
34
- * so this lane spells exactly that observed behavior: extensions first,
35
- * then externalModuleIndicator.
31
+ * - isNodeEsmFile: 7's client SourceFile has no impliedNodeFormat, so this
32
+ * lane spells Node's format decision directly: fixed extensions first,
33
+ * then an explicit nearest-package `type`, then syntax detection for
34
+ * ambiguous .js/.ts files.
36
35
  * - Malformed tsconfig.json: tsgo's parseConfigFile swallows JSONC syntax
37
36
  * errors (recovers to empty options) where 5.9.3 reported a passthrough
38
37
  * diagnostic, so this lane validates the config's JSONC syntax itself
@@ -40,15 +39,16 @@
40
39
  * JSON.parse's wording rather than tsc's, the one message-text delta on
41
40
  * that path (no snapshot pins it). */
42
41
  import { builtinModules } from "node:module";
42
+ import { statSync } from "node:fs";
43
43
  import { dirname, resolve } from "node:path";
44
44
  import * as ts from "./ts7/adapter.js";
45
- import { strictNullChecksFloorDiag, tscPassthroughDiag, unsupportedDiag, } from "../diagnostics/diagnostic.js";
46
- import { isNodeModulesPath, nearestPkgJsonPath, projectDtsRuntimeSibling, resolveBareModule, resolveProjectImport, resolveRelativeModule, resolveTypeDirective, setProjectRealm } from "./resolve.js";
45
+ import { commonJsModuleSyntaxDiag, invalidPackageConfigDiag, strictNullChecksFloorDiag, tscPassthroughDiag, unsupportedDiag, } from "../diagnostics/diagnostic.js";
46
+ import { isNodeModulesPath, nearestInvalidPackageJsonPath, nearestPackageType, nearestPkgJsonPath, projectDtsRuntimeSibling, resolveBareModule, resolveProjectImport, resolveRelativeModule, resolveTypeDirective, setProjectRealm } from "./resolve.js";
47
47
  import { probeNodeImportRefusal, probeNodeRequireRefusal } from "./npm.js";
48
48
  import { isNpmStaticPackage, npmStaticActive, npmStaticFsShadow, npmStaticPackageOfPath, reportNpmStaticOffender, setNpmStaticPackages } from "./npm-static.js";
49
49
  import { provenanceEntryFor, provenancePaths } from "./provenance-registry.js";
50
50
  import { cjsLexerVisibleNames } from "./cjs-lexer.js";
51
- import { ADOPTED_OPTIONS, ambientDtsPath, builtinDefaultImportModule, canonicalBuiltinModule, clearWorkspacePackages, fallbackDtsPath, isJsSourceFileName, isNodeTypesPath, isRelativeSpecifier, isWorkspacePackageName, JS_ANY_OPERATOR_CODES, JS_RELAXED_TSC_CODES, overridesDtsPath, registerWorkspacePackage, SUPPORTED_NODE_MODULES, unsupportedModuleFeatureOf, workspacePackageOfPath, } from "./shared.js";
51
+ import { ADOPTED_OPTIONS, ambientDtsPath, builtinDefaultImportModule, canonicalBuiltinModule, clearWorkspacePackages, fallbackDtsPath, isJsSourceFileName, isNodeTypesPath, isRelativeSpecifier, isWorkspacePackageName, JS_ANY_OPERATOR_CODES, JS_RELAXED_TSC_CODES, overridesDtsPath, registerWorkspacePackage, SUPPORTED_NODE_MODULES, tsgoPath, unsupportedModuleFeatureOf, workspacePackageOfPath, } from "./shared.js";
52
52
  const BASE_OPTIONS = {
53
53
  strict: true,
54
54
  };
@@ -56,6 +56,14 @@ const FORCED_OPTIONS = {
56
56
  target: ts.ScriptTarget.ESNext,
57
57
  module: ts.ModuleKind.ESNext,
58
58
  moduleResolution: ts.ModuleResolutionKind.Bundler,
59
+ // Every file Node executes has its own lexical module wrapper: ESM has a
60
+ // module environment and CommonJS has the per-file function wrapper. In
61
+ // particular, an ambiguous file whose ONLY ESM marker is top-level await
62
+ // must not remain a TypeScript global script (otherwise declarations in
63
+ // sibling files merge and reads cross module boundaries). Runtime format
64
+ // classification is intentionally independent below; this option is only
65
+ // the binder's scope decision.
66
+ moduleDetection: ts.ModuleDetectionKind.Force,
59
67
  lib: ["lib.es2025.d.ts"],
60
68
  types: [],
61
69
  allowImportingTsExtensions: true,
@@ -145,7 +153,81 @@ function resolveNodeTypes7(entryPath) {
145
153
  const file = resolveTypeDirective("node", entryPath);
146
154
  return file !== null && isNodeTypesPath(file) ? file : null;
147
155
  }
148
- function loadProgram7(host, entryPath) {
156
+ /** True when a coverage mapping names one exact bare host module. TypeScript
157
+ * gives `paths` keys containing `*` pattern semantics, so accepting one here
158
+ * would silently broaden the mapping beyond the specifier the caller named. */
159
+ export function isExactExternalTypeSpecifier(specifier) {
160
+ return (specifier !== "" &&
161
+ !specifier.startsWith(".") &&
162
+ !specifier.startsWith("/") &&
163
+ !specifier.startsWith("#") &&
164
+ !specifier.startsWith("node:") &&
165
+ !specifier.includes("*"));
166
+ }
167
+ function externalHostModuleDiag7(specifier, node) {
168
+ return unsupportedDiag("SC1010", locOf7(node), `the '${specifier}' external host module (types supplied by --external-types, but no runtime implementation or scriptc lowering was provided)`, "the declaration mapping is analysis-only: coverage continues through project code, while executing this module requires an embedder integration with explicit runtime semantics");
169
+ }
170
+ /** Expand each mapped declaration entry through RELATIVE declaration
171
+ * dependencies. Declaration packages commonly expose a barrel index.d.ts;
172
+ * the structural types declared in its sibling files are part of the same
173
+ * checker-only host surface. Bare imports deliberately do not inherit this
174
+ * trust: they name a separate package/surface and need their own mapping. */
175
+ function externalTypeFileClosure7(program, externalTypes) {
176
+ const ownersByFile = new Map();
177
+ const addOwner = (file, specifier) => {
178
+ let owners = ownersByFile.get(file);
179
+ if (owners === undefined) {
180
+ owners = new Set();
181
+ ownersByFile.set(file, owners);
182
+ }
183
+ if (owners.has(specifier))
184
+ return false;
185
+ owners.add(specifier);
186
+ return true;
187
+ };
188
+ for (const [specifier, file] of externalTypes) {
189
+ addOwner(tsgoPath(resolve(file)), specifier);
190
+ }
191
+ const queue = [];
192
+ for (const [owner, entry] of externalTypes) {
193
+ const file = tsgoPath(resolve(entry));
194
+ const sf = program.getSourceFile(file);
195
+ if (sf?.isDeclarationFile)
196
+ queue.push({ sf, owner });
197
+ }
198
+ const visited = new Set();
199
+ while (queue.length > 0) {
200
+ const { sf, owner } = queue.shift();
201
+ const file = tsgoPath(resolve(sf.fileName));
202
+ const visitKey = `${file}\0${owner}`;
203
+ if (visited.has(visitKey))
204
+ continue;
205
+ visited.add(visitKey);
206
+ const admit = (dep) => {
207
+ if (dep === null || !dep.isDeclarationFile)
208
+ return;
209
+ const depFile = tsgoPath(resolve(dep.fileName));
210
+ if (!addOwner(depFile, owner))
211
+ return;
212
+ queue.push({ sf: dep, owner });
213
+ };
214
+ // SourceFile.imports includes import/export declarations, import =
215
+ // require(), and import("…") type nodes. Only relative edges inherit
216
+ // the mapped entry's ownership.
217
+ for (const node of sf.imports) {
218
+ if (ts.isStringLiteralLike(node) && isRelativeSpecifier(node.text)) {
219
+ admit(resolveImport7(program, sf, node.text));
220
+ }
221
+ }
222
+ // Triple-slash path references are the other declaration-local edge.
223
+ for (const ref of sf.referencedFiles) {
224
+ const depPath = tsgoPath(resolve(dirname(sf.fileName), ref.fileName));
225
+ admit(program.getSourceFile(depPath) ?? null);
226
+ }
227
+ }
228
+ return new Map([...ownersByFile].map(([file, owners]) => [file, [...owners]]));
229
+ }
230
+ function loadProgram7(host, entryPath, externalTypes = new Map()) {
149
231
  const config = adoptProjectConfig7(host, entryPath);
150
232
  const nodeTypes = config.configFile ? resolveNodeTypes7(entryPath) : null;
151
233
  // skipLibCheck is FORCED with @types/node in the program: checking a
@@ -164,20 +246,28 @@ function loadProgram7(host, entryPath) {
164
246
  // so tsgo's OWN resolution of the bare specifiers lands on the same
165
247
  // source files the preflight resolver answers — the checker types the
166
248
  // driver against the package's real TypeScript, not its shipped .d.ts.
167
- const paths = provenancePaths();
168
- if (paths !== null)
249
+ const provenance = provenancePaths();
250
+ if (provenance !== null || externalTypes.size > 0) {
251
+ const paths = { ...(provenance ?? {}) };
252
+ for (const [specifier, declarationPath] of externalTypes) {
253
+ paths[specifier] = [declarationPath];
254
+ }
169
255
  options = { ...options, paths };
256
+ }
170
257
  const coreRoots = [entryPath, ambientDtsPath(), nodeTypes ?? fallbackDtsPath()];
171
258
  const program = ts.createProgram([...coreRoots, overridesDtsPath()], options, host);
172
259
  const entry = program.getSourceFile(entryPath);
173
260
  if (!entry)
174
261
  throw new Error(`could not load ${entryPath}`);
262
+ const externalTypeSpecifiersByFile = externalTypeFileClosure7(program, externalTypes);
175
263
  let projectWorld = null;
176
264
  return {
177
265
  program,
178
266
  entry,
179
267
  moduleOrder: [],
180
268
  configDiags: config.diags,
269
+ externalTypes,
270
+ externalTypeSpecifiersByFile,
181
271
  projectWorld: () => (projectWorld ??= ts.createProgram(coreRoots, options, host)),
182
272
  disposeAll: () => {
183
273
  projectWorld?.dispose();
@@ -193,6 +283,27 @@ export function loadProgram(entryPath, opts) {
193
283
  // Absolute from the start: tsgo's world is absolute-path-keyed (the CLI
194
284
  // resolves before calling; this covers direct API callers too).
195
285
  entryPath = resolve(entryPath);
286
+ const externalTypeEntries = opts?.externalTypes instanceof Map
287
+ ? [...opts.externalTypes]
288
+ : Object.entries(opts?.externalTypes ?? {});
289
+ const externalTypes = new Map();
290
+ for (const [specifier, file] of externalTypeEntries) {
291
+ if (!isExactExternalTypeSpecifier(specifier)) {
292
+ throw new TypeError(`invalid external type specifier ${JSON.stringify(specifier)} (expected an exact bare package specifier)`);
293
+ }
294
+ if (!/\.d\.(?:ts|mts|cts)$/.test(file)) {
295
+ throw new TypeError(`invalid external type declaration ${JSON.stringify(file)} for ${JSON.stringify(specifier)} (expected a .d.ts, .d.mts, or .d.cts file)`);
296
+ }
297
+ const declarationPath = resolve(file);
298
+ try {
299
+ if (!statSync(declarationPath).isFile())
300
+ throw new Error("not a file");
301
+ }
302
+ catch {
303
+ throw new TypeError(`external type declaration for ${JSON.stringify(specifier)} does not name a readable file: ${declarationPath}`);
304
+ }
305
+ externalTypes.set(specifier, declarationPath);
306
+ }
196
307
  setNpmStaticPackages(opts?.npmStatic ?? []);
197
308
  // Workspace-package registrations reset per load (same discipline as the
198
309
  // npm-static set), then the opted-in names are probed UP FRONT: a
@@ -223,7 +334,7 @@ export function loadProgram(entryPath, opts) {
223
334
  hideFile: (path) => (npmShadow?.hideFile(path) ?? false) || projectDtsRuntimeSibling(path) !== null,
224
335
  };
225
336
  const host = new ts.Ts7Host({ cwd: dirname(entryPath), fsShadow });
226
- const load = loadProgram7(host, entryPath);
337
+ const load = loadProgram7(host, entryPath, externalTypes);
227
338
  return {
228
339
  ...load,
229
340
  dispose: () => {
@@ -436,17 +547,198 @@ function nestedBareRequiresOf7(sf) {
436
547
  });
437
548
  return out;
438
549
  }
439
- /** True when Node would treat this file as an ES MODULE (never defining
440
- * require/__dirname there): .mjs always, .cjs never, and .js/.ts by
441
- * syntactic module detection — spelled to 5.9.3's OBSERVED bundler-mode
442
- * behavior (it set impliedNodeFormat only for the mjs/cjs families; 7's
443
- * client SourceFile has no impliedNodeFormat at all). */
444
- function isNodeEsmFile7(sf) {
445
- if (sf.fileName.endsWith(".cjs") || sf.fileName.endsWith(".cts"))
550
+ function stripRequireCasts7(expr) {
551
+ let cur = expr;
552
+ while (ts.isParenthesizedExpression(cur) ||
553
+ ts.isAsExpression(cur) ||
554
+ ts.isTypeAssertion(cur) ||
555
+ ts.isNonNullExpression(cur)) {
556
+ cur = cur.expression;
557
+ }
558
+ return cur;
559
+ }
560
+ /** The supported-builtin provenance of an imported identifier, narrowed to
561
+ * the one member this preflight distinction needs. Mirrors the lowering's
562
+ * builtinImportOf alias handling so a re-export facade remains supported. */
563
+ function isCreateRequireImport7(program, ident) {
564
+ const checker = program.getTypeChecker();
565
+ const symbol = checker.getSymbolAtLocation(ident);
566
+ const decl = symbol ? checker.declarationsOf(symbol)[0] : undefined;
567
+ if (decl === undefined || !ts.isImportSpecifier(decl))
568
+ return false;
569
+ const importDecl = decl.parent.parent.parent;
570
+ if (ts.isImportDeclaration(importDecl) && ts.isStringLiteral(importDecl.moduleSpecifier)) {
571
+ const module = canonicalBuiltinModule(importDecl.moduleSpecifier.text);
572
+ const member = decl.propertyName?.text ?? decl.name.text;
573
+ if (module === "module" && member === "createRequire")
574
+ return true;
575
+ }
576
+ if (symbol !== undefined && (symbol.flags & ts.SymbolFlags.Alias) !== 0) {
577
+ const target = checker.getAliasedSymbol(symbol);
578
+ const targetDecl = checker.declarationsOf(target)[0];
579
+ if (targetDecl !== undefined && targetDecl.getSourceFile().isDeclarationFile) {
580
+ for (let p = targetDecl.parent; p !== undefined && !ts.isSourceFile(p); p = p.parent) {
581
+ if (ts.isModuleDeclaration(p) && ts.isStringLiteral(p.name)) {
582
+ return canonicalBuiltinModule(p.name.text) === "module" && target.name === "createRequire";
583
+ }
584
+ }
585
+ }
586
+ }
587
+ return false;
588
+ }
589
+ /** True only for the createRequire binding shape the lowering recognizes:
590
+ * a const initialized from node:module's createRequire with a base naming
591
+ * the current file. Arbitrary source declarations named `require` must not
592
+ * ride the module-edge lowering, which would erase their calls. */
593
+ function isCreateRequireBinding7(program, callee) {
594
+ const checker = program.getTypeChecker();
595
+ const symbol = checker.getSymbolAtLocation(callee);
596
+ const decl = symbol
597
+ ? checker.declarationsOf(symbol).find((d) => ts.isVariableDeclaration(d))
598
+ : undefined;
599
+ if (decl === undefined ||
600
+ decl.initializer === undefined ||
601
+ !ts.isVariableDeclarationList(decl.parent) ||
602
+ (decl.parent.flags & ts.NodeFlags.Const) === 0) {
603
+ return false;
604
+ }
605
+ const init = stripRequireCasts7(decl.initializer);
606
+ if (!ts.isCallExpression(init) ||
607
+ init.questionDotToken !== undefined ||
608
+ !ts.isIdentifier(init.expression) ||
609
+ !isCreateRequireImport7(program, init.expression) ||
610
+ init.arguments.length !== 1) {
446
611
  return false;
447
- if (sf.fileName.endsWith(".mjs") || sf.fileName.endsWith(".mts"))
612
+ }
613
+ const base = stripRequireCasts7(init.arguments[0]);
614
+ if (ts.isIdentifier(base) && base.text === "__filename")
448
615
  return true;
449
- return ts.isExternalModule(sf);
616
+ return (ts.isPropertyAccessExpression(base) &&
617
+ base.questionDotToken === undefined &&
618
+ ts.isMetaProperty(base.expression) &&
619
+ base.expression.keywordToken === ts.SyntaxKind.ImportKeyword &&
620
+ (base.name.text === "url" || base.name.text === "filename"));
621
+ }
622
+ /** Classifies a require-shaped call as Node's ambient CommonJS global, the
623
+ * one supported createRequire source binding, or another source binding.
624
+ * The scanners still collect createRequire calls because they carry static
625
+ * module edges; other source bindings get a pointed fence before lowering
626
+ * can mistake them for module syntax. */
627
+ function requireCallBindingKind7(program, node) {
628
+ const call = ts.isVariableDeclaration(node) ? node.initializer : node;
629
+ if (!call || !ts.isCallExpression(call) || !ts.isIdentifier(call.expression))
630
+ return "ambient";
631
+ const checker = program.getTypeChecker();
632
+ const symbol = checker.getSymbolAtLocation(call.expression);
633
+ if (symbol === undefined)
634
+ return "ambient";
635
+ const decls = checker.declarationsOf(symbol);
636
+ if (decls.length === 0 || decls.every((d) => d.getSourceFile().isDeclarationFile))
637
+ return "ambient";
638
+ return isCreateRequireBinding7(program, call.expression) ? "createRequire" : "source";
639
+ }
640
+ function esmRequireFeature7(kind) {
641
+ return kind === "ambient"
642
+ ? "require() in an ES module (Node throws ReferenceError — use import)"
643
+ : "calls through a source binding named 'require' (this spelling is reserved for CommonJS/createRequire module edges — rename the binding)";
644
+ }
645
+ const CJS_WRAPPER_NAMES = new Set(["require", "module", "exports", "__dirname", "__filename"]);
646
+ function bindingDeclaresCjsWrapper7(name) {
647
+ if (ts.isIdentifier(name))
648
+ return CJS_WRAPPER_NAMES.has(name.text) ? name : null;
649
+ for (const el of name.elements) {
650
+ if (el.name === undefined)
651
+ continue;
652
+ const hit = bindingDeclaresCjsWrapper7(el.name);
653
+ if (hit !== null)
654
+ return hit;
655
+ }
656
+ return null;
657
+ }
658
+ function insideFunctionLike7(node) {
659
+ for (let p = node.parent; p !== undefined && !ts.isSourceFile(p); p = p.parent) {
660
+ if (ts.isFunctionLike(p))
661
+ return true;
662
+ }
663
+ return false;
664
+ }
665
+ /** The first syntax marker Node's ambiguous-file detector recognizes. This
666
+ * cannot use ts.isExternalModule: moduleDetection=force deliberately gives
667
+ * EVERY executable file module-local checker scope, including CommonJS.
668
+ * Runtime classification remains Node's own narrower question: value-level
669
+ * import/export forms, import.meta, top-level await/for-await, or a top-level
670
+ * lexical declaration that would redeclare a CommonJS wrapper binding. */
671
+ function nodeEsmSyntaxMarker7(sf) {
672
+ for (const stmt of sf.statements) {
673
+ if (ts.isImportDeclaration(stmt) && !erasedTypeOnlyImport(stmt))
674
+ return stmt;
675
+ if (ts.isExportDeclaration(stmt) &&
676
+ !stmt.isTypeOnly &&
677
+ !erasedTypeOnlyReexport(stmt)) {
678
+ return stmt;
679
+ }
680
+ if (ts.isExportAssignment(stmt))
681
+ return stmt;
682
+ if (ts.canHaveModifiers(stmt) &&
683
+ ts.getModifiers(stmt)?.some((m) => m.kind === ts.SyntaxKind.ExportKeyword) === true) {
684
+ return stmt;
685
+ }
686
+ if (ts.isVariableStatement(stmt) &&
687
+ (stmt.declarationList.flags & (ts.NodeFlags.Let | ts.NodeFlags.Const)) !== 0) {
688
+ for (const decl of stmt.declarationList.declarations) {
689
+ const hit = bindingDeclaresCjsWrapper7(decl.name);
690
+ if (hit !== null)
691
+ return hit;
692
+ }
693
+ }
694
+ if (ts.isClassDeclaration(stmt) && stmt.name !== undefined && CJS_WRAPPER_NAMES.has(stmt.name.text)) {
695
+ return stmt.name;
696
+ }
697
+ }
698
+ let found = null;
699
+ ts.walkPreorder(sf, (node) => {
700
+ if (ts.isMetaProperty(node) &&
701
+ node.keywordToken === ts.SyntaxKind.ImportKeyword) {
702
+ found = node;
703
+ return "stop";
704
+ }
705
+ if (!insideFunctionLike7(node) &&
706
+ (ts.isAwaitExpression(node) ||
707
+ (ts.isForOfStatement(node) && node.awaitModifier !== undefined))) {
708
+ found = node;
709
+ return "stop";
710
+ }
711
+ return undefined;
712
+ });
713
+ return found;
714
+ }
715
+ const nodeEsmFileCache7 = new WeakMap();
716
+ /** True when Node would treat this file as an ES MODULE (never defining
717
+ * require/__dirname there): fixed extensions first, then an explicit
718
+ * nearest-package type, then Node's syntax markers for ambiguous .js/.ts
719
+ * files. TypeScript's external-module bit is forced for checker scoping and
720
+ * therefore intentionally plays no part in this runtime decision. */
721
+ function isNodeEsmFile7(sf) {
722
+ const cached = nodeEsmFileCache7.get(sf);
723
+ if (cached !== undefined)
724
+ return cached;
725
+ let result;
726
+ if (sf.fileName.endsWith(".cjs") || sf.fileName.endsWith(".cts")) {
727
+ result = false;
728
+ }
729
+ else if (sf.fileName.endsWith(".mjs") || sf.fileName.endsWith(".mts")) {
730
+ result = true;
731
+ }
732
+ else {
733
+ const packageType = nearestPackageType(sf.fileName);
734
+ result = packageType === "module"
735
+ ? true
736
+ : packageType === "commonjs"
737
+ ? false
738
+ : nodeEsmSyntaxMarker7(sf) !== null;
739
+ }
740
+ nodeEsmFileCache7.set(sf, result);
741
+ return result;
450
742
  }
451
743
  /** A JavaScript source file Node treats as CommonJS (not an ES module):
452
744
  * ESM namespace/default machinery must not claim it — its export surface
@@ -1358,6 +1650,28 @@ function preflight7(load) {
1358
1650
  // files (a workspace package imported bare AND reached relatively)
1359
1651
  // stay program source — only the island-bound JS steps out.
1360
1652
  !islandJsFile(sf.fileName));
1653
+ // Node stops at the nearest package.json even when it is malformed, and
1654
+ // an explicit CommonJS scope (or .cjs/.cts extension) disables ambiguous-
1655
+ // file syntax detection entirely. TypeScript's bundler checker models
1656
+ // neither loader rule, so restore them before any module-edge analysis:
1657
+ // one malformed-scope diagnostic per package file, and one pointed syntax
1658
+ // diagnostic per CommonJS source file.
1659
+ const invalidPackageConfigs = new Set();
1660
+ for (const sf of userFiles) {
1661
+ const invalidConfig = nearestInvalidPackageJsonPath(sf.fileName);
1662
+ if (invalidConfig !== null) {
1663
+ if (!invalidPackageConfigs.has(invalidConfig)) {
1664
+ invalidPackageConfigs.add(invalidConfig);
1665
+ diags.push(invalidPackageConfigDiag(invalidConfig, { file: sf.fileName, start: 0, end: 0 }));
1666
+ }
1667
+ continue;
1668
+ }
1669
+ if (!isNodeEsmFile7(sf)) {
1670
+ const marker = nodeEsmSyntaxMarker7(sf);
1671
+ if (marker !== null)
1672
+ diags.push(commonJsModuleSyntaxDiag(locOf7(marker)));
1673
+ }
1674
+ }
1361
1675
  const ambientModules = new Set(SUPPORTED_NODE_MODULES);
1362
1676
  // Ambient `declare module "name"` declarations anywhere in the program —
1363
1677
  // exact names and `*` patterns — so the import fence can say "type
@@ -1422,7 +1736,13 @@ function preflight7(load) {
1422
1736
  // fence); `import type x = require(...)` is pure type surface and
1423
1737
  // lowers to nothing.
1424
1738
  if (ts.isExternalModuleReference(stmt.moduleReference) && !stmt.isTypeOnly) {
1425
- diags.push(unsupportedDiag("SC1013", locOf7(stmt), "import = require(...) assignments"));
1739
+ const spec = stmt.moduleReference.expression;
1740
+ if (spec !== undefined && ts.isStringLiteralLike(spec) && load.externalTypes.has(spec.text)) {
1741
+ diags.push(externalHostModuleDiag7(spec.text, stmt));
1742
+ }
1743
+ else {
1744
+ diags.push(unsupportedDiag("SC1013", locOf7(stmt), "import = require(...) assignments"));
1745
+ }
1426
1746
  }
1427
1747
  continue;
1428
1748
  }
@@ -1438,6 +1758,10 @@ function preflight7(load) {
1438
1758
  if (!stmt.moduleSpecifier)
1439
1759
  continue;
1440
1760
  const fromSpec = ts.isStringLiteral(stmt.moduleSpecifier) ? stmt.moduleSpecifier.text : "";
1761
+ if (load.externalTypes.has(fromSpec)) {
1762
+ diags.push(externalHostModuleDiag7(fromSpec, stmt));
1763
+ continue;
1764
+ }
1441
1765
  if (!isRelativeSpecifier(fromSpec)) {
1442
1766
  // NAMED re-exports from a SUPPORTED builtin pass (`export { ok }
1443
1767
  // from "node:assert"` — a universal re-export facade facade): the
@@ -1504,6 +1828,10 @@ function preflight7(load) {
1504
1828
  if (specNode === undefined || !ts.isStringLiteral(specNode))
1505
1829
  continue;
1506
1830
  const spec = specNode.text;
1831
+ if (load.externalTypes.has(spec)) {
1832
+ diags.push(externalHostModuleDiag7(spec, stmt));
1833
+ continue;
1834
+ }
1507
1835
  const isRelative = isRelativeSpecifier(spec);
1508
1836
  const isBare = !isRelative && !ambientModules.has(spec);
1509
1837
  // --npm-static: an opted-in package importing node:module admits
@@ -1702,7 +2030,13 @@ function preflight7(load) {
1702
2030
  for (const req of requiresOf7(stmt)) {
1703
2031
  const loc = { file: sf.fileName, start: req.node.getStart(sf), end: req.node.getEnd() };
1704
2032
  if (isNodeEsmFile7(sf)) {
1705
- diags.push(unsupportedDiag("SC1013", loc, "require() in an ES module (Node throws ReferenceError — use import)"));
2033
+ const bindingKind = requireCallBindingKind7(program, req.node);
2034
+ if (bindingKind !== "createRequire") {
2035
+ diags.push(unsupportedDiag("SC1013", loc, esmRequireFeature7(bindingKind)));
2036
+ continue;
2037
+ }
2038
+ }
2039
+ if (load.externalTypes.has(req.spec)) {
1706
2040
  continue;
1707
2041
  }
1708
2042
  if (req.decl && ts.isArrayBindingPattern(req.decl.name)) {
@@ -1764,37 +2098,45 @@ function preflight7(load) {
1764
2098
  deps.push({ dep });
1765
2099
  }
1766
2100
  }
1767
- if (!ts.isExternalModule(sf)) {
1768
- for (const call of nestedBareRequiresOf7(sf)) {
1769
- const spec = requireSpecOf7(call);
1770
- const loc = { file: sf.fileName, start: call.getStart(sf), end: call.getEnd() };
1771
- if (!isRelativeSpecifier(spec)) {
1772
- // --npm-static: opted-in packages ride the program-module edge
1773
- // (the statement-level require branch above).
1774
- const npmReq = !spec.startsWith("#") ? resolveNpmImport7(sf.fileName, spec) : null;
1775
- if (npmReq !== null && isNpmStaticPackage(npmReq.packageName)) {
1776
- const nDep = npmStaticProgramDep(program, npmReq.packageName, npmReq.typesFile);
1777
- if (nDep !== null)
1778
- deps.push({ dep: nDep });
1779
- continue;
1780
- }
1781
- if (canonicalBuiltinModule(spec) === null && !processModuleAliasRequire7(spec, null)) {
1782
- // Binding-less by construction — same require-site throw
1783
- // channel as the statement-level form above.
1784
- if (probeNodeRequireRefusal(sf.fileName, spec) === null) {
1785
- diags.push(unsupportedDiag("SC1010", loc, unsupportedModuleFeatureOf(spec)));
1786
- }
1787
- }
2101
+ for (const call of nestedBareRequiresOf7(sf)) {
2102
+ const spec = requireSpecOf7(call);
2103
+ const loc = { file: sf.fileName, start: call.getStart(sf), end: call.getEnd() };
2104
+ if (isNodeEsmFile7(sf)) {
2105
+ const bindingKind = requireCallBindingKind7(program, call);
2106
+ if (bindingKind !== "createRequire") {
2107
+ diags.push(unsupportedDiag("SC1013", loc, esmRequireFeature7(bindingKind)));
1788
2108
  continue;
1789
2109
  }
1790
- const dep = resolveImport7(program, sf, spec);
1791
- if (dep && dep.fileName.endsWith(".json")) {
1792
- diags.push(unsupportedDiag("SC1012", loc, "require() of JSON modules"));
2110
+ }
2111
+ if (load.externalTypes.has(spec)) {
2112
+ continue;
2113
+ }
2114
+ if (!isRelativeSpecifier(spec)) {
2115
+ // --npm-static: opted-in packages ride the program-module edge
2116
+ // (the statement-level require branch above).
2117
+ const npmReq = !spec.startsWith("#") ? resolveNpmImport7(sf.fileName, spec) : null;
2118
+ if (npmReq !== null && isNpmStaticPackage(npmReq.packageName)) {
2119
+ const nDep = npmStaticProgramDep(program, npmReq.packageName, npmReq.typesFile);
2120
+ if (nDep !== null)
2121
+ deps.push({ dep: nDep });
1793
2122
  continue;
1794
2123
  }
1795
- if (dep)
1796
- deps.push({ dep });
2124
+ if (canonicalBuiltinModule(spec) === null && !processModuleAliasRequire7(spec, null)) {
2125
+ // Binding-less by construction — same require-site throw
2126
+ // channel as the statement-level form above.
2127
+ if (probeNodeRequireRefusal(sf.fileName, spec) === null) {
2128
+ diags.push(unsupportedDiag("SC1010", loc, unsupportedModuleFeatureOf(spec)));
2129
+ }
2130
+ }
2131
+ continue;
2132
+ }
2133
+ const dep = resolveImport7(program, sf, spec);
2134
+ if (dep && dep.fileName.endsWith(".json")) {
2135
+ diags.push(unsupportedDiag("SC1012", loc, "require() of JSON modules"));
2136
+ continue;
1797
2137
  }
2138
+ if (dep)
2139
+ deps.push({ dep });
1798
2140
  }
1799
2141
  }
1800
2142
  }