@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.
- package/ambient/scriptc-node-fallback.d.ts +117 -37
- package/dist/backend/cc-cache.test.d.ts +1 -0
- package/dist/backend/cc-cache.test.js +2507 -0
- package/dist/backend/cc-cache.test.js.map +1 -0
- package/dist/backend/cc.d.ts +69 -11
- package/dist/backend/cc.js +1937 -222
- package/dist/backend/cc.js.map +1 -1
- package/dist/backend/emission/emit-async.js +3 -1
- package/dist/backend/emission/emit-async.js.map +1 -1
- package/dist/backend/emission/emit-exprs.d.ts +10 -0
- package/dist/backend/emission/emit-exprs.js +482 -18
- package/dist/backend/emission/emit-exprs.js.map +1 -1
- package/dist/backend/emission/emit-stmts.js +13 -5
- package/dist/backend/emission/emit-stmts.js.map +1 -1
- package/dist/backend/emission/emit-types.js +4 -1
- package/dist/backend/emission/emit-types.js.map +1 -1
- package/dist/backend/emission/emit-walkers.js +108 -7
- package/dist/backend/emission/emit-walkers.js.map +1 -1
- package/dist/backend/emission/emitter.d.ts +27 -1
- package/dist/backend/emission/emitter.js +84 -3
- package/dist/backend/emission/emitter.js.map +1 -1
- package/dist/backend/llvm/dyn.d.ts +1 -0
- package/dist/backend/llvm/dyn.js +305 -8
- package/dist/backend/llvm/dyn.js.map +1 -1
- package/dist/backend/llvm/emitter.js +831 -23
- package/dist/backend/llvm/emitter.js.map +1 -1
- package/dist/backend/llvm/shapes.js +3 -2
- package/dist/backend/llvm/shapes.js.map +1 -1
- package/dist/compat/fetch-profile.d.ts +118 -0
- package/dist/compat/fetch-profile.js +531 -0
- package/dist/compat/fetch-profile.js.map +1 -0
- package/dist/coverage/surface-manifest.js +69 -0
- package/dist/coverage/surface-manifest.js.map +1 -1
- package/dist/diagnostics/diagnostic.d.ts +10 -0
- package/dist/diagnostics/diagnostic.js +27 -1
- package/dist/diagnostics/diagnostic.js.map +1 -1
- package/dist/frontend/lowering/lower-builtins.d.ts +24 -15
- package/dist/frontend/lowering/lower-builtins.js +217 -69
- package/dist/frontend/lowering/lower-builtins.js.map +1 -1
- package/dist/frontend/lowering/lower-calls.js +41 -0
- package/dist/frontend/lowering/lower-calls.js.map +1 -1
- package/dist/frontend/lowering/lower-classes.js +32 -11
- package/dist/frontend/lowering/lower-classes.js.map +1 -1
- package/dist/frontend/lowering/lower-exprs.d.ts +3 -3
- package/dist/frontend/lowering/lower-exprs.js +87 -15
- package/dist/frontend/lowering/lower-exprs.js.map +1 -1
- package/dist/frontend/lowering/lower-generators.js +7 -1
- package/dist/frontend/lowering/lower-generators.js.map +1 -1
- package/dist/frontend/lowering/lower-island.d.ts +123 -7
- package/dist/frontend/lowering/lower-island.js +1976 -26
- package/dist/frontend/lowering/lower-island.js.map +1 -1
- package/dist/frontend/lowering/lower-modules.js +17 -1
- package/dist/frontend/lowering/lower-modules.js.map +1 -1
- package/dist/frontend/lowering/lower-stmts.js +33 -9
- package/dist/frontend/lowering/lower-stmts.js.map +1 -1
- package/dist/frontend/lowering/lowerer.d.ts +40 -0
- package/dist/frontend/lowering/lowerer.js +290 -18
- package/dist/frontend/lowering/lowerer.js.map +1 -1
- package/dist/frontend/lowering/surfaces.js +55 -12
- package/dist/frontend/lowering/surfaces.js.map +1 -1
- package/dist/frontend/program.d.ts +20 -4
- package/dist/frontend/program.js +391 -49
- package/dist/frontend/program.js.map +1 -1
- package/dist/frontend/resolve.d.ts +10 -0
- package/dist/frontend/resolve.js +37 -0
- package/dist/frontend/resolve.js.map +1 -1
- package/dist/frontend/ts7/enums.d.ts +9 -0
- package/dist/frontend/ts7/enums.js +8 -6
- package/dist/frontend/ts7/enums.js.map +1 -1
- package/dist/frontend/ts7/program.js +4 -1
- package/dist/frontend/ts7/program.js.map +1 -1
- package/dist/frontend/types.d.ts +16 -9
- package/dist/frontend/types.js +119 -38
- package/dist/frontend/types.js.map +1 -1
- package/dist/index.d.ts +7 -1
- package/dist/index.js +70 -14
- package/dist/index.js.map +1 -1
- package/dist/ir/nodes.d.ts +55 -26
- package/dist/ir/nodes.js +42 -29
- package/dist/ir/nodes.js.map +1 -1
- package/dist/ir/validate.js +106 -9
- package/dist/ir/validate.js.map +1 -1
- package/dist/library/int-infer.js +7 -1
- package/dist/library/int-infer.js.map +1 -1
- package/dist/library/int-infer.test.js +80 -0
- package/dist/library/int-infer.test.js.map +1 -1
- package/dist/library/sidecar-validate.js +5 -0
- package/dist/library/sidecar-validate.js.map +1 -1
- package/dist/library/sidecar.d.ts +3 -0
- package/dist/library/sidecar.js.map +1 -1
- package/package.json +2 -2
- package/surface-manifest.json +1097 -130
package/dist/frontend/program.js
CHANGED
|
@@ -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:
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
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
|
-
|
|
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
|
|
168
|
-
if (
|
|
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
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
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
|
-
|
|
612
|
+
}
|
|
613
|
+
const base = stripRequireCasts7(init.arguments[0]);
|
|
614
|
+
if (ts.isIdentifier(base) && base.text === "__filename")
|
|
448
615
|
return true;
|
|
449
|
-
return ts.
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
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
|
-
|
|
1791
|
-
|
|
1792
|
-
|
|
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 (
|
|
1796
|
-
|
|
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
|
}
|