limina 0.1.1 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/chunks/{dep-C5gcXDHp.js → dep-DJz9JBTi.js} +119 -10
- package/chunks/dep-mnWOqiGN.js +244 -0
- package/cli.js +1488 -386
- package/flow-renderer-process.js +23 -31
- package/index.js +1 -1
- package/package.json +1 -1
- package/schemas/tsconfig-schema.json +23 -0
- package/chunks/dep-CuMHuWBQ.js +0 -87
package/cli.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { a as __toESM, i as __require, n as __commonJSMin, r as __exportAll, t as require_picocolors } from "./chunks/dep-BPK-6PAr.js";
|
|
3
|
-
import { A as
|
|
4
|
-
import { a as
|
|
3
|
+
import { A as isPackageImportSpecifier, C as resolveRelativeModuleCandidate, D as toPosixPath, E as normalizeSlashes, F as uniqueBy, I as uniqueSortedStrings, L as uniqueTrimmedNonEmptySortedStrings, M as isUrlOrDataOrFileSpecifier, N as isVirtualModuleSpecifier, O as toRelativePath, P as posix, R as uniqueValues, S as resolvePathMappedModuleCandidate, T as normalizeAbsolutePath, _ as resolveModuleNameWithCheckers, a as formatUnknownValue, b as resolveBaseUrlModuleCandidate, c as clearCheckerProjectConfigCache, d as getBuildCheckerSupportedExtensions, f as getCheckerAdapter, g as resolveCheckerProjectExtensions, h as parseCheckerProjectConfigForContext, i as loadConfig, j as isRelativeSpecifier, k as isBarePackageSpecifier, l as collectMissingCheckerPeerDependencies, m as normalizeExtensions, n as getActiveCheckers, o as isNonEmptyString, p as getCheckerExtensions, r as isAutoCheckerConfigMode, s as isPlainRecord, u as formatMissingCheckerPeerDependencies, v as resolveModuleNameWithCheckersDetailed, w as isPathInsideDirectory, x as resolveExistingFilePath, y as candidatePathsForBasePath } from "./chunks/dep-DJz9JBTi.js";
|
|
4
|
+
import { a as SPINNER_FRAMES, c as formatMessageWithElapsed, d as toTreeFlowStatus, f as toWritableText, i as writeWithFlowArgs, l as hasRunningSnapshotWork, n as TerminalFrameTracker, o as SPINNER_INTERVAL_MS, r as patchWriteStream, s as formatInteractiveLine, t as DEFAULT_TERMINAL_COLUMNS, u as renderSnapshotLinesForTerminal } from "./chunks/dep-mnWOqiGN.js";
|
|
5
5
|
import { builtinModules, createRequire } from "node:module";
|
|
6
6
|
import { existsSync, lstatSync, readFileSync, readdirSync, statSync } from "node:fs";
|
|
7
7
|
import ts from "typescript";
|
|
@@ -12,7 +12,7 @@ import { parseSync, rawTransferSupported } from "oxc-parser";
|
|
|
12
12
|
import { ResolverFactory } from "oxc-resolver";
|
|
13
13
|
import fs, { access, mkdir, mkdtemp, readFile, readdir, rm, rmdir, writeFile } from "node:fs/promises";
|
|
14
14
|
import { glob } from "tinyglobby";
|
|
15
|
-
import
|
|
15
|
+
import process$1, { stdin, stdout } from "node:process";
|
|
16
16
|
import os, { availableParallelism, tmpdir } from "node:os";
|
|
17
17
|
import tty, { ReadStream } from "node:tty";
|
|
18
18
|
import { createHash } from "node:crypto";
|
|
@@ -361,7 +361,7 @@ function parsePnpmWorkspaceListJson(source) {
|
|
|
361
361
|
}];
|
|
362
362
|
});
|
|
363
363
|
}
|
|
364
|
-
function getManifestPackageName$
|
|
364
|
+
function getManifestPackageName$2(manifest) {
|
|
365
365
|
return typeof manifest.name === "string" && manifest.name.trim().length > 0 ? manifest.name.trim() : null;
|
|
366
366
|
}
|
|
367
367
|
function isNamedWorkspacePackage(workspacePackage) {
|
|
@@ -370,7 +370,7 @@ function isNamedWorkspacePackage(workspacePackage) {
|
|
|
370
370
|
function readWorkspacePackage(options) {
|
|
371
371
|
const packageJsonPath = normalizeAbsolutePath(options.packageJsonPath);
|
|
372
372
|
const manifest = readJsonFile(packageJsonPath);
|
|
373
|
-
const name = getManifestPackageName$
|
|
373
|
+
const name = getManifestPackageName$2(manifest);
|
|
374
374
|
return {
|
|
375
375
|
directory: normalizeAbsolutePath(posix.dirname(packageJsonPath)),
|
|
376
376
|
manifest,
|
|
@@ -1217,6 +1217,18 @@ function createImportAnalysisContext(options = {}) {
|
|
|
1217
1217
|
caches.importsCache.set(cacheKey, imports);
|
|
1218
1218
|
return imports;
|
|
1219
1219
|
};
|
|
1220
|
+
const resolveTypeScriptImport = (specifier, containingFile, compilerOptions, contextOrExtensions) => resolveModuleNameWithCheckersDetailed({
|
|
1221
|
+
compilerOptions,
|
|
1222
|
+
containingFile: normalizeAbsolutePath(containingFile),
|
|
1223
|
+
context: normalizeContextInput(contextOrExtensions),
|
|
1224
|
+
specifier
|
|
1225
|
+
});
|
|
1226
|
+
const resolveOxcImport = (specifier, containingFile, compilerOptions, contextOrExtensions) => resolveModuleNameWithOxcCaches(caches, {
|
|
1227
|
+
compilerOptions,
|
|
1228
|
+
containingFile: normalizeAbsolutePath(containingFile),
|
|
1229
|
+
context: normalizeContextInput(contextOrExtensions),
|
|
1230
|
+
specifier
|
|
1231
|
+
});
|
|
1220
1232
|
const resolveInternalImport = (specifier, containingFile, options, contextOrExtensions) => {
|
|
1221
1233
|
const normalizedContainingFile = normalizeAbsolutePath(containingFile);
|
|
1222
1234
|
const context = normalizeContextInput(contextOrExtensions);
|
|
@@ -1248,12 +1260,7 @@ function createImportAnalysisContext(options = {}) {
|
|
|
1248
1260
|
const cached = caches.resolutionCache.get(cacheKey);
|
|
1249
1261
|
if (cached !== void 0) return cached;
|
|
1250
1262
|
const preferTypeScriptResolver = hasTypeScriptOnlyResolutionOptions(options);
|
|
1251
|
-
const resolved = (preferTypeScriptResolver ?
|
|
1252
|
-
compilerOptions: options,
|
|
1253
|
-
containingFile: normalizedContainingFile,
|
|
1254
|
-
context,
|
|
1255
|
-
specifier
|
|
1256
|
-
}) : null) ?? resolveRelativeModuleCandidate({
|
|
1263
|
+
const resolved = (preferTypeScriptResolver ? resolveTypeScriptImport(specifier, normalizedContainingFile, options, context)?.resolvedFileName : null) ?? resolveRelativeModuleCandidate({
|
|
1257
1264
|
containingFile: normalizedContainingFile,
|
|
1258
1265
|
extensions,
|
|
1259
1266
|
specifier
|
|
@@ -1265,12 +1272,7 @@ function createImportAnalysisContext(options = {}) {
|
|
|
1265
1272
|
compilerOptions: options,
|
|
1266
1273
|
extensions,
|
|
1267
1274
|
specifier
|
|
1268
|
-
}) ?? (preferTypeScriptResolver ? null :
|
|
1269
|
-
compilerOptions: options,
|
|
1270
|
-
containingFile: normalizedContainingFile,
|
|
1271
|
-
context,
|
|
1272
|
-
specifier
|
|
1273
|
-
}) ?? resolveModuleNameWithCheckers({
|
|
1275
|
+
}) ?? (preferTypeScriptResolver ? null : resolveOxcImport(specifier, normalizedContainingFile, options, context) ?? resolveModuleNameWithCheckers({
|
|
1274
1276
|
compilerOptions: options,
|
|
1275
1277
|
containingFile: normalizedContainingFile,
|
|
1276
1278
|
context,
|
|
@@ -1281,7 +1283,9 @@ function createImportAnalysisContext(options = {}) {
|
|
|
1281
1283
|
};
|
|
1282
1284
|
return {
|
|
1283
1285
|
collectImportsFromFile,
|
|
1284
|
-
resolveInternalImport
|
|
1286
|
+
resolveInternalImport,
|
|
1287
|
+
resolveOxcImport,
|
|
1288
|
+
resolveTypeScriptImport
|
|
1285
1289
|
};
|
|
1286
1290
|
}
|
|
1287
1291
|
function collectImportsFromFile(filePath, rootDir, context) {
|
|
@@ -1408,9 +1412,6 @@ function chooseOwningProject(projectPaths) {
|
|
|
1408
1412
|
function findPackageForFile(filePath, packages) {
|
|
1409
1413
|
return [...packages].sort((left, right) => right.directory.length - left.directory.length).find((workspacePackage) => isPathInsideDirectory(filePath, workspacePackage.directory)) ?? null;
|
|
1410
1414
|
}
|
|
1411
|
-
function findImporterForFile(filePath, importers) {
|
|
1412
|
-
return importers.find((importer) => isPathInsideDirectory(filePath, importer.directory)) ?? null;
|
|
1413
|
-
}
|
|
1414
1415
|
function shouldResolveThroughGraph(importer, targetPackage) {
|
|
1415
1416
|
if (!importer || !targetPackage?.name) return false;
|
|
1416
1417
|
return importer.name === targetPackage.name || importer.declaredWorkspaceDependencies.has(targetPackage.name);
|
|
@@ -1459,6 +1460,7 @@ const LIMINA_CHECK_ISSUE_CODES = {
|
|
|
1459
1460
|
graphConfigInvalid: "LIMINA_GRAPH_CONFIG_INVALID",
|
|
1460
1461
|
graphImportTargetUnmapped: "LIMINA_GRAPH_IMPORT_TARGET_UNMAPPED",
|
|
1461
1462
|
graphPrepareFailed: "LIMINA_GRAPH_PREPARE_FAILED",
|
|
1463
|
+
graphReferenceCycle: "LIMINA_GRAPH_REFERENCE_CYCLE",
|
|
1462
1464
|
graphReferenceExtra: "LIMINA_GRAPH_REFERENCE_EXTRA",
|
|
1463
1465
|
graphReferenceMissing: "LIMINA_GRAPH_REFERENCE_MISSING",
|
|
1464
1466
|
graphTargetUnreachable: "LIMINA_GRAPH_TARGET_UNREACHABLE",
|
|
@@ -1553,6 +1555,11 @@ const LIMINA_CHECK_ISSUE_RULE_METADATA = {
|
|
|
1553
1555
|
description: "Generated graph preparation failed.",
|
|
1554
1556
|
task: "graph:prepare"
|
|
1555
1557
|
},
|
|
1558
|
+
[LIMINA_CHECK_ISSUE_CODES.graphReferenceCycle]: {
|
|
1559
|
+
code: LIMINA_CHECK_ISSUE_CODES.graphReferenceCycle,
|
|
1560
|
+
description: "Generated TypeScript project references contain a cycle.",
|
|
1561
|
+
task: "graph:check"
|
|
1562
|
+
},
|
|
1556
1563
|
[LIMINA_CHECK_ISSUE_CODES.graphReferenceExtra]: {
|
|
1557
1564
|
code: LIMINA_CHECK_ISSUE_CODES.graphReferenceExtra,
|
|
1558
1565
|
description: "A TypeScript project reference exists without a matching source edge.",
|
|
@@ -2002,13 +2009,13 @@ const ansiStyles$1 = assembleStyles$1();
|
|
|
2002
2009
|
|
|
2003
2010
|
//#endregion
|
|
2004
2011
|
//#region ../../node_modules/.pnpm/chalk@5.6.2/node_modules/chalk/source/vendor/supports-color/index.js
|
|
2005
|
-
function hasFlag(flag, argv = globalThis.Deno ? globalThis.Deno.args :
|
|
2012
|
+
function hasFlag(flag, argv = globalThis.Deno ? globalThis.Deno.args : process$1.argv) {
|
|
2006
2013
|
const prefix = flag.startsWith("-") ? "" : flag.length === 1 ? "-" : "--";
|
|
2007
2014
|
const position = argv.indexOf(prefix + flag);
|
|
2008
2015
|
const terminatorPosition = argv.indexOf("--");
|
|
2009
2016
|
return position !== -1 && (terminatorPosition === -1 || position < terminatorPosition);
|
|
2010
2017
|
}
|
|
2011
|
-
const { env } =
|
|
2018
|
+
const { env } = process$1;
|
|
2012
2019
|
let flagForceColor;
|
|
2013
2020
|
if (hasFlag("no-color") || hasFlag("no-colors") || hasFlag("color=false") || hasFlag("color=never")) flagForceColor = 0;
|
|
2014
2021
|
else if (hasFlag("color") || hasFlag("colors") || hasFlag("color=true") || hasFlag("color=always")) flagForceColor = 1;
|
|
@@ -2041,7 +2048,7 @@ function _supportsColor(haveStream, { streamIsTTY, sniffFlags = true } = {}) {
|
|
|
2041
2048
|
if (haveStream && !streamIsTTY && forceColor === void 0) return 0;
|
|
2042
2049
|
const min = forceColor || 0;
|
|
2043
2050
|
if (env.TERM === "dumb") return min;
|
|
2044
|
-
if (
|
|
2051
|
+
if (process$1.platform === "win32") {
|
|
2045
2052
|
const osRelease = os.release().split(".");
|
|
2046
2053
|
if (Number(osRelease[0]) >= 10 && Number(osRelease[2]) >= 10586) return Number(osRelease[2]) >= 14931 ? 3 : 2;
|
|
2047
2054
|
return 1;
|
|
@@ -2821,7 +2828,7 @@ const NEWLINE = "\n";
|
|
|
2821
2828
|
const PAD = " ";
|
|
2822
2829
|
const NONE = "none";
|
|
2823
2830
|
const terminalColumns = () => {
|
|
2824
|
-
const { env, stdout, stderr } =
|
|
2831
|
+
const { env, stdout, stderr } = process$1;
|
|
2825
2832
|
if (stdout?.columns) return stdout.columns;
|
|
2826
2833
|
if (stderr?.columns) return stderr.columns;
|
|
2827
2834
|
if (env.COLUMNS) return Number.parseInt(env.COLUMNS, 10);
|
|
@@ -2964,8 +2971,8 @@ const boxContent = (content, contentWidth, options) => {
|
|
|
2964
2971
|
return result;
|
|
2965
2972
|
};
|
|
2966
2973
|
const sanitizeOptions = (options) => {
|
|
2967
|
-
if (options.fullscreen &&
|
|
2968
|
-
let newDimensions = [
|
|
2974
|
+
if (options.fullscreen && process$1?.stdout) {
|
|
2975
|
+
let newDimensions = [process$1.stdout.columns, process$1.stdout.rows];
|
|
2969
2976
|
if (typeof options.fullscreen === "function") newDimensions = options.fullscreen(...newDimensions);
|
|
2970
2977
|
options.width ||= newDimensions[0];
|
|
2971
2978
|
options.height ||= newDimensions[1];
|
|
@@ -3699,6 +3706,9 @@ function createSourceConfigScope(sourceConfigPath) {
|
|
|
3699
3706
|
if (fileName === "tsconfig.json") return "tsconfig";
|
|
3700
3707
|
return fileName.replace(/^tsconfig\./u, "").replace(/\.json$/u, "");
|
|
3701
3708
|
}
|
|
3709
|
+
function createOutputFileName(sourceFileName) {
|
|
3710
|
+
return sourceFileName === "tsconfig.json" ? "tsconfig.output.json" : sourceFileName.replace(/\.json$/u, ".output.json");
|
|
3711
|
+
}
|
|
3702
3712
|
function getGeneratedDtsConfigPath(options) {
|
|
3703
3713
|
const relativeSourcePath = toRelativePath(options.rootDir, options.sourceConfigPath);
|
|
3704
3714
|
const relativeDir = posix.dirname(relativeSourcePath);
|
|
@@ -3710,6 +3720,17 @@ function getGeneratedSolutionBuildConfigPath(options) {
|
|
|
3710
3720
|
const relativeDir = posix.dirname(relativeSourcePath);
|
|
3711
3721
|
return normalizeAbsolutePath(posix.join(options.rootDir, generatedTsconfigDir, "checkers", options.checkerName, "solutions", relativeDir === "." ? "" : relativeDir, "tsconfig.build.json"));
|
|
3712
3722
|
}
|
|
3723
|
+
function getGeneratedOutputProjectConfigPath(options) {
|
|
3724
|
+
const relativeSourcePath = toRelativePath(options.rootDir, options.sourceConfigPath);
|
|
3725
|
+
const relativeDir = posix.dirname(relativeSourcePath);
|
|
3726
|
+
const outputFileName = createOutputFileName(posix.basename(relativeSourcePath));
|
|
3727
|
+
return normalizeAbsolutePath(posix.join(options.rootDir, generatedTsconfigDir, "checkers", options.checkerName, "outputs", "projects", relativeDir === "." ? "" : relativeDir, outputFileName));
|
|
3728
|
+
}
|
|
3729
|
+
function getGeneratedOutputSolutionConfigPath(options) {
|
|
3730
|
+
const relativeSourcePath = toRelativePath(options.rootDir, options.sourceConfigPath);
|
|
3731
|
+
const relativeDir = posix.dirname(relativeSourcePath);
|
|
3732
|
+
return normalizeAbsolutePath(posix.join(options.rootDir, generatedTsconfigDir, "checkers", options.checkerName, "outputs", "solutions", relativeDir === "." ? "" : relativeDir, "tsconfig.output.json"));
|
|
3733
|
+
}
|
|
3713
3734
|
function getGeneratedCheckerEntryPath(options) {
|
|
3714
3735
|
return normalizeAbsolutePath(posix.join(options.rootDir, generatedTsconfigDir, "checkers", options.checkerName, "tsconfig.build.json"));
|
|
3715
3736
|
}
|
|
@@ -4622,6 +4643,37 @@ function formatCheckIssueSnapshotInventory(options) {
|
|
|
4622
4643
|
return issueSummary;
|
|
4623
4644
|
}
|
|
4624
4645
|
|
|
4646
|
+
//#endregion
|
|
4647
|
+
//#region src/core/import-graph/declaration-provider.ts
|
|
4648
|
+
const declarationFileFamilyPattern = /\.d\.(?:cts|mts|ts)$/u;
|
|
4649
|
+
function isDeclarationFileFamily(filePath) {
|
|
4650
|
+
return declarationFileFamilyPattern.test(filePath);
|
|
4651
|
+
}
|
|
4652
|
+
function resolveDeclarationProvider(options) {
|
|
4653
|
+
const typeScriptResolution = options.importAnalysis.resolveTypeScriptImport(options.importRecord.specifier, options.containingFile, options.compilerOptions, options.project);
|
|
4654
|
+
const oxcResolvedFilePath = options.importAnalysis.resolveOxcImport(options.importRecord.specifier, options.containingFile, options.compilerOptions, options.project);
|
|
4655
|
+
if (!typeScriptResolution) return oxcResolvedFilePath ? {
|
|
4656
|
+
kind: "oxc-only",
|
|
4657
|
+
oxcResolvedFilePath,
|
|
4658
|
+
typeScriptResolution: null
|
|
4659
|
+
} : {
|
|
4660
|
+
kind: "unresolved",
|
|
4661
|
+
oxcResolvedFilePath: null,
|
|
4662
|
+
typeScriptResolution: null
|
|
4663
|
+
};
|
|
4664
|
+
if (isDeclarationFileFamily(typeScriptResolution.resolvedFileName)) return {
|
|
4665
|
+
kind: "declaration",
|
|
4666
|
+
oxcResolvedFilePath,
|
|
4667
|
+
typeScriptResolution
|
|
4668
|
+
};
|
|
4669
|
+
return {
|
|
4670
|
+
kind: "source",
|
|
4671
|
+
ownerProjectPaths: options.fileOwnerLookup.get(typeScriptResolution.resolvedFileName) ?? [],
|
|
4672
|
+
oxcResolvedFilePath,
|
|
4673
|
+
typeScriptResolution
|
|
4674
|
+
};
|
|
4675
|
+
}
|
|
4676
|
+
|
|
4625
4677
|
//#endregion
|
|
4626
4678
|
//#region src/core/packages/build-scripts.ts
|
|
4627
4679
|
const supportedBuildCheckers = new Set([
|
|
@@ -4629,10 +4681,7 @@ const supportedBuildCheckers = new Set([
|
|
|
4629
4681
|
"vue-tsc",
|
|
4630
4682
|
"tsgo"
|
|
4631
4683
|
]);
|
|
4632
|
-
function
|
|
4633
|
-
return /\blimina\s+checker\s+build\b/u.test(command);
|
|
4634
|
-
}
|
|
4635
|
-
function hasLegacyLiminaBuildIntent(command) {
|
|
4684
|
+
function hasLiminaBuildIntent(command) {
|
|
4636
4685
|
return /\blimina\s+build\b/u.test(command);
|
|
4637
4686
|
}
|
|
4638
4687
|
function hasShellControlOperator(command) {
|
|
@@ -4666,10 +4715,10 @@ function tokenizeStaticCommand(command) {
|
|
|
4666
4715
|
if (current.length > 0) tokens.push(current);
|
|
4667
4716
|
return tokens;
|
|
4668
4717
|
}
|
|
4669
|
-
function
|
|
4670
|
-
if (tokens[0] === "limina" && tokens[1] === "
|
|
4671
|
-
if (tokens[0] === "pnpm" && tokens[1] === "limina" && tokens[2] === "
|
|
4672
|
-
if (tokens[0] === "pnpm" && tokens[1] === "exec" && tokens[2] === "limina" && tokens[3] === "
|
|
4718
|
+
function getLiminaBuildArgumentOffset(tokens) {
|
|
4719
|
+
if (tokens[0] === "limina" && tokens[1] === "build") return 2;
|
|
4720
|
+
if (tokens[0] === "pnpm" && tokens[1] === "limina" && tokens[2] === "build") return 3;
|
|
4721
|
+
if (tokens[0] === "pnpm" && tokens[1] === "exec" && tokens[2] === "limina" && tokens[3] === "build") return 4;
|
|
4673
4722
|
return null;
|
|
4674
4723
|
}
|
|
4675
4724
|
function parseChecker(value) {
|
|
@@ -4679,12 +4728,12 @@ function createDiagnostic(options) {
|
|
|
4679
4728
|
return options;
|
|
4680
4729
|
}
|
|
4681
4730
|
function parsePackageBuildScript(options) {
|
|
4682
|
-
if (!
|
|
4731
|
+
if (!hasLiminaBuildIntent(options.command)) return null;
|
|
4683
4732
|
if (hasShellControlOperator(options.command) || /[$`]/u.test(options.command)) return createDiagnostic({
|
|
4684
4733
|
command: options.command,
|
|
4685
4734
|
packageJsonPath: options.packageJsonPath,
|
|
4686
4735
|
packageName: options.packageName,
|
|
4687
|
-
reason: "Limina only derives Knip source configs from static limina
|
|
4736
|
+
reason: "Limina only derives Knip source configs from static limina build scripts without shell control operators or dynamic expansion.",
|
|
4688
4737
|
scriptName: options.scriptName
|
|
4689
4738
|
});
|
|
4690
4739
|
const tokens = tokenizeStaticCommand(options.command);
|
|
@@ -4695,21 +4744,22 @@ function parsePackageBuildScript(options) {
|
|
|
4695
4744
|
reason: "Limina could not statically tokenize this package script.",
|
|
4696
4745
|
scriptName: options.scriptName
|
|
4697
4746
|
});
|
|
4698
|
-
const argumentOffset =
|
|
4747
|
+
const argumentOffset = getLiminaBuildArgumentOffset(tokens);
|
|
4699
4748
|
if (argumentOffset === null) return createDiagnostic({
|
|
4700
4749
|
command: options.command,
|
|
4701
4750
|
packageJsonPath: options.packageJsonPath,
|
|
4702
4751
|
packageName: options.packageName,
|
|
4703
|
-
reason: "Limina only recognizes limina
|
|
4752
|
+
reason: "Limina only recognizes direct limina build, pnpm limina build, and pnpm exec limina build package scripts.",
|
|
4704
4753
|
scriptName: options.scriptName
|
|
4705
4754
|
});
|
|
4706
4755
|
let checker;
|
|
4707
4756
|
let configPath;
|
|
4708
|
-
let
|
|
4757
|
+
let raw = false;
|
|
4709
4758
|
for (let index = argumentOffset; index < tokens.length; index += 1) {
|
|
4710
4759
|
const token = tokens[index];
|
|
4711
|
-
if (token === "-w" || token === "--watch")
|
|
4712
|
-
|
|
4760
|
+
if (token === "-w" || token === "--watch") continue;
|
|
4761
|
+
if (token === "--raw") {
|
|
4762
|
+
raw = true;
|
|
4713
4763
|
continue;
|
|
4714
4764
|
}
|
|
4715
4765
|
if (token === "--checker" || token.startsWith("--checker=")) return createDiagnostic({
|
|
@@ -4720,7 +4770,6 @@ function parsePackageBuildScript(options) {
|
|
|
4720
4770
|
scriptName: options.scriptName
|
|
4721
4771
|
});
|
|
4722
4772
|
if (token === "--preset") {
|
|
4723
|
-
sawTargetOption = true;
|
|
4724
4773
|
const parsedChecker = parseChecker(tokens[index + 1]);
|
|
4725
4774
|
if (!parsedChecker) return createDiagnostic({
|
|
4726
4775
|
command: options.command,
|
|
@@ -4734,7 +4783,6 @@ function parsePackageBuildScript(options) {
|
|
|
4734
4783
|
continue;
|
|
4735
4784
|
}
|
|
4736
4785
|
if (token.startsWith("--preset=")) {
|
|
4737
|
-
sawTargetOption = true;
|
|
4738
4786
|
const parsedChecker = parseChecker(token.slice(9));
|
|
4739
4787
|
if (!parsedChecker) return createDiagnostic({
|
|
4740
4788
|
command: options.command,
|
|
@@ -4750,32 +4798,37 @@ function parsePackageBuildScript(options) {
|
|
|
4750
4798
|
command: options.command,
|
|
4751
4799
|
packageJsonPath: options.packageJsonPath,
|
|
4752
4800
|
packageName: options.packageName,
|
|
4753
|
-
reason: "Limina
|
|
4801
|
+
reason: "Limina build script analysis only supports --raw, --preset, -w/--watch, plus one literal config argument.",
|
|
4754
4802
|
scriptName: options.scriptName
|
|
4755
4803
|
});
|
|
4756
4804
|
if (configPath) return createDiagnostic({
|
|
4757
4805
|
command: options.command,
|
|
4758
4806
|
packageJsonPath: options.packageJsonPath,
|
|
4759
4807
|
packageName: options.packageName,
|
|
4760
|
-
reason: "Limina
|
|
4808
|
+
reason: "Limina build script analysis found multiple config arguments.",
|
|
4761
4809
|
scriptName: options.scriptName
|
|
4762
4810
|
});
|
|
4763
4811
|
configPath = token;
|
|
4764
4812
|
}
|
|
4765
|
-
if (!configPath) {
|
|
4766
|
-
|
|
4767
|
-
|
|
4768
|
-
|
|
4769
|
-
|
|
4770
|
-
|
|
4771
|
-
|
|
4772
|
-
|
|
4773
|
-
|
|
4774
|
-
|
|
4813
|
+
if (!configPath) return createDiagnostic({
|
|
4814
|
+
command: options.command,
|
|
4815
|
+
packageJsonPath: options.packageJsonPath,
|
|
4816
|
+
packageName: options.packageName,
|
|
4817
|
+
reason: "Limina build script analysis requires a config argument.",
|
|
4818
|
+
scriptName: options.scriptName
|
|
4819
|
+
});
|
|
4820
|
+
if (raw && !checker) return createDiagnostic({
|
|
4821
|
+
command: options.command,
|
|
4822
|
+
packageJsonPath: options.packageJsonPath,
|
|
4823
|
+
packageName: options.packageName,
|
|
4824
|
+
reason: "limina build --raw package scripts require --preset.",
|
|
4825
|
+
scriptName: options.scriptName
|
|
4826
|
+
});
|
|
4775
4827
|
return {
|
|
4776
4828
|
...checker ? { checker } : {},
|
|
4777
4829
|
command: options.command,
|
|
4778
4830
|
configPath: normalizeAbsolutePath(posix.resolve(options.packageDirectory, configPath)),
|
|
4831
|
+
raw,
|
|
4779
4832
|
name: options.scriptName,
|
|
4780
4833
|
packageJsonPath: options.packageJsonPath,
|
|
4781
4834
|
packageName: options.packageName
|
|
@@ -4816,9 +4869,14 @@ function getGeneratedKnipConfigPath(options) {
|
|
|
4816
4869
|
const relativeOutputPath = relativePackageDirectory === "." ? posix.join(".limina/knip", "tsconfig.knip.json") : posix.join(".limina/knip", relativePackageDirectory, "tsconfig.knip.json");
|
|
4817
4870
|
return normalizeAbsolutePath(posix.join(options.rootDir, relativeOutputPath));
|
|
4818
4871
|
}
|
|
4819
|
-
function
|
|
4820
|
-
|
|
4821
|
-
|
|
4872
|
+
function resolveManagedBuildConfigPaths(options) {
|
|
4873
|
+
const configPaths = /* @__PURE__ */ new Set();
|
|
4874
|
+
for (const checker of options.checkers) {
|
|
4875
|
+
if (options.script.checker && checker.preset !== options.script.checker) continue;
|
|
4876
|
+
const outputModule = options.configToOutputBuildByChecker.get(checker.name)?.get(options.script.configPath);
|
|
4877
|
+
if (outputModule) configPaths.add(outputModule.path);
|
|
4878
|
+
}
|
|
4879
|
+
return [...configPaths].sort((left, right) => left.localeCompare(right));
|
|
4822
4880
|
}
|
|
4823
4881
|
function toPackageScriptDiagnostic(diagnostic) {
|
|
4824
4882
|
return {
|
|
@@ -4928,10 +4986,12 @@ function prepareGeneratedKnipPackageConfigs(options) {
|
|
|
4928
4986
|
const references = /* @__PURE__ */ new Set();
|
|
4929
4987
|
const scripts = [];
|
|
4930
4988
|
for (const script of packageScripts) {
|
|
4931
|
-
const
|
|
4932
|
-
|
|
4933
|
-
|
|
4934
|
-
|
|
4989
|
+
const managedConfigPaths = script.raw ? [] : resolveManagedBuildConfigPaths({
|
|
4990
|
+
checkers: options.checkers,
|
|
4991
|
+
configToOutputBuildByChecker: options.configToOutputBuildByChecker,
|
|
4992
|
+
script
|
|
4993
|
+
});
|
|
4994
|
+
const mode = script.raw ? "raw" : "managed";
|
|
4935
4995
|
const diagnostic = validatePackageBuildScript({
|
|
4936
4996
|
config: options.config,
|
|
4937
4997
|
mode,
|
|
@@ -4942,7 +5002,17 @@ function prepareGeneratedKnipPackageConfigs(options) {
|
|
|
4942
5002
|
diagnostics.push(diagnostic);
|
|
4943
5003
|
continue;
|
|
4944
5004
|
}
|
|
4945
|
-
|
|
5005
|
+
if (!script.raw && managedConfigPaths.length === 0) {
|
|
5006
|
+
diagnostics.push({
|
|
5007
|
+
command: script.command,
|
|
5008
|
+
packageJsonPath: script.packageJsonPath,
|
|
5009
|
+
packageName: script.packageName,
|
|
5010
|
+
reason: "managed limina build package scripts must point to a Limina-managed config with liminaOptions.outputs.",
|
|
5011
|
+
scriptName: script.name
|
|
5012
|
+
});
|
|
5013
|
+
continue;
|
|
5014
|
+
}
|
|
5015
|
+
for (const referencePath of script.raw ? [script.configPath] : managedConfigPaths) references.add(referencePath);
|
|
4946
5016
|
scripts.push({
|
|
4947
5017
|
...script.checker ? { checker: script.checker } : {},
|
|
4948
5018
|
command: script.command,
|
|
@@ -5000,6 +5070,154 @@ function readGraphRules(config, sourceConfigPath) {
|
|
|
5000
5070
|
const graphRules = liminaOptions.graphRules;
|
|
5001
5071
|
return Array.isArray(graphRules) ? uniqueValues(graphRules.filter((label) => typeof label === "string" && label.trim().length > 0)).map((label) => label.trim()) : [];
|
|
5002
5072
|
}
|
|
5073
|
+
function addOutputOptionsProblem(options) {
|
|
5074
|
+
options.problems.push([
|
|
5075
|
+
"Invalid Limina output options:",
|
|
5076
|
+
` config: ${toRelativePath(options.config.rootDir, options.sourceConfigPath)}`,
|
|
5077
|
+
` field: ${options.field}`,
|
|
5078
|
+
...Object.hasOwn(options, "value") ? [` value: ${formatUnknownValue(options.value)}`] : [],
|
|
5079
|
+
` reason: ${options.reason}`
|
|
5080
|
+
].join("\n"));
|
|
5081
|
+
}
|
|
5082
|
+
function normalizeExtendsConfigPath(configPath, extendsValue) {
|
|
5083
|
+
const trimmedValue = extendsValue.trim();
|
|
5084
|
+
if (trimmedValue.length === 0) return null;
|
|
5085
|
+
if (posix.isAbsolute(trimmedValue) || trimmedValue.startsWith("./") || trimmedValue.startsWith("../")) {
|
|
5086
|
+
const resolvedPath = posix.resolve(posix.dirname(configPath), trimmedValue);
|
|
5087
|
+
return normalizeAbsolutePath(posix.extname(resolvedPath) ? resolvedPath : `${resolvedPath}.json`);
|
|
5088
|
+
}
|
|
5089
|
+
try {
|
|
5090
|
+
return normalizeAbsolutePath(createRequire(configPath).resolve(trimmedValue));
|
|
5091
|
+
} catch {
|
|
5092
|
+
return null;
|
|
5093
|
+
}
|
|
5094
|
+
}
|
|
5095
|
+
function readExplicitSourceCompilerTarget(options) {
|
|
5096
|
+
const seenConfigPaths = options.seenConfigPaths ?? /* @__PURE__ */ new Set();
|
|
5097
|
+
const configPath = normalizeAbsolutePath(options.configPath);
|
|
5098
|
+
if (seenConfigPaths.has(configPath) || !existsSync(configPath)) return null;
|
|
5099
|
+
seenConfigPaths.add(configPath);
|
|
5100
|
+
const configObject = readJsonConfig(options.config, configPath);
|
|
5101
|
+
const extendsValue = configObject.extends;
|
|
5102
|
+
const extendsValues = typeof extendsValue === "string" ? [extendsValue] : Array.isArray(extendsValue) ? extendsValue.filter((entry) => typeof entry === "string") : [];
|
|
5103
|
+
let target = null;
|
|
5104
|
+
for (const entry of extendsValues) {
|
|
5105
|
+
const extendedConfigPath = normalizeExtendsConfigPath(configPath, entry);
|
|
5106
|
+
if (!extendedConfigPath) continue;
|
|
5107
|
+
target = readExplicitSourceCompilerTarget({
|
|
5108
|
+
config: options.config,
|
|
5109
|
+
configPath: extendedConfigPath,
|
|
5110
|
+
seenConfigPaths
|
|
5111
|
+
}) ?? target;
|
|
5112
|
+
}
|
|
5113
|
+
const compilerOptions = configObject.compilerOptions;
|
|
5114
|
+
if (isPlainRecord(compilerOptions)) {
|
|
5115
|
+
const targetValue = compilerOptions.target;
|
|
5116
|
+
if (isNonEmptyString(targetValue)) target = targetValue.trim();
|
|
5117
|
+
}
|
|
5118
|
+
return target;
|
|
5119
|
+
}
|
|
5120
|
+
function readOutputOptions(config, sourceConfigPath) {
|
|
5121
|
+
const liminaOptions = readJsonConfig(config, sourceConfigPath).liminaOptions;
|
|
5122
|
+
const problems = [];
|
|
5123
|
+
if (liminaOptions === void 0) return {
|
|
5124
|
+
outputs: null,
|
|
5125
|
+
problems
|
|
5126
|
+
};
|
|
5127
|
+
if (!isPlainRecord(liminaOptions)) {
|
|
5128
|
+
addOutputOptionsProblem({
|
|
5129
|
+
config,
|
|
5130
|
+
field: "liminaOptions",
|
|
5131
|
+
problems,
|
|
5132
|
+
reason: "liminaOptions must be an object before outputs can be read.",
|
|
5133
|
+
sourceConfigPath,
|
|
5134
|
+
value: liminaOptions
|
|
5135
|
+
});
|
|
5136
|
+
return {
|
|
5137
|
+
outputs: null,
|
|
5138
|
+
problems
|
|
5139
|
+
};
|
|
5140
|
+
}
|
|
5141
|
+
const outputs = liminaOptions.outputs;
|
|
5142
|
+
if (outputs === void 0) return {
|
|
5143
|
+
outputs: null,
|
|
5144
|
+
problems
|
|
5145
|
+
};
|
|
5146
|
+
if (!isPlainRecord(outputs)) {
|
|
5147
|
+
addOutputOptionsProblem({
|
|
5148
|
+
config,
|
|
5149
|
+
field: "liminaOptions.outputs",
|
|
5150
|
+
problems,
|
|
5151
|
+
reason: "outputs must be an object.",
|
|
5152
|
+
sourceConfigPath,
|
|
5153
|
+
value: outputs
|
|
5154
|
+
});
|
|
5155
|
+
return {
|
|
5156
|
+
outputs: null,
|
|
5157
|
+
problems
|
|
5158
|
+
};
|
|
5159
|
+
}
|
|
5160
|
+
const allowedFields = new Set([
|
|
5161
|
+
"outDir",
|
|
5162
|
+
"rootDir",
|
|
5163
|
+
"target",
|
|
5164
|
+
"tsBuildInfoFile"
|
|
5165
|
+
]);
|
|
5166
|
+
for (const fieldName of Object.keys(outputs)) if (!allowedFields.has(fieldName)) addOutputOptionsProblem({
|
|
5167
|
+
config,
|
|
5168
|
+
field: `liminaOptions.outputs.${fieldName}`,
|
|
5169
|
+
problems,
|
|
5170
|
+
reason: "outputs only supports target, rootDir, outDir, and tsBuildInfoFile.",
|
|
5171
|
+
sourceConfigPath,
|
|
5172
|
+
value: outputs[fieldName]
|
|
5173
|
+
});
|
|
5174
|
+
const outputValues = {};
|
|
5175
|
+
for (const fieldName of allowedFields) {
|
|
5176
|
+
const fieldValue = outputs[fieldName];
|
|
5177
|
+
if (fieldValue === void 0) continue;
|
|
5178
|
+
if (!isNonEmptyString(fieldValue)) {
|
|
5179
|
+
addOutputOptionsProblem({
|
|
5180
|
+
config,
|
|
5181
|
+
field: `liminaOptions.outputs.${fieldName}`,
|
|
5182
|
+
problems,
|
|
5183
|
+
reason: "output option fields must be non-empty strings.",
|
|
5184
|
+
sourceConfigPath,
|
|
5185
|
+
value: fieldValue
|
|
5186
|
+
});
|
|
5187
|
+
continue;
|
|
5188
|
+
}
|
|
5189
|
+
if ((fieldName === "rootDir" || fieldName === "outDir" || fieldName === "tsBuildInfoFile") && posix.isAbsolute(fieldValue)) {
|
|
5190
|
+
addOutputOptionsProblem({
|
|
5191
|
+
config,
|
|
5192
|
+
field: `liminaOptions.outputs.${fieldName}`,
|
|
5193
|
+
problems,
|
|
5194
|
+
reason: "output path fields must be relative to the tsconfig that declares them.",
|
|
5195
|
+
sourceConfigPath,
|
|
5196
|
+
value: fieldValue
|
|
5197
|
+
});
|
|
5198
|
+
continue;
|
|
5199
|
+
}
|
|
5200
|
+
outputValues[fieldName] = fieldValue.trim();
|
|
5201
|
+
}
|
|
5202
|
+
if (problems.length > 0) return {
|
|
5203
|
+
outputs: null,
|
|
5204
|
+
problems
|
|
5205
|
+
};
|
|
5206
|
+
const sourceConfigDirectory = posix.dirname(sourceConfigPath);
|
|
5207
|
+
const scope = createSourceConfigScope(sourceConfigPath);
|
|
5208
|
+
return {
|
|
5209
|
+
outputs: {
|
|
5210
|
+
target: outputValues.target ?? readExplicitSourceCompilerTarget({
|
|
5211
|
+
config,
|
|
5212
|
+
configPath: sourceConfigPath
|
|
5213
|
+
}) ?? "ESNext",
|
|
5214
|
+
rootDir: normalizeAbsolutePath(posix.resolve(sourceConfigDirectory, outputValues.rootDir ?? ".")),
|
|
5215
|
+
outDir: normalizeAbsolutePath(posix.resolve(sourceConfigDirectory, outputValues.outDir ?? "./dist")),
|
|
5216
|
+
tsBuildInfoFile: normalizeAbsolutePath(posix.resolve(sourceConfigDirectory, outputValues.tsBuildInfoFile ?? `./dist/.${scope}_tsbuildinfo`))
|
|
5217
|
+
},
|
|
5218
|
+
problems
|
|
5219
|
+
};
|
|
5220
|
+
}
|
|
5003
5221
|
function addImplicitRefProblem(options) {
|
|
5004
5222
|
options.problems.push([
|
|
5005
5223
|
"Invalid Limina implicit reference:",
|
|
@@ -5372,12 +5590,26 @@ function createSolutionBuildModule(options) {
|
|
|
5372
5590
|
path: getGeneratedSolutionBuildConfigPath(options)
|
|
5373
5591
|
};
|
|
5374
5592
|
}
|
|
5593
|
+
function createOutputProjectBuildModule(options) {
|
|
5594
|
+
return {
|
|
5595
|
+
kind: "project",
|
|
5596
|
+
path: getGeneratedOutputProjectConfigPath(options)
|
|
5597
|
+
};
|
|
5598
|
+
}
|
|
5599
|
+
function createOutputSolutionBuildModule(options) {
|
|
5600
|
+
return {
|
|
5601
|
+
kind: "solution",
|
|
5602
|
+
path: getGeneratedOutputSolutionConfigPath(options)
|
|
5603
|
+
};
|
|
5604
|
+
}
|
|
5375
5605
|
function collectCheckerSourceConfigModules(options) {
|
|
5376
5606
|
if (options.excludedConfigPaths.has(options.sourceConfigPath)) return;
|
|
5377
5607
|
if (options.seenConfigs.has(options.sourceConfigPath)) return;
|
|
5378
5608
|
options.seenConfigs.add(options.sourceConfigPath);
|
|
5379
5609
|
const configObject = readJsonConfig(options.config, options.sourceConfigPath);
|
|
5380
5610
|
const hasReferences = Object.hasOwn(configObject, "references");
|
|
5611
|
+
const outputOptions = readOutputOptions(options.config, options.sourceConfigPath);
|
|
5612
|
+
options.problems.push(...outputOptions.problems);
|
|
5381
5613
|
if (hasReferences && !isDefaultTsconfigPath(options.sourceConfigPath)) {
|
|
5382
5614
|
addSourceReferenceConfigProblems({
|
|
5383
5615
|
config: options.config,
|
|
@@ -5387,6 +5619,13 @@ function collectCheckerSourceConfigModules(options) {
|
|
|
5387
5619
|
return;
|
|
5388
5620
|
}
|
|
5389
5621
|
if (hasReferences && isDefaultTsconfigPath(options.sourceConfigPath)) {
|
|
5622
|
+
if (outputOptions.outputs) options.problems.push([
|
|
5623
|
+
"Invalid Limina output options:",
|
|
5624
|
+
` config: ${toRelativePath(options.config.rootDir, options.sourceConfigPath)}`,
|
|
5625
|
+
" field: liminaOptions.outputs",
|
|
5626
|
+
" reason: liminaOptions.outputs is only allowed on ordinary source leaf configs, not solution-style configs.",
|
|
5627
|
+
" fix: move liminaOptions.outputs to one or more referenced source leaf tsconfigs."
|
|
5628
|
+
].join("\n"));
|
|
5390
5629
|
options.collection.solutionConfigPaths.add(options.sourceConfigPath);
|
|
5391
5630
|
options.collection.buildModulesBySourcePath.set(options.sourceConfigPath, createSolutionBuildModule({
|
|
5392
5631
|
checkerName: options.checkerName,
|
|
@@ -5702,6 +5941,7 @@ function createSourceProject(options) {
|
|
|
5702
5941
|
projectRootDir: options.config.rootDir
|
|
5703
5942
|
});
|
|
5704
5943
|
const ownedFileNames = parsed.fileNames.map(normalizeAbsolutePath).sort();
|
|
5944
|
+
const outputOptions = readOutputOptions(options.config, options.sourceConfigPath);
|
|
5705
5945
|
return {
|
|
5706
5946
|
checkerName: options.checkerName,
|
|
5707
5947
|
configPath: options.sourceConfigPath,
|
|
@@ -5714,6 +5954,13 @@ function createSourceProject(options) {
|
|
|
5714
5954
|
fileNames: uniqueSortedStrings([...ownedFileNames, ...readRelativeTypeFiles$1(options.config, options.sourceConfigPath)]),
|
|
5715
5955
|
graphRules: readGraphRules(options.config, options.sourceConfigPath),
|
|
5716
5956
|
ownedFileNames,
|
|
5957
|
+
outputConfigPath: getGeneratedOutputProjectConfigPath({
|
|
5958
|
+
checkerName: options.checkerName,
|
|
5959
|
+
rootDir: options.config.rootDir,
|
|
5960
|
+
sourceConfigPath: options.sourceConfigPath
|
|
5961
|
+
}),
|
|
5962
|
+
outputOptions: outputOptions.outputs,
|
|
5963
|
+
outputReferences: /* @__PURE__ */ new Set(),
|
|
5717
5964
|
options: parsed.options,
|
|
5718
5965
|
references: /* @__PURE__ */ new Set()
|
|
5719
5966
|
};
|
|
@@ -5731,6 +5978,104 @@ function createSolutionProject(options) {
|
|
|
5731
5978
|
references: new Set(referenceSourceConfigPaths.map((sourceConfigPath) => options.collection.buildModulesBySourcePath.get(sourceConfigPath)?.path).filter((buildPath) => Boolean(buildPath)))
|
|
5732
5979
|
};
|
|
5733
5980
|
}
|
|
5981
|
+
function createSourceProjectsByDtsPath(projects) {
|
|
5982
|
+
return new Map(projects.map((project) => [project.dtsConfigPath, project]));
|
|
5983
|
+
}
|
|
5984
|
+
function createOutputSolutionProject(options) {
|
|
5985
|
+
return {
|
|
5986
|
+
buildConfigPath: getGeneratedOutputSolutionConfigPath({
|
|
5987
|
+
checkerName: options.checkerName,
|
|
5988
|
+
rootDir: options.config.rootDir,
|
|
5989
|
+
sourceConfigPath: options.sourceConfigPath
|
|
5990
|
+
}),
|
|
5991
|
+
checkerName: options.checkerName,
|
|
5992
|
+
configPath: options.sourceConfigPath,
|
|
5993
|
+
references: new Set(options.references)
|
|
5994
|
+
};
|
|
5995
|
+
}
|
|
5996
|
+
function collectFlattenedOutputSolutionReferences(options) {
|
|
5997
|
+
const seenConfigPaths = options.seenConfigPaths ?? /* @__PURE__ */ new Set();
|
|
5998
|
+
if (seenConfigPaths.has(options.sourceConfigPath)) return [];
|
|
5999
|
+
seenConfigPaths.add(options.sourceConfigPath);
|
|
6000
|
+
const references = options.collection.solutionReferencesBySourcePath.get(options.sourceConfigPath) ?? [];
|
|
6001
|
+
const outputReferences = /* @__PURE__ */ new Set();
|
|
6002
|
+
for (const referencePath of references) {
|
|
6003
|
+
const outputProjectModule = options.outputProjectModuleBySourcePath.get(referencePath);
|
|
6004
|
+
if (outputProjectModule) {
|
|
6005
|
+
outputReferences.add(outputProjectModule.path);
|
|
6006
|
+
continue;
|
|
6007
|
+
}
|
|
6008
|
+
for (const nestedReferencePath of collectFlattenedOutputSolutionReferences({
|
|
6009
|
+
collection: options.collection,
|
|
6010
|
+
outputProjectModuleBySourcePath: options.outputProjectModuleBySourcePath,
|
|
6011
|
+
sourceConfigPath: referencePath,
|
|
6012
|
+
seenConfigPaths
|
|
6013
|
+
})) outputReferences.add(nestedReferencePath);
|
|
6014
|
+
}
|
|
6015
|
+
return [...outputReferences].sort((left, right) => left.localeCompare(right));
|
|
6016
|
+
}
|
|
6017
|
+
function formatMissingOutputDependencyProblem(options) {
|
|
6018
|
+
return [
|
|
6019
|
+
"Missing Limina output options for referenced source project:",
|
|
6020
|
+
` config: ${toRelativePath(options.config.rootDir, options.project.configPath)}`,
|
|
6021
|
+
` referenced config: ${toRelativePath(options.config.rootDir, options.targetProject.configPath)}`,
|
|
6022
|
+
" reason: this output-enabled source project has a Limina-generated project reference to another managed source project that does not declare liminaOptions.outputs.",
|
|
6023
|
+
" fix: add liminaOptions.outputs to the referenced source config, or move the dependency behind a declaration or artifact boundary."
|
|
6024
|
+
].join("\n");
|
|
6025
|
+
}
|
|
6026
|
+
function createCheckerOutputGraph(options) {
|
|
6027
|
+
if (getCheckerAdapter(options.checker.preset)?.execution !== "build") return {
|
|
6028
|
+
configToOutputBuild: /* @__PURE__ */ new Map(),
|
|
6029
|
+
outputProjects: [],
|
|
6030
|
+
outputSolutions: []
|
|
6031
|
+
};
|
|
6032
|
+
const outputProjects = options.projects.filter((project) => Boolean(project.outputOptions));
|
|
6033
|
+
const outputProjectModuleBySourcePath = new Map(outputProjects.map((project) => [project.configPath, createOutputProjectBuildModule({
|
|
6034
|
+
checkerName: options.checker.name,
|
|
6035
|
+
rootDir: options.config.rootDir,
|
|
6036
|
+
sourceConfigPath: project.configPath
|
|
6037
|
+
})]));
|
|
6038
|
+
const configToOutputBuild = new Map(outputProjectModuleBySourcePath);
|
|
6039
|
+
for (const project of outputProjects) for (const referencePath of project.references) {
|
|
6040
|
+
const targetProject = options.allProjectsByDtsPath.get(referencePath);
|
|
6041
|
+
if (!targetProject) continue;
|
|
6042
|
+
if (!targetProject.outputOptions) {
|
|
6043
|
+
options.problems.push(formatMissingOutputDependencyProblem({
|
|
6044
|
+
config: options.config,
|
|
6045
|
+
project,
|
|
6046
|
+
targetProject
|
|
6047
|
+
}));
|
|
6048
|
+
continue;
|
|
6049
|
+
}
|
|
6050
|
+
project.outputReferences.add(targetProject.outputConfigPath);
|
|
6051
|
+
}
|
|
6052
|
+
const outputSolutions = [];
|
|
6053
|
+
for (const sourceConfigPath of [...options.collection.solutionConfigPaths].sort((left, right) => left.localeCompare(right))) {
|
|
6054
|
+
const references = collectFlattenedOutputSolutionReferences({
|
|
6055
|
+
collection: options.collection,
|
|
6056
|
+
outputProjectModuleBySourcePath,
|
|
6057
|
+
sourceConfigPath
|
|
6058
|
+
});
|
|
6059
|
+
if (references.length === 0) continue;
|
|
6060
|
+
const outputSolution = createOutputSolutionProject({
|
|
6061
|
+
checkerName: options.checker.name,
|
|
6062
|
+
config: options.config,
|
|
6063
|
+
references,
|
|
6064
|
+
sourceConfigPath
|
|
6065
|
+
});
|
|
6066
|
+
outputSolutions.push(outputSolution);
|
|
6067
|
+
configToOutputBuild.set(sourceConfigPath, createOutputSolutionBuildModule({
|
|
6068
|
+
checkerName: options.checker.name,
|
|
6069
|
+
rootDir: options.config.rootDir,
|
|
6070
|
+
sourceConfigPath
|
|
6071
|
+
}));
|
|
6072
|
+
}
|
|
6073
|
+
return {
|
|
6074
|
+
configToOutputBuild,
|
|
6075
|
+
outputProjects,
|
|
6076
|
+
outputSolutions
|
|
6077
|
+
};
|
|
6078
|
+
}
|
|
5734
6079
|
function createDtsProjectsBySourcePath(projects) {
|
|
5735
6080
|
const projectsBySourcePath = /* @__PURE__ */ new Map();
|
|
5736
6081
|
for (const project of projects) projectsBySourcePath.set(project.configPath, [...projectsBySourcePath.get(project.configPath) ?? [], project]);
|
|
@@ -5849,6 +6194,17 @@ function formatMissingCrossCheckerProviderProblem(options) {
|
|
|
5849
6194
|
" fix: cover the target source config with a build-capable checker preset such as tsc, tsgo, or vue-tsc."
|
|
5850
6195
|
].join("\n");
|
|
5851
6196
|
}
|
|
6197
|
+
function formatOxcOnlyDeclarationProviderProblem(options) {
|
|
6198
|
+
return [
|
|
6199
|
+
"Oxc can resolve this specifier, but TypeScript cannot:",
|
|
6200
|
+
` importing config: ${toRelativePath(options.config.rootDir, options.project.configPath)}`,
|
|
6201
|
+
` file: ${formatImportRecordLocation(options.config.rootDir, options.importRecord)}`,
|
|
6202
|
+
` imported specifier: ${options.importRecord.specifier}`,
|
|
6203
|
+
` Oxc resolved file: ${toRelativePath(options.config.rootDir, options.oxcResolvedFilePath)}`,
|
|
6204
|
+
" reason: generated declaration references follow the checker-aware TypeScript declaration provider, not the Oxc runtime-like resolver.",
|
|
6205
|
+
" fix: check moduleResolution, exports.types/types conditions, paths, customConditions, and package boundaries."
|
|
6206
|
+
].join("\n");
|
|
6207
|
+
}
|
|
5852
6208
|
function inferProjectReferences(config, projects, ownerProjects = projects, options = {}) {
|
|
5853
6209
|
const problems = [];
|
|
5854
6210
|
const providerEdgesByKey = /* @__PURE__ */ new Map();
|
|
@@ -5900,13 +6256,31 @@ function inferProjectReferences(config, projects, ownerProjects = projects, opti
|
|
|
5900
6256
|
}
|
|
5901
6257
|
}
|
|
5902
6258
|
for (const project of projects) for (const fileName of project.ownedFileNames) for (const importRecord of collectImportsFromFile(fileName, config.rootDir, importAnalysis)) {
|
|
5903
|
-
const
|
|
5904
|
-
|
|
5905
|
-
|
|
5906
|
-
|
|
5907
|
-
|
|
5908
|
-
|
|
5909
|
-
|
|
6259
|
+
const declarationProvider = resolveDeclarationProvider({
|
|
6260
|
+
compilerOptions: project.options,
|
|
6261
|
+
containingFile: fileName,
|
|
6262
|
+
fileOwnerLookup: ownerLookup,
|
|
6263
|
+
importAnalysis,
|
|
6264
|
+
importRecord,
|
|
6265
|
+
project: {
|
|
6266
|
+
...project.context,
|
|
6267
|
+
configPath: project.configPath,
|
|
6268
|
+
resolverConfigPath: project.configPath
|
|
6269
|
+
}
|
|
6270
|
+
});
|
|
6271
|
+
if (declarationProvider.kind === "declaration") continue;
|
|
6272
|
+
if (declarationProvider.kind === "oxc-only") {
|
|
6273
|
+
problems.push(formatOxcOnlyDeclarationProviderProblem({
|
|
6274
|
+
config,
|
|
6275
|
+
importRecord,
|
|
6276
|
+
oxcResolvedFilePath: declarationProvider.oxcResolvedFilePath,
|
|
6277
|
+
project
|
|
6278
|
+
}));
|
|
6279
|
+
continue;
|
|
6280
|
+
}
|
|
6281
|
+
if (declarationProvider.kind === "unresolved") continue;
|
|
6282
|
+
const resolvedFilePath = declarationProvider.typeScriptResolution.resolvedFileName;
|
|
6283
|
+
const owners = declarationProvider.ownerProjectPaths;
|
|
5910
6284
|
if (!owners || owners.length === 0) continue;
|
|
5911
6285
|
const targetSourceConfigPath = owners.filter((owner) => owner !== project.configPath).sort((left, right) => posix.dirname(right).length - posix.dirname(left).length || left.localeCompare(right))[0] ?? null;
|
|
5912
6286
|
if (!targetSourceConfigPath) continue;
|
|
@@ -6044,6 +6418,33 @@ function createGeneratedDtsConfig(config, project) {
|
|
|
6044
6418
|
liminaOptions
|
|
6045
6419
|
};
|
|
6046
6420
|
}
|
|
6421
|
+
function createGeneratedOutputProjectConfig(config, project) {
|
|
6422
|
+
if (!project.outputOptions) throw new Error(`Missing output options for ${toRelativePath(config.rootDir, project.configPath)}.`);
|
|
6423
|
+
const outputOptions = project.outputOptions;
|
|
6424
|
+
return {
|
|
6425
|
+
$schema: createLiminaTsconfigSchemaPath(config.rootDir, project.outputConfigPath),
|
|
6426
|
+
extends: [createRelativePath(project.outputConfigPath, project.configPath)],
|
|
6427
|
+
files: project.fileNames.map((fileName) => createRelativePath(project.outputConfigPath, fileName)),
|
|
6428
|
+
compilerOptions: {
|
|
6429
|
+
composite: true,
|
|
6430
|
+
incremental: true,
|
|
6431
|
+
noEmit: false,
|
|
6432
|
+
declaration: true,
|
|
6433
|
+
emitDeclarationOnly: false,
|
|
6434
|
+
target: outputOptions.target,
|
|
6435
|
+
rootDir: createRelativePath(project.outputConfigPath, outputOptions.rootDir),
|
|
6436
|
+
outDir: createRelativePath(project.outputConfigPath, outputOptions.outDir),
|
|
6437
|
+
declarationDir: createRelativePath(project.outputConfigPath, outputOptions.outDir),
|
|
6438
|
+
tsBuildInfoFile: createRelativePath(project.outputConfigPath, outputOptions.tsBuildInfoFile)
|
|
6439
|
+
},
|
|
6440
|
+
references: [...project.outputReferences].sort().map((referencePath) => ({ path: createRelativePath(project.outputConfigPath, referencePath) })),
|
|
6441
|
+
liminaOptions: {
|
|
6442
|
+
generated: true,
|
|
6443
|
+
checker: project.checkerName,
|
|
6444
|
+
sourceConfig: createRelativePath(project.outputConfigPath, project.configPath)
|
|
6445
|
+
}
|
|
6446
|
+
};
|
|
6447
|
+
}
|
|
6047
6448
|
function createGeneratedSolutionBuildConfig(config, solution) {
|
|
6048
6449
|
return {
|
|
6049
6450
|
$schema: createLiminaTsconfigSchemaPath(config.rootDir, solution.buildConfigPath),
|
|
@@ -6056,6 +6457,18 @@ function createGeneratedSolutionBuildConfig(config, solution) {
|
|
|
6056
6457
|
}
|
|
6057
6458
|
};
|
|
6058
6459
|
}
|
|
6460
|
+
function createGeneratedOutputSolutionConfig(config, solution) {
|
|
6461
|
+
return {
|
|
6462
|
+
$schema: createLiminaTsconfigSchemaPath(config.rootDir, solution.buildConfigPath),
|
|
6463
|
+
files: [],
|
|
6464
|
+
references: [...solution.references].sort().map((referencePath) => ({ path: createRelativePath(solution.buildConfigPath, referencePath) })),
|
|
6465
|
+
liminaOptions: {
|
|
6466
|
+
generated: true,
|
|
6467
|
+
checker: solution.checkerName,
|
|
6468
|
+
sourceConfig: createRelativePath(solution.buildConfigPath, solution.configPath)
|
|
6469
|
+
}
|
|
6470
|
+
};
|
|
6471
|
+
}
|
|
6059
6472
|
function createCheckerBuildConfig(options) {
|
|
6060
6473
|
return {
|
|
6061
6474
|
$schema: createLiminaTsconfigSchemaPath(options.rootDir, options.entryPath),
|
|
@@ -6098,11 +6511,20 @@ function createManifest(options) {
|
|
|
6098
6511
|
for (const checker of options.checkers) {
|
|
6099
6512
|
const projects = options.projectsByChecker.get(checker.name) ?? [];
|
|
6100
6513
|
const entryPath = options.checkerEntries.get(checker.name);
|
|
6514
|
+
const configToOutputBuildByConfigPath = options.configToOutputBuildByChecker.get(checker.name) ?? /* @__PURE__ */ new Map();
|
|
6101
6515
|
const sourceToBuildBySourcePath = options.sourceToBuildByChecker.get(checker.name) ?? /* @__PURE__ */ new Map();
|
|
6102
6516
|
if (!entryPath) continue;
|
|
6517
|
+
const configToOutputBuild = {};
|
|
6103
6518
|
const sourceToBuild = {};
|
|
6104
6519
|
const sourceToDts = {};
|
|
6105
6520
|
const dtsToSource = {};
|
|
6521
|
+
for (const [sourceConfigPath, outputModule] of configToOutputBuildByConfigPath) {
|
|
6522
|
+
const sourcePath = toPosixPath(toRelativePath(options.rootDir, sourceConfigPath));
|
|
6523
|
+
configToOutputBuild[sourcePath] = {
|
|
6524
|
+
kind: outputModule.kind,
|
|
6525
|
+
path: toPosixPath(toRelativePath(options.rootDir, outputModule.path))
|
|
6526
|
+
};
|
|
6527
|
+
}
|
|
6106
6528
|
for (const [sourceConfigPath, buildModule] of sourceToBuildBySourcePath) {
|
|
6107
6529
|
const sourcePath = toPosixPath(toRelativePath(options.rootDir, sourceConfigPath));
|
|
6108
6530
|
sourceToBuild[sourcePath] = {
|
|
@@ -6117,6 +6539,7 @@ function createManifest(options) {
|
|
|
6117
6539
|
dtsToSource[dtsPath] = sourcePath;
|
|
6118
6540
|
}
|
|
6119
6541
|
manifestCheckers[checker.name] = {
|
|
6542
|
+
configToOutputBuild: Object.fromEntries(Object.entries(configToOutputBuild).sort(([left], [right]) => left.localeCompare(right))),
|
|
6120
6543
|
preset: checker.preset,
|
|
6121
6544
|
entry: toPosixPath(toRelativePath(options.rootDir, entryPath)),
|
|
6122
6545
|
roots: projects.map((project) => toPosixPath(toRelativePath(options.rootDir, project.configPath))).sort(),
|
|
@@ -6126,7 +6549,7 @@ function createManifest(options) {
|
|
|
6126
6549
|
};
|
|
6127
6550
|
}
|
|
6128
6551
|
return {
|
|
6129
|
-
version:
|
|
6552
|
+
version: 2,
|
|
6130
6553
|
generatedBy: "limina",
|
|
6131
6554
|
checkers: manifestCheckers,
|
|
6132
6555
|
knip: {
|
|
@@ -6146,6 +6569,7 @@ function createManifest(options) {
|
|
|
6146
6569
|
}
|
|
6147
6570
|
function createResult(options) {
|
|
6148
6571
|
const checkerEntries = /* @__PURE__ */ new Map();
|
|
6572
|
+
const configToOutputBuild = /* @__PURE__ */ new Map();
|
|
6149
6573
|
const sourceToBuild = /* @__PURE__ */ new Map();
|
|
6150
6574
|
const sourceToDts = /* @__PURE__ */ new Map();
|
|
6151
6575
|
const dtsToSource = /* @__PURE__ */ new Map();
|
|
@@ -6160,6 +6584,10 @@ function createResult(options) {
|
|
|
6160
6584
|
}));
|
|
6161
6585
|
for (const [checkerName, checkerManifest] of Object.entries(options.manifest.checkers)) {
|
|
6162
6586
|
checkerEntries.set(checkerName, normalizeAbsolutePath(posix.join(options.rootDir, checkerManifest.entry)));
|
|
6587
|
+
configToOutputBuild.set(checkerName, new Map(Object.entries(checkerManifest.configToOutputBuild ?? {}).map(([sourcePath, buildModule]) => [normalizeAbsolutePath(posix.join(options.rootDir, sourcePath)), {
|
|
6588
|
+
kind: buildModule.kind,
|
|
6589
|
+
path: normalizeAbsolutePath(posix.join(options.rootDir, buildModule.path))
|
|
6590
|
+
}])));
|
|
6163
6591
|
sourceToBuild.set(checkerName, new Map(Object.entries(checkerManifest.sourceToBuild ?? {}).map(([sourcePath, buildModule]) => [normalizeAbsolutePath(posix.join(options.rootDir, sourcePath)), {
|
|
6164
6592
|
kind: buildModule.kind,
|
|
6165
6593
|
path: normalizeAbsolutePath(posix.join(options.rootDir, buildModule.path))
|
|
@@ -6172,6 +6600,7 @@ function createResult(options) {
|
|
|
6172
6600
|
checkers: options.checkers,
|
|
6173
6601
|
manifestPath: options.manifestPath,
|
|
6174
6602
|
checkerEntries,
|
|
6603
|
+
configToOutputBuild,
|
|
6175
6604
|
sourceToBuild,
|
|
6176
6605
|
sourceToDts,
|
|
6177
6606
|
dtsToSource,
|
|
@@ -6193,6 +6622,9 @@ function collectGeneratedSourceConfigPaths(generatedGraph) {
|
|
|
6193
6622
|
async function prepareGeneratedTsconfigGraph(config, options = {}) {
|
|
6194
6623
|
const checkers = await resolveGeneratedGraphCheckers(config, options);
|
|
6195
6624
|
const checkerCollectionsByName = /* @__PURE__ */ new Map();
|
|
6625
|
+
const configToOutputBuildByChecker = /* @__PURE__ */ new Map();
|
|
6626
|
+
const outputProjectsByChecker = /* @__PURE__ */ new Map();
|
|
6627
|
+
const outputSolutionsByChecker = /* @__PURE__ */ new Map();
|
|
6196
6628
|
const projectsByChecker = /* @__PURE__ */ new Map();
|
|
6197
6629
|
const rootBuildPathsByChecker = /* @__PURE__ */ new Map();
|
|
6198
6630
|
const solutionsByChecker = /* @__PURE__ */ new Map();
|
|
@@ -6269,6 +6701,27 @@ async function prepareGeneratedTsconfigGraph(config, options = {}) {
|
|
|
6269
6701
|
projects: allProjects,
|
|
6270
6702
|
providerEdges
|
|
6271
6703
|
});
|
|
6704
|
+
const allProjectsByDtsPath = createSourceProjectsByDtsPath(allProjects);
|
|
6705
|
+
for (const checker of checkers) {
|
|
6706
|
+
const outputGraph = createCheckerOutputGraph({
|
|
6707
|
+
allProjectsByDtsPath,
|
|
6708
|
+
checker,
|
|
6709
|
+
collection: checkerCollectionsByName.get(checker.name) ?? {
|
|
6710
|
+
buildModulesBySourcePath: /* @__PURE__ */ new Map(),
|
|
6711
|
+
entryConfigPaths: /* @__PURE__ */ new Set(),
|
|
6712
|
+
projectConfigPaths: /* @__PURE__ */ new Set(),
|
|
6713
|
+
rootConfigPaths: [],
|
|
6714
|
+
solutionConfigPaths: /* @__PURE__ */ new Set(),
|
|
6715
|
+
solutionReferencesBySourcePath: /* @__PURE__ */ new Map()
|
|
6716
|
+
},
|
|
6717
|
+
config,
|
|
6718
|
+
problems,
|
|
6719
|
+
projects: projectsByChecker.get(checker.name) ?? []
|
|
6720
|
+
});
|
|
6721
|
+
configToOutputBuildByChecker.set(checker.name, outputGraph.configToOutputBuild);
|
|
6722
|
+
outputProjectsByChecker.set(checker.name, outputGraph.outputProjects);
|
|
6723
|
+
outputSolutionsByChecker.set(checker.name, outputGraph.outputSolutions);
|
|
6724
|
+
}
|
|
6272
6725
|
providerEdges.sort((left, right) => left.fromChecker.localeCompare(right.fromChecker) || left.fromConfigPath.localeCompare(right.fromConfigPath) || left.toChecker.localeCompare(right.toChecker) || left.toConfigPath.localeCompare(right.toConfigPath) || left.file.localeCompare(right.file) || left.importedSpecifier.localeCompare(right.importedSpecifier));
|
|
6273
6726
|
if (problems.length > 0) throw createGeneratedGraphStructuredError({
|
|
6274
6727
|
config,
|
|
@@ -6276,20 +6729,25 @@ async function prepareGeneratedTsconfigGraph(config, options = {}) {
|
|
|
6276
6729
|
problems
|
|
6277
6730
|
});
|
|
6278
6731
|
const generatedKnip = prepareGeneratedKnipPackageConfigs({
|
|
6732
|
+
checkers,
|
|
6733
|
+
configToOutputBuildByChecker,
|
|
6279
6734
|
config,
|
|
6280
|
-
sourceToBuildByChecker,
|
|
6281
6735
|
workspacePackages: options.workspacePackagesProvider ? await options.workspacePackagesProvider() : await collectWorkspacePackages(config)
|
|
6282
6736
|
});
|
|
6283
6737
|
await Promise.all(checkers.map(async (checker) => {
|
|
6284
6738
|
const checkerName = checker.name;
|
|
6285
6739
|
const projects = projectsByChecker.get(checkerName) ?? [];
|
|
6286
6740
|
const entryPath = checkerEntries.get(checkerName);
|
|
6741
|
+
const outputProjects = outputProjectsByChecker.get(checkerName) ?? [];
|
|
6742
|
+
const outputSolutions = outputSolutionsByChecker.get(checkerName) ?? [];
|
|
6287
6743
|
const solutions = solutionsByChecker.get(checkerName) ?? [];
|
|
6288
6744
|
const rootBuildPaths = rootBuildPathsByChecker.get(checkerName) ?? [];
|
|
6289
6745
|
if (!entryPath) return;
|
|
6290
6746
|
await Promise.all([
|
|
6291
6747
|
...projects.map((project) => writeGeneratedJson(writeContext, project.dtsConfigPath, createGeneratedDtsConfig(config, project))),
|
|
6292
6748
|
...solutions.map((solution) => writeGeneratedJson(writeContext, solution.buildConfigPath, createGeneratedSolutionBuildConfig(config, solution))),
|
|
6749
|
+
...outputProjects.map((project) => writeGeneratedJson(writeContext, project.outputConfigPath, createGeneratedOutputProjectConfig(config, project))),
|
|
6750
|
+
...outputSolutions.map((solution) => writeGeneratedJson(writeContext, solution.buildConfigPath, createGeneratedOutputSolutionConfig(config, solution))),
|
|
6293
6751
|
writeGeneratedJson(writeContext, entryPath, createCheckerBuildConfig({
|
|
6294
6752
|
checkerName,
|
|
6295
6753
|
entryPath,
|
|
@@ -6302,6 +6760,7 @@ async function prepareGeneratedTsconfigGraph(config, options = {}) {
|
|
|
6302
6760
|
const manifest = createManifest({
|
|
6303
6761
|
checkerEntries,
|
|
6304
6762
|
checkers,
|
|
6763
|
+
configToOutputBuildByChecker,
|
|
6305
6764
|
generatedKnipDiagnostics: generatedKnip.diagnostics,
|
|
6306
6765
|
generatedKnipPackageConfigs: generatedKnip.configs.map((entry) => entry.config),
|
|
6307
6766
|
projectsByChecker,
|
|
@@ -7557,17 +8016,17 @@ function createProjectResolveContext(project) {
|
|
|
7557
8016
|
function findOwnerForFile(filePath, owners) {
|
|
7558
8017
|
return owners.filter((owner) => isPathInsideDirectory(filePath, owner.directory)).sort((left, right) => right.directory.length - left.directory.length)[0] ?? null;
|
|
7559
8018
|
}
|
|
7560
|
-
function getManifestPackageName(manifest) {
|
|
8019
|
+
function getManifestPackageName$1(manifest) {
|
|
7561
8020
|
return typeof manifest.name === "string" && manifest.name.trim().length > 0 ? manifest.name.trim() : void 0;
|
|
7562
8021
|
}
|
|
7563
|
-
function isNodeModulesPackageRoot(directory) {
|
|
8022
|
+
function isNodeModulesPackageRoot$1(directory) {
|
|
7564
8023
|
const parentDirectory = posix.dirname(directory);
|
|
7565
8024
|
const parentName = posix.basename(parentDirectory);
|
|
7566
8025
|
if (parentName === "node_modules") return true;
|
|
7567
8026
|
if (parentName.startsWith("@")) return posix.basename(posix.dirname(parentDirectory)) === "node_modules";
|
|
7568
8027
|
return false;
|
|
7569
8028
|
}
|
|
7570
|
-
function isPackageInfoInsideNodeModules(packageInfo) {
|
|
8029
|
+
function isPackageInfoInsideNodeModules$1(packageInfo) {
|
|
7571
8030
|
return normalizeAbsolutePath(packageInfo.directory).split("/").includes("node_modules");
|
|
7572
8031
|
}
|
|
7573
8032
|
function readPackageInfo(packageJsonPath) {
|
|
@@ -7577,21 +8036,10 @@ function readPackageInfo(packageJsonPath) {
|
|
|
7577
8036
|
return {
|
|
7578
8037
|
directory,
|
|
7579
8038
|
manifest,
|
|
7580
|
-
name: getManifestPackageName(manifest),
|
|
8039
|
+
name: getManifestPackageName$1(manifest),
|
|
7581
8040
|
packageJsonPath: normalizedPackageJsonPath
|
|
7582
8041
|
};
|
|
7583
8042
|
}
|
|
7584
|
-
function findNearestPackageScopeInfo(filePath) {
|
|
7585
|
-
const normalizedFilePath = normalizeAbsolutePath(filePath);
|
|
7586
|
-
let currentDir = normalizeAbsolutePath(posix.dirname(normalizedFilePath));
|
|
7587
|
-
while (true) {
|
|
7588
|
-
const packageJsonPath = normalizeAbsolutePath(posix.join(currentDir, "package.json"));
|
|
7589
|
-
if (existsSync(packageJsonPath)) return readPackageInfo(packageJsonPath);
|
|
7590
|
-
const parentDir = posix.dirname(currentDir);
|
|
7591
|
-
if (parentDir === currentDir) return null;
|
|
7592
|
-
currentDir = parentDir;
|
|
7593
|
-
}
|
|
7594
|
-
}
|
|
7595
8043
|
function findNearestPackageInfo(filePath) {
|
|
7596
8044
|
const normalizedFilePath = normalizeAbsolutePath(filePath);
|
|
7597
8045
|
let currentDir = normalizeAbsolutePath(posix.dirname(normalizedFilePath));
|
|
@@ -7599,7 +8047,7 @@ function findNearestPackageInfo(filePath) {
|
|
|
7599
8047
|
const packageJsonPath = normalizeAbsolutePath(posix.join(currentDir, "package.json"));
|
|
7600
8048
|
if (existsSync(packageJsonPath)) {
|
|
7601
8049
|
const packageInfo = readPackageInfo(packageJsonPath);
|
|
7602
|
-
if (packageInfo.name || isNodeModulesPackageRoot(currentDir)) return packageInfo;
|
|
8050
|
+
if (packageInfo.name || isNodeModulesPackageRoot$1(currentDir)) return packageInfo;
|
|
7603
8051
|
}
|
|
7604
8052
|
const parentDir = posix.dirname(currentDir);
|
|
7605
8053
|
if (parentDir === currentDir) return null;
|
|
@@ -7626,7 +8074,7 @@ function classifyResolvedPackageTarget(options) {
|
|
|
7626
8074
|
};
|
|
7627
8075
|
return { kind: "unowned" };
|
|
7628
8076
|
}
|
|
7629
|
-
if (targetOwner?.packageJsonPath === options.owner.packageJsonPath && !isPackageInfoInsideNodeModules(packageInfo)) return {
|
|
8077
|
+
if (targetOwner?.packageJsonPath === options.owner.packageJsonPath && !isPackageInfoInsideNodeModules$1(packageInfo)) return {
|
|
7630
8078
|
kind: "current-owner",
|
|
7631
8079
|
packageInfo
|
|
7632
8080
|
};
|
|
@@ -7872,15 +8320,55 @@ function isDependencyAuthorized(manifest, packageName) {
|
|
|
7872
8320
|
function findPackageImportMatch(importsField, specifier) {
|
|
7873
8321
|
if (!importsField || typeof importsField !== "object") return null;
|
|
7874
8322
|
for (const key of Object.keys(importsField)) {
|
|
7875
|
-
|
|
8323
|
+
const value = importsField[key];
|
|
8324
|
+
if (key === specifier) return {
|
|
8325
|
+
key,
|
|
8326
|
+
targetKind: classifyPackageImportTarget(value),
|
|
8327
|
+
value
|
|
8328
|
+
};
|
|
7876
8329
|
const wildcardIndex = key.indexOf("*");
|
|
7877
8330
|
if (wildcardIndex === -1) continue;
|
|
7878
8331
|
const prefix = key.slice(0, wildcardIndex);
|
|
7879
8332
|
const suffix = key.slice(wildcardIndex + 1);
|
|
7880
|
-
if (specifier.startsWith(prefix) && specifier.endsWith(suffix)) return {
|
|
8333
|
+
if (specifier.startsWith(prefix) && specifier.endsWith(suffix)) return {
|
|
8334
|
+
key,
|
|
8335
|
+
targetKind: classifyPackageImportTarget(value),
|
|
8336
|
+
value
|
|
8337
|
+
};
|
|
7881
8338
|
}
|
|
7882
8339
|
return null;
|
|
7883
8340
|
}
|
|
8341
|
+
function classifyPackageImportTarget(value) {
|
|
8342
|
+
const kinds = /* @__PURE__ */ new Set();
|
|
8343
|
+
collectPackageImportTargetKinds(value, kinds);
|
|
8344
|
+
if (kinds.size === 0) return "unknown";
|
|
8345
|
+
if (kinds.size === 1) return kinds.values().next().value ?? "unknown";
|
|
8346
|
+
return "mixed";
|
|
8347
|
+
}
|
|
8348
|
+
function collectPackageImportTargetKinds(value, kinds) {
|
|
8349
|
+
if (typeof value === "string") {
|
|
8350
|
+
const target = value.trim();
|
|
8351
|
+
if (isRelativeSpecifier(target)) {
|
|
8352
|
+
kinds.add("relative");
|
|
8353
|
+
return;
|
|
8354
|
+
}
|
|
8355
|
+
if (isBarePackageSpecifier(target)) {
|
|
8356
|
+
kinds.add("package");
|
|
8357
|
+
return;
|
|
8358
|
+
}
|
|
8359
|
+
kinds.add("unknown");
|
|
8360
|
+
return;
|
|
8361
|
+
}
|
|
8362
|
+
if (Array.isArray(value)) {
|
|
8363
|
+
for (const item of value) collectPackageImportTargetKinds(item, kinds);
|
|
8364
|
+
return;
|
|
8365
|
+
}
|
|
8366
|
+
if (isPlainRecord(value)) {
|
|
8367
|
+
for (const item of Object.values(value)) collectPackageImportTargetKinds(item, kinds);
|
|
8368
|
+
return;
|
|
8369
|
+
}
|
|
8370
|
+
if (value !== null && value !== void 0) kinds.add("unknown");
|
|
8371
|
+
}
|
|
7884
8372
|
|
|
7885
8373
|
//#endregion
|
|
7886
8374
|
//#region src/core/workspace.ts
|
|
@@ -8062,7 +8550,7 @@ function sortEdges(edges) {
|
|
|
8062
8550
|
function resolveTargetPackage(options) {
|
|
8063
8551
|
return options.declaredTargetPackage ?? (options.graphResolvedFilePath ? findPackageForFile(options.graphResolvedFilePath, options.packages) : null) ?? findPackageForFile(options.resolvedFilePath, options.packages);
|
|
8064
8552
|
}
|
|
8065
|
-
function shouldUseWorkspaceExportResolution
|
|
8553
|
+
function shouldUseWorkspaceExportResolution(options) {
|
|
8066
8554
|
if (!options.declaredTargetPackage) return false;
|
|
8067
8555
|
return !options.resolvedFilePath;
|
|
8068
8556
|
}
|
|
@@ -8107,7 +8595,7 @@ async function collectDependencyGraph(config, options = {}) {
|
|
|
8107
8595
|
const declaredTargetPackage = findPackageForSpecifier(importRecord.specifier, workspacePackages);
|
|
8108
8596
|
const workspaceExportResolution = declaredTargetPackage && workspaceExports.hasExports(declaredTargetPackage.name) ? workspaceExports.get(project.configPath, importRecord.specifier) : null;
|
|
8109
8597
|
const internalResolvedFilePath = resolveInternalImport(importRecord.specifier, fileName, project.options, project, importAnalysis);
|
|
8110
|
-
const useWorkspaceExportResolution = shouldUseWorkspaceExportResolution
|
|
8598
|
+
const useWorkspaceExportResolution = shouldUseWorkspaceExportResolution({
|
|
8111
8599
|
declaredTargetPackage,
|
|
8112
8600
|
resolvedFilePath: internalResolvedFilePath
|
|
8113
8601
|
});
|
|
@@ -9109,6 +9597,202 @@ function clearCliScreen() {
|
|
|
9109
9597
|
readline.clearScreenDown(process.stdout);
|
|
9110
9598
|
}
|
|
9111
9599
|
|
|
9600
|
+
//#endregion
|
|
9601
|
+
//#region src/core/workspace/lookup.ts
|
|
9602
|
+
var WorkspaceLookupIndex = class {
|
|
9603
|
+
rootDir;
|
|
9604
|
+
#importers;
|
|
9605
|
+
#namedPackagesByName = /* @__PURE__ */ new Map();
|
|
9606
|
+
#ownersByDirectory;
|
|
9607
|
+
#packageInfoByPackageJsonPath = /* @__PURE__ */ new Map();
|
|
9608
|
+
#packagesByDirectory;
|
|
9609
|
+
#packagesByPackageJsonPath = /* @__PURE__ */ new Map();
|
|
9610
|
+
#importerByFilePath = /* @__PURE__ */ new Map();
|
|
9611
|
+
#nearestNamedPackageInfoByDirectory = /* @__PURE__ */ new Map();
|
|
9612
|
+
#nearestPackageScopeInfoByDirectory = /* @__PURE__ */ new Map();
|
|
9613
|
+
#ownerByFilePath = /* @__PURE__ */ new Map();
|
|
9614
|
+
#packageByFilePath = /* @__PURE__ */ new Map();
|
|
9615
|
+
#resolvedPackageTargetByKey = /* @__PURE__ */ new Map();
|
|
9616
|
+
constructor(options) {
|
|
9617
|
+
this.rootDir = normalizeAbsolutePath(options.rootDir);
|
|
9618
|
+
this.#importers = options.importers.map((importer) => ({
|
|
9619
|
+
directory: normalizeAbsolutePath(importer.directory),
|
|
9620
|
+
importer
|
|
9621
|
+
}));
|
|
9622
|
+
this.#ownersByDirectory = createDirectoryMap(options.owners);
|
|
9623
|
+
this.#packagesByDirectory = createDirectoryMap(options.packages);
|
|
9624
|
+
for (const workspacePackage of options.packages) {
|
|
9625
|
+
const packageJsonPath = normalizeAbsolutePath(posix.join(workspacePackage.directory, "package.json"));
|
|
9626
|
+
this.#packagesByPackageJsonPath.set(packageJsonPath, workspacePackage);
|
|
9627
|
+
if (isNamedWorkspacePackage(workspacePackage) && !this.#namedPackagesByName.has(workspacePackage.name)) this.#namedPackagesByName.set(workspacePackage.name, workspacePackage);
|
|
9628
|
+
}
|
|
9629
|
+
}
|
|
9630
|
+
findPackageForFile(filePath) {
|
|
9631
|
+
const normalizedFilePath = normalizeAbsolutePath(filePath);
|
|
9632
|
+
const cached = this.#packageByFilePath.get(normalizedFilePath);
|
|
9633
|
+
if (cached !== void 0) return cached;
|
|
9634
|
+
const workspacePackage = findNearestDirectoryItem(normalizedFilePath, this.#packagesByDirectory);
|
|
9635
|
+
this.#packageByFilePath.set(normalizedFilePath, workspacePackage);
|
|
9636
|
+
return workspacePackage;
|
|
9637
|
+
}
|
|
9638
|
+
findOwnerForFile(filePath) {
|
|
9639
|
+
const normalizedFilePath = normalizeAbsolutePath(filePath);
|
|
9640
|
+
const cached = this.#ownerByFilePath.get(normalizedFilePath);
|
|
9641
|
+
if (cached !== void 0) return cached;
|
|
9642
|
+
const owner = findNearestDirectoryItem(normalizedFilePath, this.#ownersByDirectory);
|
|
9643
|
+
this.#ownerByFilePath.set(normalizedFilePath, owner);
|
|
9644
|
+
return owner;
|
|
9645
|
+
}
|
|
9646
|
+
findImporterForFile(filePath) {
|
|
9647
|
+
const normalizedFilePath = normalizeAbsolutePath(filePath);
|
|
9648
|
+
const cached = this.#importerByFilePath.get(normalizedFilePath);
|
|
9649
|
+
if (cached !== void 0) return cached;
|
|
9650
|
+
const importer = this.#importers.find((candidate) => isPathInsideNormalizedDirectory(normalizedFilePath, candidate.directory))?.importer ?? null;
|
|
9651
|
+
this.#importerByFilePath.set(normalizedFilePath, importer);
|
|
9652
|
+
return importer;
|
|
9653
|
+
}
|
|
9654
|
+
findNearestPackageScopeInfo(filePath) {
|
|
9655
|
+
const directory = normalizeAbsolutePath(posix.dirname(normalizeAbsolutePath(filePath)));
|
|
9656
|
+
return this.#findNearestPackageInfoFromDirectory(directory, { requireNamedPackageOrNodeModulesPackage: false });
|
|
9657
|
+
}
|
|
9658
|
+
findPackageForSpecifier(specifier) {
|
|
9659
|
+
return this.#namedPackagesByName.get(getPackageRootSpecifier(specifier)) ?? null;
|
|
9660
|
+
}
|
|
9661
|
+
classifyResolvedPackageTarget(options) {
|
|
9662
|
+
const normalizedResolvedFilePath = normalizeAbsolutePath(options.resolvedFilePath);
|
|
9663
|
+
const cacheKey = `${options.owner.packageJsonPath}\0${normalizedResolvedFilePath}`;
|
|
9664
|
+
const cached = this.#resolvedPackageTargetByKey.get(cacheKey);
|
|
9665
|
+
if (cached) return cached;
|
|
9666
|
+
const packageInfo = this.#findNearestPackageInfoFromDirectory(normalizeAbsolutePath(posix.dirname(normalizedResolvedFilePath)), { requireNamedPackageOrNodeModulesPackage: true });
|
|
9667
|
+
const targetOwner = this.findOwnerForFile(normalizedResolvedFilePath);
|
|
9668
|
+
const target = this.#classifyResolvedPackageTarget({
|
|
9669
|
+
owner: options.owner,
|
|
9670
|
+
packageInfo,
|
|
9671
|
+
targetOwner
|
|
9672
|
+
});
|
|
9673
|
+
this.#resolvedPackageTargetByKey.set(cacheKey, target);
|
|
9674
|
+
return target;
|
|
9675
|
+
}
|
|
9676
|
+
#classifyResolvedPackageTarget(options) {
|
|
9677
|
+
if (!options.packageInfo) {
|
|
9678
|
+
if (options.targetOwner?.packageJsonPath === options.owner.packageJsonPath) return {
|
|
9679
|
+
kind: "current-owner",
|
|
9680
|
+
packageInfo: {
|
|
9681
|
+
directory: options.owner.directory,
|
|
9682
|
+
manifest: options.owner.manifest,
|
|
9683
|
+
...options.owner.name ? { name: options.owner.name } : {},
|
|
9684
|
+
packageJsonPath: options.owner.packageJsonPath
|
|
9685
|
+
}
|
|
9686
|
+
};
|
|
9687
|
+
return { kind: "unowned" };
|
|
9688
|
+
}
|
|
9689
|
+
if (options.targetOwner?.packageJsonPath === options.owner.packageJsonPath && !isPackageInfoInsideNodeModules(options.packageInfo)) return {
|
|
9690
|
+
kind: "current-owner",
|
|
9691
|
+
packageInfo: options.packageInfo
|
|
9692
|
+
};
|
|
9693
|
+
if (options.targetOwner && options.targetOwner.packageJsonPath !== options.owner.packageJsonPath) return {
|
|
9694
|
+
kind: "other-owner",
|
|
9695
|
+
packageInfo: options.packageInfo,
|
|
9696
|
+
targetOwner: options.targetOwner,
|
|
9697
|
+
workspacePackage: this.#findWorkspacePackageForPackageInfo(options.packageInfo)
|
|
9698
|
+
};
|
|
9699
|
+
return {
|
|
9700
|
+
kind: "artifact-package",
|
|
9701
|
+
packageInfo: options.packageInfo
|
|
9702
|
+
};
|
|
9703
|
+
}
|
|
9704
|
+
#findNearestPackageInfoFromDirectory(directory, options) {
|
|
9705
|
+
const cache = options.requireNamedPackageOrNodeModulesPackage ? this.#nearestNamedPackageInfoByDirectory : this.#nearestPackageScopeInfoByDirectory;
|
|
9706
|
+
const visitedDirectories = [];
|
|
9707
|
+
let currentDir = normalizeAbsolutePath(directory);
|
|
9708
|
+
while (true) {
|
|
9709
|
+
const cached = cache.get(currentDir);
|
|
9710
|
+
if (cached !== void 0) {
|
|
9711
|
+
setCachedPackageInfo(cache, visitedDirectories, cached);
|
|
9712
|
+
return cached;
|
|
9713
|
+
}
|
|
9714
|
+
visitedDirectories.push(currentDir);
|
|
9715
|
+
const packageJsonPath = normalizeAbsolutePath(posix.join(currentDir, "package.json"));
|
|
9716
|
+
if (existsSync(packageJsonPath)) {
|
|
9717
|
+
const packageInfo = this.#readPackageInfo(packageJsonPath);
|
|
9718
|
+
if (!options.requireNamedPackageOrNodeModulesPackage || packageInfo.name || isNodeModulesPackageRoot(currentDir)) {
|
|
9719
|
+
setCachedPackageInfo(cache, visitedDirectories, packageInfo);
|
|
9720
|
+
return packageInfo;
|
|
9721
|
+
}
|
|
9722
|
+
}
|
|
9723
|
+
const parentDir = posix.dirname(currentDir);
|
|
9724
|
+
if (parentDir === currentDir) {
|
|
9725
|
+
setCachedPackageInfo(cache, visitedDirectories, null);
|
|
9726
|
+
return null;
|
|
9727
|
+
}
|
|
9728
|
+
currentDir = parentDir;
|
|
9729
|
+
}
|
|
9730
|
+
}
|
|
9731
|
+
#findWorkspacePackageForPackageInfo(packageInfo) {
|
|
9732
|
+
return this.#packagesByPackageJsonPath.get(packageInfo.packageJsonPath) ?? (packageInfo.name ? this.#namedPackagesByName.get(packageInfo.name) : void 0) ?? null;
|
|
9733
|
+
}
|
|
9734
|
+
#readPackageInfo(packageJsonPath) {
|
|
9735
|
+
const normalizedPackageJsonPath = normalizeAbsolutePath(packageJsonPath);
|
|
9736
|
+
const cached = this.#packageInfoByPackageJsonPath.get(normalizedPackageJsonPath);
|
|
9737
|
+
if (cached) return cached;
|
|
9738
|
+
const directory = normalizeAbsolutePath(posix.dirname(packageJsonPath));
|
|
9739
|
+
const manifest = readJsonFile(normalizedPackageJsonPath);
|
|
9740
|
+
const name = getManifestPackageName(manifest);
|
|
9741
|
+
const packageInfo = {
|
|
9742
|
+
directory,
|
|
9743
|
+
manifest,
|
|
9744
|
+
...name ? { name } : {},
|
|
9745
|
+
packageJsonPath: normalizedPackageJsonPath
|
|
9746
|
+
};
|
|
9747
|
+
this.#packageInfoByPackageJsonPath.set(normalizedPackageJsonPath, packageInfo);
|
|
9748
|
+
return packageInfo;
|
|
9749
|
+
}
|
|
9750
|
+
};
|
|
9751
|
+
function createWorkspaceLookupIndex(options) {
|
|
9752
|
+
return new WorkspaceLookupIndex(options);
|
|
9753
|
+
}
|
|
9754
|
+
function createDirectoryMap(items) {
|
|
9755
|
+
const itemsByDirectory = /* @__PURE__ */ new Map();
|
|
9756
|
+
for (const item of items) {
|
|
9757
|
+
const directory = normalizeAbsolutePath(item.directory);
|
|
9758
|
+
if (!itemsByDirectory.has(directory)) itemsByDirectory.set(directory, item);
|
|
9759
|
+
}
|
|
9760
|
+
return itemsByDirectory;
|
|
9761
|
+
}
|
|
9762
|
+
function findNearestDirectoryItem(filePath, itemsByDirectory) {
|
|
9763
|
+
let currentDir = normalizeAbsolutePath(filePath);
|
|
9764
|
+
const exactMatch = itemsByDirectory.get(currentDir);
|
|
9765
|
+
if (exactMatch) return exactMatch;
|
|
9766
|
+
currentDir = normalizeAbsolutePath(posix.dirname(currentDir));
|
|
9767
|
+
while (true) {
|
|
9768
|
+
const item = itemsByDirectory.get(currentDir);
|
|
9769
|
+
if (item) return item;
|
|
9770
|
+
const parentDir = posix.dirname(currentDir);
|
|
9771
|
+
if (parentDir === currentDir) return null;
|
|
9772
|
+
currentDir = parentDir;
|
|
9773
|
+
}
|
|
9774
|
+
}
|
|
9775
|
+
function getManifestPackageName(manifest) {
|
|
9776
|
+
return typeof manifest.name === "string" && manifest.name.trim().length > 0 ? manifest.name.trim() : void 0;
|
|
9777
|
+
}
|
|
9778
|
+
function isNodeModulesPackageRoot(directory) {
|
|
9779
|
+
const parentDirectory = posix.dirname(directory);
|
|
9780
|
+
const parentName = posix.basename(parentDirectory);
|
|
9781
|
+
if (parentName === "node_modules") return true;
|
|
9782
|
+
if (parentName.startsWith("@")) return posix.basename(posix.dirname(parentDirectory)) === "node_modules";
|
|
9783
|
+
return false;
|
|
9784
|
+
}
|
|
9785
|
+
function isPackageInfoInsideNodeModules(packageInfo) {
|
|
9786
|
+
return normalizeAbsolutePath(packageInfo.directory).split("/").includes("node_modules");
|
|
9787
|
+
}
|
|
9788
|
+
function isPathInsideNormalizedDirectory(normalizedFilePath, normalizedDirectoryPath) {
|
|
9789
|
+
const directoryPrefix = normalizedDirectoryPath.endsWith("/") ? normalizedDirectoryPath : `${normalizedDirectoryPath}/`;
|
|
9790
|
+
return normalizedFilePath === normalizedDirectoryPath || normalizedFilePath.startsWith(directoryPrefix);
|
|
9791
|
+
}
|
|
9792
|
+
function setCachedPackageInfo(cache, directories, packageInfo) {
|
|
9793
|
+
for (const directory of directories) cache.set(directory, packageInfo);
|
|
9794
|
+
}
|
|
9795
|
+
|
|
9112
9796
|
//#endregion
|
|
9113
9797
|
//#region src/package-check/entry-selection.ts
|
|
9114
9798
|
const DEFAULT_PACKAGE_CHECKS = [
|
|
@@ -9585,6 +10269,14 @@ var LiminaPreflightManager = class {
|
|
|
9585
10269
|
ensureImporters() {
|
|
9586
10270
|
return this.#ensure("importers", () => this.core.workspace.getImporters());
|
|
9587
10271
|
}
|
|
10272
|
+
ensureWorkspaceLookupIndex() {
|
|
10273
|
+
return this.#ensure("workspaceLookupIndex", async () => createWorkspaceLookupIndex({
|
|
10274
|
+
importers: await this.ensureImporters(),
|
|
10275
|
+
owners: await this.ensurePackageOwners(),
|
|
10276
|
+
packages: await this.ensureWorkspacePackages(),
|
|
10277
|
+
rootDir: this.config.rootDir
|
|
10278
|
+
}));
|
|
10279
|
+
}
|
|
9588
10280
|
ensureWorkspaceDependencyDeclarations() {
|
|
9589
10281
|
return this.#ensure("workspaceDependencyDeclarations", () => this.core.workspace.getWorkspaceDependencyDeclarations());
|
|
9590
10282
|
}
|
|
@@ -10318,6 +11010,8 @@ const GRAPH_CHECK_ITEM_NAMES = [
|
|
|
10318
11010
|
"condition domains",
|
|
10319
11011
|
"reference completeness"
|
|
10320
11012
|
];
|
|
11013
|
+
const GENERATED_REFERENCE_CYCLE_REASON = "Generated declaration project references must be acyclic so build-mode checkers can order declaration builds.";
|
|
11014
|
+
const GENERATED_REFERENCE_CYCLE_FIX = "Break the cycle by merging tightly coupled source scopes, extracting shared contracts, moving runtime wiring to a higher-level entry, or using an intentional declaration boundary.";
|
|
10321
11015
|
function getGeneratedCheckerNamespace(configPath) {
|
|
10322
11016
|
const markerIndex = configPath.indexOf("/.limina/tsconfig/checkers/");
|
|
10323
11017
|
if (markerIndex === -1) return null;
|
|
@@ -10389,7 +11083,7 @@ function addDeniedReferenceProblems(options) {
|
|
|
10389
11083
|
options.checks.add();
|
|
10390
11084
|
if (!options.projectsByPath.has(referencePath)) continue;
|
|
10391
11085
|
const deniedRefRule = getDeniedRefRule(options.rules, options.project.labels, referencePath);
|
|
10392
|
-
const targetPackage = findPackageForFile(referencePath
|
|
11086
|
+
const targetPackage = options.workspaceLookup.findPackageForFile(referencePath);
|
|
10393
11087
|
const deniedDepRule = targetPackage?.name ? getDeniedDepRuleForPackage(options.rules, options.project.labels, targetPackage.name) : null;
|
|
10394
11088
|
if (!deniedRefRule && !deniedDepRule) continue;
|
|
10395
11089
|
const lines = [
|
|
@@ -10456,8 +11150,8 @@ function getNodeModulesPackageName(filePath) {
|
|
|
10456
11150
|
}
|
|
10457
11151
|
return packageName;
|
|
10458
11152
|
}
|
|
10459
|
-
function getResolvedPackageName(filePath,
|
|
10460
|
-
return getNodeModulesPackageName(filePath) ?? findPackageForFile(filePath
|
|
11153
|
+
function getResolvedPackageName(filePath, workspaceLookup) {
|
|
11154
|
+
return getNodeModulesPackageName(filePath) ?? workspaceLookup.findPackageForFile(filePath)?.name ?? null;
|
|
10461
11155
|
}
|
|
10462
11156
|
function addNamelessWorkspaceReferenceProblem(options) {
|
|
10463
11157
|
const packageManifestPath = posix.join(options.workspacePackage.directory, "package.json");
|
|
@@ -10478,23 +11172,19 @@ function addNamelessWorkspaceReferenceProblem(options) {
|
|
|
10478
11172
|
title: "Project reference crosses workspace package without package identity"
|
|
10479
11173
|
});
|
|
10480
11174
|
}
|
|
10481
|
-
function getResolvedWorkspacePackage(filePath,
|
|
11175
|
+
function getResolvedWorkspacePackage(filePath, workspaceLookup) {
|
|
10482
11176
|
if (getNodeModulesPackageName(filePath)) return null;
|
|
10483
|
-
return findPackageForFile(filePath
|
|
11177
|
+
return workspaceLookup.findPackageForFile(filePath);
|
|
10484
11178
|
}
|
|
10485
|
-
function
|
|
10486
|
-
if (!options.targetPackage) return false;
|
|
10487
|
-
return !options.resolvedFilePath;
|
|
10488
|
-
}
|
|
10489
|
-
function addWorkspaceReferenceDependencyProblems(config, project, projectsByPath, packages, importers, problems, checks) {
|
|
11179
|
+
function addWorkspaceReferenceDependencyProblems(config, project, projectsByPath, workspaceLookup, problems, checks) {
|
|
10490
11180
|
if (!isDtsProjectConfig(project.configPath)) return;
|
|
10491
|
-
const sourcePackage = findPackageForFile(project.configPath
|
|
10492
|
-
const importer = sourcePackage ? findImporterForFile(project.configPath
|
|
11181
|
+
const sourcePackage = workspaceLookup.findPackageForFile(project.configPath);
|
|
11182
|
+
const importer = sourcePackage ? workspaceLookup.findImporterForFile(project.configPath) : null;
|
|
10493
11183
|
if (!sourcePackage) return;
|
|
10494
11184
|
for (const referencePath of project.references) {
|
|
10495
11185
|
checks.add();
|
|
10496
11186
|
if (!projectsByPath.has(referencePath)) continue;
|
|
10497
|
-
const targetPackage = findPackageForFile(referencePath
|
|
11187
|
+
const targetPackage = workspaceLookup.findPackageForFile(referencePath);
|
|
10498
11188
|
if (!targetPackage || targetPackage.directory === sourcePackage.directory) continue;
|
|
10499
11189
|
if (!isNamedWorkspacePackage(sourcePackage)) {
|
|
10500
11190
|
addNamelessWorkspaceReferenceProblem({
|
|
@@ -10540,6 +11230,80 @@ function addWorkspaceReferenceDependencyProblems(config, project, projectsByPath
|
|
|
10540
11230
|
});
|
|
10541
11231
|
}
|
|
10542
11232
|
}
|
|
11233
|
+
function createGeneratedReferenceGraph(projects) {
|
|
11234
|
+
const dtsProjects = projects.filter((project) => isDtsProjectConfig(project.configPath));
|
|
11235
|
+
const dtsProjectPaths = new Set(dtsProjects.map((project) => project.configPath));
|
|
11236
|
+
const graph = /* @__PURE__ */ new Map();
|
|
11237
|
+
for (const project of dtsProjects) graph.set(project.configPath, new Set([...project.references].filter((referencePath) => dtsProjectPaths.has(referencePath)).sort()));
|
|
11238
|
+
return graph;
|
|
11239
|
+
}
|
|
11240
|
+
function collectGeneratedReferenceComponents(graph) {
|
|
11241
|
+
const components = [];
|
|
11242
|
+
const indexByPath = /* @__PURE__ */ new Map();
|
|
11243
|
+
const lowLinkByPath = /* @__PURE__ */ new Map();
|
|
11244
|
+
const stack = [];
|
|
11245
|
+
const pathsOnStack = /* @__PURE__ */ new Set();
|
|
11246
|
+
let nextIndex = 0;
|
|
11247
|
+
function visit(configPath) {
|
|
11248
|
+
indexByPath.set(configPath, nextIndex);
|
|
11249
|
+
lowLinkByPath.set(configPath, nextIndex);
|
|
11250
|
+
nextIndex += 1;
|
|
11251
|
+
stack.push(configPath);
|
|
11252
|
+
pathsOnStack.add(configPath);
|
|
11253
|
+
for (const referencePath of graph.get(configPath) ?? []) {
|
|
11254
|
+
if (!indexByPath.has(referencePath)) {
|
|
11255
|
+
visit(referencePath);
|
|
11256
|
+
lowLinkByPath.set(configPath, Math.min(lowLinkByPath.get(configPath), lowLinkByPath.get(referencePath)));
|
|
11257
|
+
continue;
|
|
11258
|
+
}
|
|
11259
|
+
if (pathsOnStack.has(referencePath)) lowLinkByPath.set(configPath, Math.min(lowLinkByPath.get(configPath), indexByPath.get(referencePath)));
|
|
11260
|
+
}
|
|
11261
|
+
if (lowLinkByPath.get(configPath) !== indexByPath.get(configPath)) return;
|
|
11262
|
+
const component = [];
|
|
11263
|
+
while (stack.length > 0) {
|
|
11264
|
+
const currentPath = stack.pop();
|
|
11265
|
+
pathsOnStack.delete(currentPath);
|
|
11266
|
+
component.push(currentPath);
|
|
11267
|
+
if (currentPath === configPath) break;
|
|
11268
|
+
}
|
|
11269
|
+
components.push(component.sort());
|
|
11270
|
+
}
|
|
11271
|
+
for (const configPath of [...graph.keys()].sort()) if (!indexByPath.has(configPath)) visit(configPath);
|
|
11272
|
+
return components.sort((left, right) => left[0].localeCompare(right[0]));
|
|
11273
|
+
}
|
|
11274
|
+
function getGeneratedReferenceCycleEdges(graph, members) {
|
|
11275
|
+
const memberPaths = new Set(members);
|
|
11276
|
+
return members.flatMap((from) => [...graph.get(from) ?? []].filter((to) => memberPaths.has(to)).map((to) => ({
|
|
11277
|
+
from,
|
|
11278
|
+
to
|
|
11279
|
+
}))).sort((left, right) => left.from.localeCompare(right.from) || left.to.localeCompare(right.to));
|
|
11280
|
+
}
|
|
11281
|
+
function addGeneratedReferenceCycleProblems(options) {
|
|
11282
|
+
const graph = createGeneratedReferenceGraph(options.projects);
|
|
11283
|
+
options.checks.add(graph.size);
|
|
11284
|
+
for (const component of collectGeneratedReferenceComponents(graph)) {
|
|
11285
|
+
const hasSelfReference = Boolean(component[0] && graph.get(component[0])?.has(component[0]));
|
|
11286
|
+
if (component.length === 1 && !hasSelfReference) continue;
|
|
11287
|
+
const members = [...component].sort();
|
|
11288
|
+
const internalEdges = getGeneratedReferenceCycleEdges(graph, members);
|
|
11289
|
+
const lines = [
|
|
11290
|
+
"Generated project reference cycle:",
|
|
11291
|
+
" projects:",
|
|
11292
|
+
...members.map((member) => ` - ${toRelativePath(options.config.rootDir, member)}`),
|
|
11293
|
+
" references in cycle:",
|
|
11294
|
+
...internalEdges.map((edge) => ` - ${toRelativePath(options.config.rootDir, edge.from)} -> ${toRelativePath(options.config.rootDir, edge.to)}`),
|
|
11295
|
+
` reason: ${GENERATED_REFERENCE_CYCLE_REASON}`,
|
|
11296
|
+
` fix: ${GENERATED_REFERENCE_CYCLE_FIX}`
|
|
11297
|
+
];
|
|
11298
|
+
addGraphProblem(options.problems, lines, {
|
|
11299
|
+
code: LIMINA_CHECK_ISSUE_CODES.graphReferenceCycle,
|
|
11300
|
+
filePath: members[0],
|
|
11301
|
+
fix: GENERATED_REFERENCE_CYCLE_FIX,
|
|
11302
|
+
reason: GENERATED_REFERENCE_CYCLE_REASON,
|
|
11303
|
+
title: "Generated project reference cycle"
|
|
11304
|
+
});
|
|
11305
|
+
}
|
|
11306
|
+
}
|
|
10543
11307
|
function getExpectedReferencesForProject(expectedReferencesByProjectPath, project) {
|
|
10544
11308
|
const expectedReferences = expectedReferencesByProjectPath.get(project.configPath) ?? /* @__PURE__ */ new Map();
|
|
10545
11309
|
expectedReferencesByProjectPath.set(project.configPath, expectedReferences);
|
|
@@ -10673,30 +11437,34 @@ function collectExpectedReferenceForImport(options) {
|
|
|
10673
11437
|
});
|
|
10674
11438
|
}
|
|
10675
11439
|
function resolveImportForReferenceExpectation(options) {
|
|
10676
|
-
const targetPackage = findPackageForSpecifier(options.importRecord.specifier
|
|
10677
|
-
const importer = findImporterForFile(options.importRecord.filePath
|
|
11440
|
+
const targetPackage = options.context.workspaceLookup.findPackageForSpecifier(options.importRecord.specifier);
|
|
11441
|
+
const importer = options.context.workspaceLookup.findImporterForFile(options.importRecord.filePath);
|
|
10678
11442
|
const workspaceExportResolution = getWorkspaceExportResolution({
|
|
10679
11443
|
context: options.context,
|
|
10680
11444
|
importRecord: options.importRecord,
|
|
10681
11445
|
project: options.project,
|
|
10682
11446
|
targetPackage
|
|
10683
11447
|
});
|
|
10684
|
-
|
|
10685
|
-
|
|
11448
|
+
const declarationProvider = resolveDeclarationProvider({
|
|
11449
|
+
compilerOptions: options.project.options,
|
|
11450
|
+
containingFile: options.filePath,
|
|
11451
|
+
fileOwnerLookup: options.context.fileOwnerLookup,
|
|
11452
|
+
importAnalysis: options.context.importAnalysis,
|
|
11453
|
+
importRecord: options.importRecord,
|
|
11454
|
+
project: options.project
|
|
11455
|
+
});
|
|
11456
|
+
const workspaceTypeScriptResolvedFilePath = workspaceExportResolution?.typeScriptResolvedFileName ?? null;
|
|
11457
|
+
const graphResolvedFilePath = declarationProvider.kind === "declaration" || declarationProvider.kind === "source" ? declarationProvider.typeScriptResolution.resolvedFileName : workspaceTypeScriptResolvedFilePath;
|
|
11458
|
+
if (!graphResolvedFilePath && declarationProvider.kind === "oxc-only") {
|
|
11459
|
+
addOxcOnlyDeclarationProviderProblem({
|
|
10686
11460
|
context: options.context,
|
|
10687
11461
|
importRecord: options.importRecord,
|
|
10688
|
-
|
|
10689
|
-
|
|
11462
|
+
oxcResolvedFilePath: declarationProvider.oxcResolvedFilePath,
|
|
11463
|
+
project: options.project
|
|
10690
11464
|
});
|
|
10691
11465
|
return null;
|
|
10692
11466
|
}
|
|
10693
|
-
|
|
10694
|
-
const useWorkspaceExportResolution = shouldUseWorkspaceExportResolution({
|
|
10695
|
-
resolvedFilePath: internalResolvedFilePath,
|
|
10696
|
-
targetPackage
|
|
10697
|
-
});
|
|
10698
|
-
const resolvedFilePath = (useWorkspaceExportResolution ? workspaceExportResolution?.oxcResolvedFileName : null) ?? internalResolvedFilePath;
|
|
10699
|
-
if (!resolvedFilePath) {
|
|
11467
|
+
if (!graphResolvedFilePath && declarationProvider.kind === "unresolved") {
|
|
10700
11468
|
addUnresolvedWorkspaceImportProblem({
|
|
10701
11469
|
context: options.context,
|
|
10702
11470
|
importRecord: options.importRecord,
|
|
@@ -10706,22 +11474,22 @@ function resolveImportForReferenceExpectation(options) {
|
|
|
10706
11474
|
});
|
|
10707
11475
|
return null;
|
|
10708
11476
|
}
|
|
10709
|
-
|
|
10710
|
-
|
|
10711
|
-
addUnresolvedWorkspaceImportProblem({
|
|
11477
|
+
if (workspaceExportResolution && !workspaceExportResolution.hasTypeScriptStableEntry) {
|
|
11478
|
+
addWorkspacePackageExportWithoutTypeEntryProblem({
|
|
10712
11479
|
context: options.context,
|
|
10713
11480
|
importRecord: options.importRecord,
|
|
10714
11481
|
project: options.project,
|
|
10715
|
-
|
|
10716
|
-
title: "Unresolved workspace import in TypeScript:"
|
|
11482
|
+
resolution: workspaceExportResolution
|
|
10717
11483
|
});
|
|
10718
11484
|
return null;
|
|
10719
11485
|
}
|
|
10720
|
-
|
|
11486
|
+
if (!graphResolvedFilePath) return null;
|
|
11487
|
+
const resolvedFilePath = graphResolvedFilePath;
|
|
11488
|
+
const targetWorkspacePackageForResolved = getResolvedWorkspacePackage(graphResolvedFilePath, options.context.workspaceLookup);
|
|
10721
11489
|
const targetPackageForGraph = getTargetPackageForGraph({
|
|
10722
11490
|
targetPackage,
|
|
10723
11491
|
targetWorkspacePackageForResolved,
|
|
10724
|
-
useWorkspaceExportResolution
|
|
11492
|
+
useWorkspaceExportResolution: Boolean(workspaceExportResolution)
|
|
10725
11493
|
});
|
|
10726
11494
|
const deniedDepRule = getDeniedDepRuleForResolvedPackage({
|
|
10727
11495
|
context: options.context,
|
|
@@ -10738,6 +11506,7 @@ function resolveImportForReferenceExpectation(options) {
|
|
|
10738
11506
|
});
|
|
10739
11507
|
return null;
|
|
10740
11508
|
}
|
|
11509
|
+
if (isDeclarationFileFamily(graphResolvedFilePath)) return null;
|
|
10741
11510
|
return {
|
|
10742
11511
|
graphResolvedFilePath,
|
|
10743
11512
|
importer,
|
|
@@ -10774,7 +11543,7 @@ function getTargetPackageForGraph(options) {
|
|
|
10774
11543
|
return null;
|
|
10775
11544
|
}
|
|
10776
11545
|
function getDeniedDepRuleForResolvedPackage(options) {
|
|
10777
|
-
const resolvedPackageName = getResolvedPackageName(options.resolvedFilePath, options.context.
|
|
11546
|
+
const resolvedPackageName = getResolvedPackageName(options.resolvedFilePath, options.context.workspaceLookup);
|
|
10778
11547
|
if (!resolvedPackageName) return null;
|
|
10779
11548
|
return getDeniedDepRuleForPackage(options.context.graphRules, options.project.labels, resolvedPackageName);
|
|
10780
11549
|
}
|
|
@@ -10789,6 +11558,23 @@ function addUnresolvedWorkspaceImportProblem(options) {
|
|
|
10789
11558
|
` current references: ${formatReferences(options.context.config.rootDir, options.project.references)}`
|
|
10790
11559
|
].join("\n"));
|
|
10791
11560
|
}
|
|
11561
|
+
function addOxcOnlyDeclarationProviderProblem(options) {
|
|
11562
|
+
addGraphProblem(options.context.problems, [
|
|
11563
|
+
"Oxc can resolve this specifier, but TypeScript cannot:",
|
|
11564
|
+
` importing project: ${toRelativePath(options.context.config.rootDir, options.project.configPath)}`,
|
|
11565
|
+
` file: ${formatImportRecordLocation(options.context.config.rootDir, options.importRecord)}`,
|
|
11566
|
+
` imported specifier: ${options.importRecord.specifier}`,
|
|
11567
|
+
` Oxc resolved file: ${toRelativePath(options.context.config.rootDir, options.oxcResolvedFilePath)}`,
|
|
11568
|
+
" reason: declaration references follow the checker-aware TypeScript declaration provider, not the Oxc runtime-like resolver.",
|
|
11569
|
+
" fix: check moduleResolution, exports.types/types conditions, paths, customConditions, and package boundaries."
|
|
11570
|
+
], {
|
|
11571
|
+
code: LIMINA_CHECK_ISSUE_CODES.graphWorkspaceImportUnresolved,
|
|
11572
|
+
filePath: options.importRecord.filePath,
|
|
11573
|
+
fix: "Check moduleResolution, exports.types/types conditions, paths, customConditions, and package boundaries.",
|
|
11574
|
+
reason: "Oxc resolved this specifier, but TypeScript could not resolve a declaration provider.",
|
|
11575
|
+
title: "Oxc can resolve this specifier, but TypeScript cannot"
|
|
11576
|
+
});
|
|
11577
|
+
}
|
|
10792
11578
|
function findExpectedReferenceTargetProjectPath(options) {
|
|
10793
11579
|
if (shouldSkipWorkspaceExportResolvedOutsideGraph(options)) return null;
|
|
10794
11580
|
if (addBuildArtifactImportProblem(options)) return null;
|
|
@@ -10929,7 +11715,7 @@ async function runGraphCheckImpl(config, options = {}) {
|
|
|
10929
11715
|
const projectsByPath = new Map(projects.map((project) => [project.configPath, project]));
|
|
10930
11716
|
const fileOwnerLookup = createFileOwnerLookup(projects);
|
|
10931
11717
|
const packages = await preflight.ensureWorkspacePackages();
|
|
10932
|
-
const
|
|
11718
|
+
const workspaceLookup = await preflight.ensureWorkspaceLookupIndex();
|
|
10933
11719
|
checkItems.start("source graph routes");
|
|
10934
11720
|
problems.push(...graphRoute.problems);
|
|
10935
11721
|
const customConditionConsistencyContext = createCustomConditionConsistencyContext(projectsByPath);
|
|
@@ -10960,14 +11746,20 @@ async function runGraphCheckImpl(config, options = {}) {
|
|
|
10960
11746
|
addDeniedReferenceProblems({
|
|
10961
11747
|
checks,
|
|
10962
11748
|
config,
|
|
10963
|
-
packages,
|
|
10964
11749
|
problems,
|
|
10965
11750
|
project,
|
|
10966
11751
|
projectsByPath,
|
|
10967
|
-
rules: graphRules
|
|
11752
|
+
rules: graphRules,
|
|
11753
|
+
workspaceLookup
|
|
10968
11754
|
});
|
|
10969
|
-
addWorkspaceReferenceDependencyProblems(config, project, projectsByPath,
|
|
11755
|
+
addWorkspaceReferenceDependencyProblems(config, project, projectsByPath, workspaceLookup, problems, checks);
|
|
10970
11756
|
}
|
|
11757
|
+
addGeneratedReferenceCycleProblems({
|
|
11758
|
+
checks,
|
|
11759
|
+
config,
|
|
11760
|
+
problems,
|
|
11761
|
+
projects
|
|
11762
|
+
});
|
|
10971
11763
|
checkItems.record("project references");
|
|
10972
11764
|
checkItems.start("condition domains");
|
|
10973
11765
|
addDefaultCustomConditionProblems({
|
|
@@ -10996,13 +11788,13 @@ async function runGraphCheckImpl(config, options = {}) {
|
|
|
10996
11788
|
generatedGraph,
|
|
10997
11789
|
graphRules,
|
|
10998
11790
|
importAnalysis: preflight.importAnalysis,
|
|
10999
|
-
importers,
|
|
11000
11791
|
packages,
|
|
11001
11792
|
problems,
|
|
11002
11793
|
projectPaths,
|
|
11003
11794
|
projects,
|
|
11004
11795
|
projectsByPath,
|
|
11005
|
-
workspaceExports
|
|
11796
|
+
workspaceExports,
|
|
11797
|
+
workspaceLookup
|
|
11006
11798
|
}),
|
|
11007
11799
|
generatedGraph,
|
|
11008
11800
|
graphRules,
|
|
@@ -12474,7 +13266,7 @@ var dist_exports = /* @__PURE__ */ __exportAll({
|
|
|
12474
13266
|
updateSettings: () => j$1
|
|
12475
13267
|
});
|
|
12476
13268
|
function ee() {
|
|
12477
|
-
return
|
|
13269
|
+
return process$1.platform !== "win32" ? process$1.env.TERM !== "linux" : !!process$1.env.CI || !!process$1.env.WT_SESSION || !!process$1.env.TERMINUS_SUBLIME || process$1.env.ConEmuTask === "{cmd::Cmder}" || process$1.env.TERM_PROGRAM === "Terminus-Sublime" || process$1.env.TERM_PROGRAM === "vscode" || process$1.env.TERM === "xterm-256color" || process$1.env.TERM === "alacritty" || process$1.env.TERMINAL_EMULATOR === "JetBrains-JediTerm";
|
|
12478
13270
|
}
|
|
12479
13271
|
const tt$1 = ee(), ot = () => process.env.CI === "true", It = (t) => t.isTTY === !0, w$1 = (t, i) => tt$1 ? t : i, Tt = w$1("◆", "*"), at = w$1("■", "x"), ut = w$1("▲", "x"), H = w$1("◇", "o"), lt = w$1("┌", "T"), $ = w$1("│", "|"), x = w$1("└", "—"), _t = w$1("┐", "T"), xt = w$1("┘", "—"), z$1 = w$1("●", ">"), U = w$1("○", " "), et$1 = w$1("◻", "[•]"), K = w$1("◼", "[+]"), Y = w$1("◻", "[ ]"), Et = w$1("▪", "•"), st = w$1("─", "-"), ct = w$1("╮", "+"), Gt = w$1("├", "+"), $t = w$1("╯", "+"), dt = w$1("╰", "+"), Mt = w$1("╭", "+"), ht = w$1("●", "•"), pt = w$1("◆", "*"), mt = w$1("▲", "!"), gt = w$1("■", "x"), P = (t) => {
|
|
12480
13272
|
switch (t) {
|
|
@@ -13088,7 +13880,7 @@ ${r ? styleText("cyan", x) : ""}
|
|
|
13088
13880
|
`), n = u.reduce((o, l) => Math.max(fastStringWidth(l), o), 0);
|
|
13089
13881
|
return wrapAnsi(t, i - (u.map(s).reduce((o, l) => Math.max(fastStringWidth(l), o), 0) - n), r);
|
|
13090
13882
|
}, Se = (t = "", i = "", s) => {
|
|
13091
|
-
const r = s?.output ??
|
|
13883
|
+
const r = s?.output ?? process$1.stdout, u = s?.withGuide ?? h.withGuide, n = s?.format ?? we$1, a = [
|
|
13092
13884
|
"",
|
|
13093
13885
|
...be$1(t, A$1(r) - 6, n).split(`
|
|
13094
13886
|
`).map(n),
|
|
@@ -44249,8 +45041,8 @@ function collectSourceKnipWorkspaceConfigs(options) {
|
|
|
44249
45041
|
if (Object.hasOwn(rawWorkspaceConfig, "tsConfig")) options.problems.push([
|
|
44250
45042
|
"Unsupported source Knip workspace config:",
|
|
44251
45043
|
` field: ${field}.tsConfig`,
|
|
44252
|
-
" reason: tsConfig is no longer supported. Limina uses Knip default tsconfig behavior unless a package has a static limina
|
|
44253
|
-
" fix: remove tsConfig, or add a static package script such as \"build\": \"limina
|
|
45044
|
+
" reason: tsConfig is no longer supported. Limina uses Knip default tsconfig behavior unless a package has a static limina build script.",
|
|
45045
|
+
" fix: remove tsConfig, or add a static package script such as \"build\": \"limina build tsconfig.json\" when this package needs a specific Knip tsconfig source."
|
|
44254
45046
|
].join("\n"));
|
|
44255
45047
|
workspaceConfigs.set(packageName, rawWorkspaceConfig);
|
|
44256
45048
|
}
|
|
@@ -45401,7 +46193,7 @@ function addProjectOwnerProblems(options) {
|
|
|
45401
46193
|
const missingOwnerFiles = [];
|
|
45402
46194
|
for (const fileName of options.fileNames) {
|
|
45403
46195
|
options.checks.add();
|
|
45404
|
-
const owner = findOwnerForFile(fileName
|
|
46196
|
+
const owner = options.workspaceLookup.findOwnerForFile(fileName);
|
|
45405
46197
|
if (!owner) {
|
|
45406
46198
|
missingOwnerFiles.push(fileName);
|
|
45407
46199
|
continue;
|
|
@@ -45617,14 +46409,79 @@ function addPackageImportOtherOwnerProblem(options) {
|
|
|
45617
46409
|
" reason: #... package imports must not resolve to modules governed by another source owner."
|
|
45618
46410
|
].join("\n"));
|
|
45619
46411
|
}
|
|
46412
|
+
function addPackageImportRelativeScopeProblem(options) {
|
|
46413
|
+
options.problems.push([
|
|
46414
|
+
"Package import relative target escapes package scope:",
|
|
46415
|
+
` source owner: ${toRelativePath(options.config.rootDir, options.owner.packageJsonPath)}`,
|
|
46416
|
+
` package scope: ${toRelativePath(options.config.rootDir, options.packageScope.packageJsonPath)}`,
|
|
46417
|
+
` file: ${formatImportRecordLocation(options.config.rootDir, options.importRecord)}`,
|
|
46418
|
+
` imported specifier: ${options.importRecord.specifier}`,
|
|
46419
|
+
` resolved file: ${toRelativePath(options.config.rootDir, options.resolvedFilePath)}`,
|
|
46420
|
+
...options.targetPackageScope ? [` target package scope: ${toRelativePath(options.config.rootDir, options.targetPackageScope.packageJsonPath)}`] : [],
|
|
46421
|
+
" reason: #... package imports with relative targets must stay inside the declaring package scope."
|
|
46422
|
+
].join("\n"));
|
|
46423
|
+
}
|
|
46424
|
+
function isResolvedInsidePackageScope(options) {
|
|
46425
|
+
return options.workspaceLookup.findNearestPackageScopeInfo(options.resolvedFilePath)?.packageJsonPath === options.packageScope.packageJsonPath;
|
|
46426
|
+
}
|
|
46427
|
+
function addPackageImportArtifactAuthorizationProblem(options) {
|
|
46428
|
+
if (!options.packageInfo.name) {
|
|
46429
|
+
addResolvedPackageWithoutNameProblem({
|
|
46430
|
+
config: options.config,
|
|
46431
|
+
importRecord: options.importRecord,
|
|
46432
|
+
owner: options.owner,
|
|
46433
|
+
packageInfo: options.packageInfo,
|
|
46434
|
+
problems: options.problems
|
|
46435
|
+
});
|
|
46436
|
+
return;
|
|
46437
|
+
}
|
|
46438
|
+
const packageName = getPackageNameForAuthorization({
|
|
46439
|
+
importRecord: options.importRecord,
|
|
46440
|
+
resolvedPackageName: options.packageInfo.name
|
|
46441
|
+
});
|
|
46442
|
+
if (isDependencyAuthorizedBySourceAuthority({
|
|
46443
|
+
config: options.config,
|
|
46444
|
+
importAuthorityAllowRules: options.importAuthorityAllowRules,
|
|
46445
|
+
importRecord: options.importRecord,
|
|
46446
|
+
owner: options.owner,
|
|
46447
|
+
packageName,
|
|
46448
|
+
rootPackage: options.rootPackage
|
|
46449
|
+
})) return;
|
|
46450
|
+
addPackageImportAuthorizationProblem({
|
|
46451
|
+
authorityManifestPaths: getDependencyAuthorityManifestPaths({
|
|
46452
|
+
config: options.config,
|
|
46453
|
+
importAuthorityAllowRules: options.importAuthorityAllowRules,
|
|
46454
|
+
importRecord: options.importRecord,
|
|
46455
|
+
owner: options.owner,
|
|
46456
|
+
packageName,
|
|
46457
|
+
rootPackage: options.rootPackage
|
|
46458
|
+
}),
|
|
46459
|
+
config: options.config,
|
|
46460
|
+
...packageName === options.packageInfo.name ? {} : { dependencySpecifier: options.packageInfo.name },
|
|
46461
|
+
importRecord: options.importRecord,
|
|
46462
|
+
owner: options.owner,
|
|
46463
|
+
packageName,
|
|
46464
|
+
problems: options.problems,
|
|
46465
|
+
workspacePackage: options.workspacePackage
|
|
46466
|
+
});
|
|
46467
|
+
}
|
|
46468
|
+
function shouldTreatPackageImportAsRelativeTarget(match) {
|
|
46469
|
+
return match.targetKind === "relative";
|
|
46470
|
+
}
|
|
46471
|
+
function shouldTreatPackageImportAsPackageTarget(match) {
|
|
46472
|
+
return match.targetKind === "package" || match.targetKind === "mixed";
|
|
46473
|
+
}
|
|
45620
46474
|
function addPackageImportProblem(options) {
|
|
45621
|
-
|
|
46475
|
+
const packageScope = options.workspaceLookup.findNearestPackageScopeInfo(options.importRecord.filePath);
|
|
46476
|
+
const match = findPackageImportMatch(packageScope?.manifest.imports, options.importRecord.specifier);
|
|
46477
|
+
if (!match) {
|
|
45622
46478
|
options.problems.push([
|
|
45623
46479
|
"Unauthorized package import specifier:",
|
|
45624
46480
|
` source owner: ${toRelativePath(options.config.rootDir, options.owner.packageJsonPath)}`,
|
|
46481
|
+
...packageScope ? [` package scope: ${toRelativePath(options.config.rootDir, packageScope.packageJsonPath)}`] : [],
|
|
45625
46482
|
` file: ${formatImportRecordLocation(options.config.rootDir, options.importRecord)}`,
|
|
45626
46483
|
` imported specifier: ${options.importRecord.specifier}`,
|
|
45627
|
-
" reason: #... package imports must match the
|
|
46484
|
+
" reason: #... package imports must match the nearest package scope package.json imports field."
|
|
45628
46485
|
].join("\n"));
|
|
45629
46486
|
return;
|
|
45630
46487
|
}
|
|
@@ -45632,68 +46489,82 @@ function addPackageImportProblem(options) {
|
|
|
45632
46489
|
options.problems.push([
|
|
45633
46490
|
"Unresolved package import specifier:",
|
|
45634
46491
|
` source owner: ${toRelativePath(options.config.rootDir, options.owner.packageJsonPath)}`,
|
|
46492
|
+
...packageScope ? [` package scope: ${toRelativePath(options.config.rootDir, packageScope.packageJsonPath)}`] : [],
|
|
45635
46493
|
` file: ${formatImportRecordLocation(options.config.rootDir, options.importRecord)}`,
|
|
45636
46494
|
` imported specifier: ${options.importRecord.specifier}`,
|
|
45637
|
-
" reason: matched #... package imports must resolve
|
|
46495
|
+
" reason: matched #... package imports must resolve from the nearest package scope package.json imports field."
|
|
45638
46496
|
].join("\n"));
|
|
45639
46497
|
return;
|
|
45640
46498
|
}
|
|
45641
|
-
|
|
46499
|
+
if (packageScope && shouldTreatPackageImportAsRelativeTarget(match) && !isResolvedInsidePackageScope({
|
|
46500
|
+
packageScope,
|
|
46501
|
+
resolvedFilePath: options.resolvedFilePath,
|
|
46502
|
+
workspaceLookup: options.workspaceLookup
|
|
46503
|
+
})) {
|
|
46504
|
+
addPackageImportRelativeScopeProblem({
|
|
46505
|
+
config: options.config,
|
|
46506
|
+
importRecord: options.importRecord,
|
|
46507
|
+
owner: options.owner,
|
|
46508
|
+
packageScope,
|
|
46509
|
+
problems: options.problems,
|
|
46510
|
+
resolvedFilePath: options.resolvedFilePath,
|
|
46511
|
+
targetPackageScope: options.workspaceLookup.findNearestPackageScopeInfo(options.resolvedFilePath)
|
|
46512
|
+
});
|
|
46513
|
+
return;
|
|
46514
|
+
}
|
|
46515
|
+
const target = options.workspaceLookup.classifyResolvedPackageTarget({
|
|
45642
46516
|
owner: options.owner,
|
|
45643
|
-
owners: options.owners,
|
|
45644
|
-
packages: options.packages,
|
|
45645
46517
|
resolvedFilePath: options.resolvedFilePath
|
|
45646
46518
|
});
|
|
45647
|
-
if (target.kind === "current-owner")
|
|
45648
|
-
|
|
45649
|
-
|
|
46519
|
+
if (target.kind === "current-owner") {
|
|
46520
|
+
if (packageScope && !shouldTreatPackageImportAsPackageTarget(match) && !isResolvedInsidePackageScope({
|
|
46521
|
+
packageScope,
|
|
46522
|
+
resolvedFilePath: options.resolvedFilePath,
|
|
46523
|
+
workspaceLookup: options.workspaceLookup
|
|
46524
|
+
})) addPackageImportRelativeScopeProblem({
|
|
45650
46525
|
config: options.config,
|
|
45651
46526
|
importRecord: options.importRecord,
|
|
45652
46527
|
owner: options.owner,
|
|
46528
|
+
packageScope,
|
|
45653
46529
|
problems: options.problems,
|
|
45654
|
-
|
|
45655
|
-
|
|
46530
|
+
resolvedFilePath: options.resolvedFilePath,
|
|
46531
|
+
targetPackageScope: options.workspaceLookup.findNearestPackageScopeInfo(options.resolvedFilePath)
|
|
45656
46532
|
});
|
|
45657
46533
|
return;
|
|
45658
46534
|
}
|
|
45659
|
-
if (target.kind === "
|
|
45660
|
-
if (
|
|
45661
|
-
|
|
46535
|
+
if (target.kind === "other-owner") {
|
|
46536
|
+
if (shouldTreatPackageImportAsPackageTarget(match)) {
|
|
46537
|
+
addPackageImportArtifactAuthorizationProblem({
|
|
45662
46538
|
config: options.config,
|
|
46539
|
+
importAuthorityAllowRules: options.importAuthorityAllowRules,
|
|
45663
46540
|
importRecord: options.importRecord,
|
|
45664
46541
|
owner: options.owner,
|
|
45665
46542
|
packageInfo: target.packageInfo,
|
|
45666
|
-
problems: options.problems
|
|
46543
|
+
problems: options.problems,
|
|
46544
|
+
rootPackage: options.rootPackage,
|
|
46545
|
+
workspacePackage: target.workspacePackage
|
|
45667
46546
|
});
|
|
45668
46547
|
return;
|
|
45669
46548
|
}
|
|
45670
|
-
|
|
45671
|
-
importRecord: options.importRecord,
|
|
45672
|
-
resolvedPackageName: target.packageInfo.name
|
|
45673
|
-
});
|
|
45674
|
-
if (isDependencyAuthorizedBySourceAuthority({
|
|
46549
|
+
addPackageImportOtherOwnerProblem({
|
|
45675
46550
|
config: options.config,
|
|
45676
|
-
importAuthorityAllowRules: options.importAuthorityAllowRules,
|
|
45677
46551
|
importRecord: options.importRecord,
|
|
45678
46552
|
owner: options.owner,
|
|
45679
|
-
|
|
45680
|
-
|
|
45681
|
-
|
|
45682
|
-
|
|
45683
|
-
|
|
45684
|
-
|
|
45685
|
-
|
|
45686
|
-
|
|
45687
|
-
owner: options.owner,
|
|
45688
|
-
packageName,
|
|
45689
|
-
rootPackage: options.rootPackage
|
|
45690
|
-
}),
|
|
46553
|
+
problems: options.problems,
|
|
46554
|
+
targetOwner: target.targetOwner,
|
|
46555
|
+
workspacePackage: target.workspacePackage
|
|
46556
|
+
});
|
|
46557
|
+
return;
|
|
46558
|
+
}
|
|
46559
|
+
if (target.kind === "artifact-package") {
|
|
46560
|
+
addPackageImportArtifactAuthorizationProblem({
|
|
45691
46561
|
config: options.config,
|
|
45692
|
-
|
|
46562
|
+
importAuthorityAllowRules: options.importAuthorityAllowRules,
|
|
45693
46563
|
importRecord: options.importRecord,
|
|
45694
46564
|
owner: options.owner,
|
|
45695
|
-
|
|
46565
|
+
packageInfo: target.packageInfo,
|
|
45696
46566
|
problems: options.problems,
|
|
46567
|
+
rootPackage: options.rootPackage,
|
|
45697
46568
|
workspacePackage: null
|
|
45698
46569
|
});
|
|
45699
46570
|
return;
|
|
@@ -45831,7 +46702,7 @@ async function addTsconfigGovernanceProblems(options) {
|
|
|
45831
46702
|
for (const configPath of configPaths) {
|
|
45832
46703
|
if (shouldSkipGovernedTsconfig(readJsonConfig(options.config, configPath))) continue;
|
|
45833
46704
|
options.checks.add();
|
|
45834
|
-
const owner = findOwnerForFile(configPath
|
|
46705
|
+
const owner = options.workspaceLookup.findOwnerForFile(configPath);
|
|
45835
46706
|
if (!owner) {
|
|
45836
46707
|
options.problems.push([
|
|
45837
46708
|
"Tsconfig has no source owner:",
|
|
@@ -45845,7 +46716,7 @@ async function addTsconfigGovernanceProblems(options) {
|
|
|
45845
46716
|
projectFileSetsByConfigPath.set(configPath, new Set(project.fileNames));
|
|
45846
46717
|
for (const fileName of project.fileNames) {
|
|
45847
46718
|
options.checks.add();
|
|
45848
|
-
const fileOwner = findOwnerForFile(fileName
|
|
46719
|
+
const fileOwner = options.workspaceLookup.findOwnerForFile(fileName);
|
|
45849
46720
|
if (fileOwner?.packageJsonPath !== owner.packageJsonPath) options.problems.push([
|
|
45850
46721
|
"Tsconfig source file set crosses source owner scope:",
|
|
45851
46722
|
` config: ${toRelativePath(options.config.rootDir, configPath)}`,
|
|
@@ -46057,9 +46928,9 @@ async function addSourceProjectOwnerProblems(options) {
|
|
|
46057
46928
|
config: options.config,
|
|
46058
46929
|
configPath: project.configPath,
|
|
46059
46930
|
fileNames: project.fileNames,
|
|
46060
|
-
owners: options.owners,
|
|
46061
46931
|
problems: options.problems,
|
|
46062
|
-
role: "declaration leaf"
|
|
46932
|
+
role: "declaration leaf",
|
|
46933
|
+
workspaceLookup: options.workspaceLookup
|
|
46063
46934
|
});
|
|
46064
46935
|
const typecheckConfigPath = getTypecheckConfigPath(project.configPath);
|
|
46065
46936
|
if (!existsSync(typecheckConfigPath)) continue;
|
|
@@ -46068,16 +46939,16 @@ async function addSourceProjectOwnerProblems(options) {
|
|
|
46068
46939
|
config: options.config,
|
|
46069
46940
|
configPath: typecheckConfigPath,
|
|
46070
46941
|
fileNames: (await options.core.tsconfig.getProject(typecheckConfigPath, project)).fileNames,
|
|
46071
|
-
owners: options.owners,
|
|
46072
46942
|
problems: options.problems,
|
|
46073
|
-
role: "typecheck companion"
|
|
46943
|
+
role: "typecheck companion",
|
|
46944
|
+
workspaceLookup: options.workspaceLookup
|
|
46074
46945
|
});
|
|
46075
46946
|
}
|
|
46076
46947
|
}
|
|
46077
46948
|
function addRelativeImportProblems(options) {
|
|
46078
46949
|
if (!options.resolvedFilePath) return;
|
|
46079
|
-
const sourcePackageScope = findNearestPackageScopeInfo(options.filePath);
|
|
46080
|
-
const targetPackageScope = findNearestPackageScopeInfo(options.resolvedFilePath);
|
|
46950
|
+
const sourcePackageScope = options.workspaceLookup.findNearestPackageScopeInfo(options.filePath);
|
|
46951
|
+
const targetPackageScope = options.workspaceLookup.findNearestPackageScopeInfo(options.resolvedFilePath);
|
|
46081
46952
|
if (sourcePackageScope?.packageJsonPath === targetPackageScope?.packageJsonPath) return;
|
|
46082
46953
|
addRelativeImportOwnerProblem({
|
|
46083
46954
|
config: options.config,
|
|
@@ -46176,10 +47047,8 @@ function addResolvedArtifactBarePackageProblems(options) {
|
|
|
46176
47047
|
});
|
|
46177
47048
|
}
|
|
46178
47049
|
function addResolvedBarePackageImportProblems(options) {
|
|
46179
|
-
const target = classifyResolvedPackageTarget({
|
|
47050
|
+
const target = options.workspaceLookup.classifyResolvedPackageTarget({
|
|
46180
47051
|
owner: options.owner,
|
|
46181
|
-
owners: options.owners,
|
|
46182
|
-
packages: options.packages,
|
|
46183
47052
|
resolvedFilePath: options.resolvedFilePath
|
|
46184
47053
|
});
|
|
46185
47054
|
if (target.kind === "current-owner") return true;
|
|
@@ -46216,11 +47085,10 @@ function addBarePackageImportProblems(options) {
|
|
|
46216
47085
|
importAuthorityAllowRules: options.importAuthorityAllowRules,
|
|
46217
47086
|
importRecord: options.importRecord,
|
|
46218
47087
|
owner: options.owner,
|
|
46219
|
-
owners: options.owners,
|
|
46220
|
-
packages: options.packages,
|
|
46221
47088
|
problems: options.problems,
|
|
46222
47089
|
resolvedFilePath: options.resolvedFilePath,
|
|
46223
|
-
rootPackage: options.rootPackage
|
|
47090
|
+
rootPackage: options.rootPackage,
|
|
47091
|
+
workspaceLookup: options.workspaceLookup
|
|
46224
47092
|
})) return;
|
|
46225
47093
|
const workspacePackage = options.packages.find((candidate) => candidate.name === options.fallbackPackageName) ?? null;
|
|
46226
47094
|
if (isDependencyAuthorizedBySourceAuthority({
|
|
@@ -46257,7 +47125,8 @@ function addImportRecordProblems(options) {
|
|
|
46257
47125
|
importRecord: options.importRecord,
|
|
46258
47126
|
owner: options.owner,
|
|
46259
47127
|
problems: options.problems,
|
|
46260
|
-
resolvedFilePath
|
|
47128
|
+
resolvedFilePath,
|
|
47129
|
+
workspaceLookup: options.workspaceLookup
|
|
46261
47130
|
});
|
|
46262
47131
|
return;
|
|
46263
47132
|
}
|
|
@@ -46266,12 +47135,11 @@ function addImportRecordProblems(options) {
|
|
|
46266
47135
|
config: options.config,
|
|
46267
47136
|
importRecord: options.importRecord,
|
|
46268
47137
|
owner: options.owner,
|
|
46269
|
-
owners: options.owners,
|
|
46270
|
-
packages: options.packages,
|
|
46271
47138
|
problems: options.problems,
|
|
46272
47139
|
resolvedFilePath,
|
|
46273
47140
|
importAuthorityAllowRules: options.importAuthorityAllowRules,
|
|
46274
|
-
rootPackage: options.rootPackage
|
|
47141
|
+
rootPackage: options.rootPackage,
|
|
47142
|
+
workspaceLookup: options.workspaceLookup
|
|
46275
47143
|
});
|
|
46276
47144
|
return;
|
|
46277
47145
|
}
|
|
@@ -46282,16 +47150,16 @@ function addImportRecordProblems(options) {
|
|
|
46282
47150
|
importAuthorityAllowRules: options.importAuthorityAllowRules,
|
|
46283
47151
|
importRecord: options.importRecord,
|
|
46284
47152
|
owner: options.owner,
|
|
46285
|
-
owners: options.owners,
|
|
46286
47153
|
packages: options.packages,
|
|
46287
47154
|
problems: options.problems,
|
|
46288
47155
|
resolvedFilePath,
|
|
46289
|
-
rootPackage: options.rootPackage
|
|
47156
|
+
rootPackage: options.rootPackage,
|
|
47157
|
+
workspaceLookup: options.workspaceLookup
|
|
46290
47158
|
});
|
|
46291
47159
|
}
|
|
46292
47160
|
function addSourceImportProblems(options) {
|
|
46293
47161
|
for (const { fileNames, project } of options.sourceProjectEntries) for (const filePath of fileNames) {
|
|
46294
|
-
const owner = findOwnerForFile(filePath
|
|
47162
|
+
const owner = options.workspaceLookup.findOwnerForFile(filePath);
|
|
46295
47163
|
if (!owner) continue;
|
|
46296
47164
|
for (const importRecord of collectImportsFromFile(filePath, options.config.rootDir, options.importAnalysis)) {
|
|
46297
47165
|
options.checks.add();
|
|
@@ -46302,11 +47170,11 @@ function addSourceImportProblems(options) {
|
|
|
46302
47170
|
importAuthorityAllowRules: options.importAuthorityAllowRules,
|
|
46303
47171
|
importRecord,
|
|
46304
47172
|
owner,
|
|
46305
|
-
owners: options.owners,
|
|
46306
47173
|
packages: options.packages,
|
|
46307
47174
|
problems: options.problems,
|
|
46308
47175
|
project,
|
|
46309
|
-
rootPackage: options.rootPackage
|
|
47176
|
+
rootPackage: options.rootPackage,
|
|
47177
|
+
workspaceLookup: options.workspaceLookup
|
|
46310
47178
|
});
|
|
46311
47179
|
}
|
|
46312
47180
|
}
|
|
@@ -46404,6 +47272,7 @@ async function runSourceCheckImpl(config, options = {}) {
|
|
|
46404
47272
|
const sourceProjectEntries = await createSourceProjectEntries(core, projects);
|
|
46405
47273
|
const packages = await preflight.ensureWorkspacePackages();
|
|
46406
47274
|
const packageOwners = await preflight.ensurePackageOwners();
|
|
47275
|
+
const workspaceLookup = await preflight.ensureWorkspaceLookupIndex();
|
|
46407
47276
|
const workspaceDependencyDeclarations = await preflight.ensureWorkspaceDependencyDeclarations();
|
|
46408
47277
|
const rootPackage = findWorkspaceRootPackage({
|
|
46409
47278
|
config,
|
|
@@ -46424,8 +47293,8 @@ async function runSourceCheckImpl(config, options = {}) {
|
|
|
46424
47293
|
config,
|
|
46425
47294
|
configPaths: collectGeneratedSourceConfigPaths(generatedGraph),
|
|
46426
47295
|
generatedGraph,
|
|
46427
|
-
|
|
46428
|
-
|
|
47296
|
+
problems,
|
|
47297
|
+
workspaceLookup
|
|
46429
47298
|
});
|
|
46430
47299
|
checkItems.record("tsconfig governance");
|
|
46431
47300
|
checkItems.start("knip source usage");
|
|
@@ -46446,9 +47315,9 @@ async function runSourceCheckImpl(config, options = {}) {
|
|
|
46446
47315
|
checks,
|
|
46447
47316
|
config,
|
|
46448
47317
|
core,
|
|
46449
|
-
owners: packageOwners,
|
|
46450
47318
|
problems,
|
|
46451
|
-
projects
|
|
47319
|
+
projects,
|
|
47320
|
+
workspaceLookup
|
|
46452
47321
|
});
|
|
46453
47322
|
checkItems.record("source project ownership");
|
|
46454
47323
|
checkItems.start("source import authority");
|
|
@@ -46468,11 +47337,11 @@ async function runSourceCheckImpl(config, options = {}) {
|
|
|
46468
47337
|
config,
|
|
46469
47338
|
importAnalysis,
|
|
46470
47339
|
importAuthorityAllowRules,
|
|
46471
|
-
owners: packageOwners,
|
|
46472
47340
|
packages,
|
|
46473
47341
|
problems,
|
|
46474
47342
|
rootPackage,
|
|
46475
|
-
sourceProjectEntries
|
|
47343
|
+
sourceProjectEntries,
|
|
47344
|
+
workspaceLookup
|
|
46476
47345
|
});
|
|
46477
47346
|
checkItems.record("source import authority");
|
|
46478
47347
|
const ownerNamesByManifestPath = createSourceProblemOwnerLookup(packageOwners);
|
|
@@ -46939,6 +47808,135 @@ async function runCheckerBuildImpl(options) {
|
|
|
46939
47808
|
});
|
|
46940
47809
|
const flowDepth = options.flowDepth ?? 0;
|
|
46941
47810
|
const rootConfigPaths = [];
|
|
47811
|
+
if (options.configPath) {
|
|
47812
|
+
const sourceConfigPath = resolveBuildConfigPath({
|
|
47813
|
+
configPath: options.configPath,
|
|
47814
|
+
cwd,
|
|
47815
|
+
rootDir: projectRootDir
|
|
47816
|
+
});
|
|
47817
|
+
const managedTargets = collectManagedDeclarationBuildTargets({
|
|
47818
|
+
allCheckers,
|
|
47819
|
+
generatedGraph,
|
|
47820
|
+
sourceConfigPath
|
|
47821
|
+
});
|
|
47822
|
+
const buildCapableTargets = managedTargets.filter(({ checker }) => getCheckerAdapter(checker.preset)?.execution === "build");
|
|
47823
|
+
const availableCheckers = uniqueSortedStrings(buildCapableTargets.map(({ checker }) => checker.preset));
|
|
47824
|
+
const checkerTargets = options.checker ? buildCapableTargets.filter(({ checker }) => checker.preset === options.checker) : buildCapableTargets;
|
|
47825
|
+
if (checkerTargets.length === 0) {
|
|
47826
|
+
const selectionProblem = options.checker ? formatManagedBuildCheckerSelectionProblem({
|
|
47827
|
+
availableCheckers,
|
|
47828
|
+
projectRootDir,
|
|
47829
|
+
selectedChecker: options.checker,
|
|
47830
|
+
sourceConfigPath
|
|
47831
|
+
}) : managedTargets.length > 0 ? formatTypecheckOnlyBuildProblem({
|
|
47832
|
+
checkers: managedTargets.map(({ checker }) => checker),
|
|
47833
|
+
projectRootDir,
|
|
47834
|
+
sourceConfigPath
|
|
47835
|
+
}) : [
|
|
47836
|
+
"Unmanaged Limina checker build config:",
|
|
47837
|
+
` config: ${toRelativePath(projectRootDir, sourceConfigPath)}`,
|
|
47838
|
+
" reason: limina checker build <config> only accepts source configs managed by Limina checker.include.",
|
|
47839
|
+
" fix: add the owning tsconfig.json entry to checker.include, or use limina build <config> --raw --preset <checker> for a direct raw build."
|
|
47840
|
+
].join("\n");
|
|
47841
|
+
if (shouldLogCheckReport(options.report)) TypecheckLogger.error(formatTypecheckProblemSummaryReport({
|
|
47842
|
+
pluralIssueLabel: "checker build selection issues",
|
|
47843
|
+
problems: [selectionProblem],
|
|
47844
|
+
singularIssueLabel: "checker build selection issue",
|
|
47845
|
+
title: "Checker build summary"
|
|
47846
|
+
}));
|
|
47847
|
+
return {
|
|
47848
|
+
failedTargets: [],
|
|
47849
|
+
failureKind: "target-selection",
|
|
47850
|
+
passed: false,
|
|
47851
|
+
problems: [selectionProblem],
|
|
47852
|
+
projectRootDir,
|
|
47853
|
+
rootConfigPaths,
|
|
47854
|
+
targetResults: []
|
|
47855
|
+
};
|
|
47856
|
+
}
|
|
47857
|
+
const problems = collectCheckerPeerDependencyProblems({
|
|
47858
|
+
checkers: checkerTargets.map(({ checker }) => checker),
|
|
47859
|
+
imports: options.config.config?.imports,
|
|
47860
|
+
projectRootDir,
|
|
47861
|
+
resolvePackage: options.checkerPackageResolver
|
|
47862
|
+
});
|
|
47863
|
+
if (problems.length > 0) {
|
|
47864
|
+
if (shouldLogCheckReport(options.report)) TypecheckLogger.error(formatTypecheckProblemSummaryReport({
|
|
47865
|
+
pluralIssueLabel: "checker build issues",
|
|
47866
|
+
problems,
|
|
47867
|
+
singularIssueLabel: "checker build issue",
|
|
47868
|
+
title: "Checker build summary"
|
|
47869
|
+
}));
|
|
47870
|
+
return {
|
|
47871
|
+
failedTargets: [],
|
|
47872
|
+
failureKind: "peer-dependency",
|
|
47873
|
+
passed: false,
|
|
47874
|
+
problems,
|
|
47875
|
+
projectRootDir,
|
|
47876
|
+
rootConfigPaths,
|
|
47877
|
+
targetResults: []
|
|
47878
|
+
};
|
|
47879
|
+
}
|
|
47880
|
+
const targets = checkerTargets.map(({ buildModule, checker, sourceConfigPath }) => {
|
|
47881
|
+
rootConfigPaths.push(buildModule.path);
|
|
47882
|
+
return {
|
|
47883
|
+
...createCheckerTarget({
|
|
47884
|
+
checker,
|
|
47885
|
+
commandOverride: options.tscCommand,
|
|
47886
|
+
configPath: buildModule.path,
|
|
47887
|
+
executionKind: "build",
|
|
47888
|
+
projectRootDir,
|
|
47889
|
+
watch: options.watch
|
|
47890
|
+
}),
|
|
47891
|
+
sourceConfigPath
|
|
47892
|
+
};
|
|
47893
|
+
});
|
|
47894
|
+
options.flow?.info(`found ${targets.length} checker build target(s)`, { depth: flowDepth + 1 });
|
|
47895
|
+
const targetTasks = new Map(createPlannedCheckerTargetTasks(targets, options.progress, "checker build", projectRootDir));
|
|
47896
|
+
const results = await runBuildTargets(targets, generatedGraph.providerEdges, resolveTypecheckRunner(options), {
|
|
47897
|
+
config: options.config,
|
|
47898
|
+
onTargetResult: (target, result) => {
|
|
47899
|
+
const task = targetTasks.get(target.configPath);
|
|
47900
|
+
if (!task) return;
|
|
47901
|
+
if (result.status === 0) task.pass();
|
|
47902
|
+
else {
|
|
47903
|
+
const suffix = result.error ? formatErrorMessage(result.error) : `exited with code ${result.status}`;
|
|
47904
|
+
task.fail(void 0, { error: suffix });
|
|
47905
|
+
}
|
|
47906
|
+
},
|
|
47907
|
+
onTargetStart: (target) => {
|
|
47908
|
+
if (options.progress) {
|
|
47909
|
+
targetTasks.get(target.configPath)?.start();
|
|
47910
|
+
return;
|
|
47911
|
+
}
|
|
47912
|
+
if (!options.flow) return;
|
|
47913
|
+
targetTasks.set(target.configPath, options.flow.start(getCheckerTargetFlowLabel(target, "checker build", projectRootDir), {
|
|
47914
|
+
collapseOnSuccess: false,
|
|
47915
|
+
depth: flowDepth + 1
|
|
47916
|
+
}));
|
|
47917
|
+
},
|
|
47918
|
+
watch: options.watch
|
|
47919
|
+
});
|
|
47920
|
+
const failedResults = results.filter((result) => result.status !== 0);
|
|
47921
|
+
const failedTargets = collectFailedCheckerTargets(targets, failedResults);
|
|
47922
|
+
const passed = failedResults.length === 0;
|
|
47923
|
+
if (!passed && shouldLogCheckReport(options.report)) TypecheckLogger.error(formatFailedTargetSummaryReport({
|
|
47924
|
+
failedResults,
|
|
47925
|
+
heading: "build checks failed:",
|
|
47926
|
+
pluralIssueLabel: "failed checker build targets",
|
|
47927
|
+
projectRootDir,
|
|
47928
|
+
singularIssueLabel: "failed checker build target",
|
|
47929
|
+
title: "Checker build summary"
|
|
47930
|
+
}));
|
|
47931
|
+
else if (passed && shouldLogCheckReport(options.report) && !options.flow?.interactive) TypecheckLogger.success(`Checked ${targets.length} checker build target(s).`);
|
|
47932
|
+
return {
|
|
47933
|
+
failedTargets,
|
|
47934
|
+
passed,
|
|
47935
|
+
projectRootDir,
|
|
47936
|
+
rootConfigPaths,
|
|
47937
|
+
targetResults: results
|
|
47938
|
+
};
|
|
47939
|
+
}
|
|
46942
47940
|
const problems = collectCheckerPeerDependencyProblems({
|
|
46943
47941
|
checkers: allCheckers,
|
|
46944
47942
|
imports: options.config.config?.imports,
|
|
@@ -47116,13 +48114,49 @@ function formatTypecheckOnlyBuildProblem(options) {
|
|
|
47116
48114
|
}
|
|
47117
48115
|
function formatManagedBuildCheckerSelectionProblem(options) {
|
|
47118
48116
|
return [
|
|
47119
|
-
|
|
48117
|
+
`Invalid Limina ${options.commandLabel ?? "checker build"} preset:`,
|
|
47120
48118
|
` config: ${toRelativePath(options.projectRootDir, options.sourceConfigPath)}`,
|
|
47121
48119
|
` preset: ${options.selectedChecker}`,
|
|
47122
48120
|
" reason: --preset must select a build-capable checker preset that reaches this Limina-managed target.",
|
|
47123
48121
|
...options.availableCheckers.length > 0 ? [" available presets:", ...options.availableCheckers.map((checker) => ` - ${checker}`)] : [" available presets: none"]
|
|
47124
48122
|
].join("\n");
|
|
47125
48123
|
}
|
|
48124
|
+
function formatMultipleOutputBuildPresetProblem(options) {
|
|
48125
|
+
return [
|
|
48126
|
+
"Ambiguous Limina output build preset:",
|
|
48127
|
+
` config: ${toRelativePath(options.projectRootDir, options.sourceConfigPath)}`,
|
|
48128
|
+
" reason: multiple build-capable checker presets can produce output artifacts for this config.",
|
|
48129
|
+
" fix: pass --preset with one of the available presets.",
|
|
48130
|
+
" available presets:",
|
|
48131
|
+
...options.availableCheckers.map((checker) => ` - ${checker}`)
|
|
48132
|
+
].join("\n");
|
|
48133
|
+
}
|
|
48134
|
+
function formatOutputBuildTargetResolutionProblem(options) {
|
|
48135
|
+
const configLine = ` config: ${toRelativePath(options.projectRootDir, options.sourceConfigPath)}`;
|
|
48136
|
+
if (options.resolutionKind === "unmanaged") return [
|
|
48137
|
+
"Unmanaged Limina output build config:",
|
|
48138
|
+
configLine,
|
|
48139
|
+
" reason: limina build <config> only accepts source configs managed by Limina checker.include.",
|
|
48140
|
+
" fix: add the owning tsconfig.json entry to a build-capable checker include, or use limina build <config> --raw --preset <checker> for a direct raw build."
|
|
48141
|
+
].join("\n");
|
|
48142
|
+
if (options.resolutionKind === "outputless-solution") return [
|
|
48143
|
+
"No output-enabled source configs were found under this solution config.",
|
|
48144
|
+
configLine,
|
|
48145
|
+
" reason: the solution is Limina-managed, but none of its recursive referenced source leaves declare liminaOptions.outputs.",
|
|
48146
|
+
" fix: Add liminaOptions.outputs to at least one referenced source leaf."
|
|
48147
|
+
].join("\n");
|
|
48148
|
+
if (options.resolutionKind === "outputless-project") return [
|
|
48149
|
+
"Missing Limina output build options:",
|
|
48150
|
+
configLine,
|
|
48151
|
+
" reason: this Limina-managed source config does not declare liminaOptions.outputs.",
|
|
48152
|
+
" fix: add liminaOptions.outputs to this source config, or use limina build <config> --raw --preset <checker> for a direct raw build."
|
|
48153
|
+
].join("\n");
|
|
48154
|
+
return formatTypecheckOnlyBuildProblem({
|
|
48155
|
+
checkers: options.matchingCheckers,
|
|
48156
|
+
projectRootDir: options.projectRootDir,
|
|
48157
|
+
sourceConfigPath: options.sourceConfigPath
|
|
48158
|
+
});
|
|
48159
|
+
}
|
|
47126
48160
|
function getBuildTargetDescriptorKey(descriptor) {
|
|
47127
48161
|
return `${descriptor.checker.name}\0${descriptor.sourceConfigPath}`;
|
|
47128
48162
|
}
|
|
@@ -47138,7 +48172,7 @@ function createRawBuildChecker(options) {
|
|
|
47138
48172
|
preset: options.preset
|
|
47139
48173
|
};
|
|
47140
48174
|
}
|
|
47141
|
-
function
|
|
48175
|
+
function collectManagedDeclarationBuildTargets(options) {
|
|
47142
48176
|
return options.allCheckers.flatMap((checker) => {
|
|
47143
48177
|
const buildModule = options.generatedGraph.sourceToBuild.get(checker.name)?.get(options.sourceConfigPath);
|
|
47144
48178
|
if (!buildModule) return [];
|
|
@@ -47149,6 +48183,17 @@ function collectManagedBuildTargets(options) {
|
|
|
47149
48183
|
}];
|
|
47150
48184
|
});
|
|
47151
48185
|
}
|
|
48186
|
+
function collectManagedOutputBuildTargets(options) {
|
|
48187
|
+
return options.allCheckers.flatMap((checker) => {
|
|
48188
|
+
const buildModule = options.generatedGraph.configToOutputBuild.get(checker.name)?.get(options.sourceConfigPath);
|
|
48189
|
+
if (!buildModule) return [];
|
|
48190
|
+
return [{
|
|
48191
|
+
buildModule,
|
|
48192
|
+
checker,
|
|
48193
|
+
sourceConfigPath: options.sourceConfigPath
|
|
48194
|
+
}];
|
|
48195
|
+
});
|
|
48196
|
+
}
|
|
47152
48197
|
async function resolveBuildTarget(options) {
|
|
47153
48198
|
const projectRootDir = normalizeAbsolutePath(options.config.rootDir);
|
|
47154
48199
|
const targetConfigPath = resolveBuildConfigPath({
|
|
@@ -47157,26 +48202,49 @@ async function resolveBuildTarget(options) {
|
|
|
47157
48202
|
project: options.project,
|
|
47158
48203
|
rootDir: projectRootDir
|
|
47159
48204
|
});
|
|
48205
|
+
if (options.raw) {
|
|
48206
|
+
if (!options.checker) throw new Error([
|
|
48207
|
+
"Invalid raw build invocation:",
|
|
48208
|
+
` config: ${toRelativePath(projectRootDir, targetConfigPath)}`,
|
|
48209
|
+
" reason: limina build --raw requires --preset."
|
|
48210
|
+
].join("\n"));
|
|
48211
|
+
if (targetConfigPath.split(posix.sep).includes(".limina")) throw new Error([
|
|
48212
|
+
"Invalid raw build config:",
|
|
48213
|
+
` config: ${toRelativePath(projectRootDir, targetConfigPath)}`,
|
|
48214
|
+
" reason: raw build expects a user-authored tsconfig, not a .limina generated config."
|
|
48215
|
+
].join("\n"));
|
|
48216
|
+
return {
|
|
48217
|
+
checker: options.checker,
|
|
48218
|
+
kind: "raw",
|
|
48219
|
+
targetConfigPath
|
|
48220
|
+
};
|
|
48221
|
+
}
|
|
47160
48222
|
const generatedGraph = await (options.core ?? createLiminaCore(options.config)).buildGraph.getGraph();
|
|
47161
48223
|
const allCheckers = generatedGraph.checkers;
|
|
47162
|
-
const
|
|
48224
|
+
const declarationTargets = isOrdinarySourceTypecheckConfigPath(targetConfigPath) ? collectManagedDeclarationBuildTargets({
|
|
47163
48225
|
allCheckers,
|
|
47164
48226
|
generatedGraph,
|
|
47165
48227
|
sourceConfigPath: targetConfigPath
|
|
47166
48228
|
}) : [];
|
|
47167
|
-
|
|
47168
|
-
|
|
47169
|
-
|
|
47170
|
-
targetConfigPath
|
|
47171
|
-
};
|
|
47172
|
-
const
|
|
48229
|
+
const buildCapableTargets = (isOrdinarySourceTypecheckConfigPath(targetConfigPath) ? collectManagedOutputBuildTargets({
|
|
48230
|
+
allCheckers,
|
|
48231
|
+
generatedGraph,
|
|
48232
|
+
sourceConfigPath: targetConfigPath
|
|
48233
|
+
}) : []).filter(({ checker }) => getCheckerAdapter(checker.preset)?.execution === "build");
|
|
48234
|
+
const buildCapableDeclarationTargets = declarationTargets.filter(({ checker }) => getCheckerAdapter(checker.preset)?.execution === "build");
|
|
48235
|
+
const availableCheckers = uniqueSortedStrings(buildCapableTargets.map(({ checker }) => checker.preset));
|
|
48236
|
+
const checkerTargets = options.checker ? buildCapableTargets.filter(({ checker }) => checker.preset === options.checker) : buildCapableTargets;
|
|
48237
|
+
const managedBuildModules = declarationTargets.length > 0;
|
|
48238
|
+
const targetBuildModuleKinds = uniqueSortedStrings(buildCapableDeclarationTargets.map(({ buildModule }) => buildModule.kind));
|
|
48239
|
+
const resolutionKind = checkerTargets.length > 0 ? "managed-output" : managedBuildModules ? buildCapableDeclarationTargets.length === 0 ? "typecheck-only" : targetBuildModuleKinds.includes("solution") ? "outputless-solution" : "outputless-project" : "unmanaged";
|
|
47173
48240
|
return {
|
|
47174
|
-
availableCheckers
|
|
48241
|
+
availableCheckers,
|
|
47175
48242
|
allCheckers,
|
|
47176
|
-
checkerTargets
|
|
48243
|
+
checkerTargets,
|
|
47177
48244
|
generatedGraph,
|
|
47178
48245
|
kind: "managed",
|
|
47179
|
-
matchingCheckers:
|
|
48246
|
+
matchingCheckers: declarationTargets.map(({ checker }) => checker),
|
|
48247
|
+
resolutionKind,
|
|
47180
48248
|
...options.checker ? { selectedChecker: options.checker } : {},
|
|
47181
48249
|
sourceConfigPath: targetConfigPath
|
|
47182
48250
|
};
|
|
@@ -47306,7 +48374,7 @@ function collectBuildTargetProviderClosure(options) {
|
|
|
47306
48374
|
if (edge.fromChecker !== current.checker.name || edge.fromConfigPath !== current.sourceConfigPath) continue;
|
|
47307
48375
|
const checker = checkerByName.get(edge.toChecker);
|
|
47308
48376
|
if (!checker || getCheckerAdapter(checker.preset)?.execution !== "build") continue;
|
|
47309
|
-
const buildModule = options.generatedGraph.
|
|
48377
|
+
const buildModule = options.generatedGraph.configToOutputBuild.get(checker.name)?.get(edge.toConfigPath);
|
|
47310
48378
|
if (!buildModule) continue;
|
|
47311
48379
|
const descriptor = {
|
|
47312
48380
|
buildModule,
|
|
@@ -47330,7 +48398,8 @@ async function runBuildImpl(options) {
|
|
|
47330
48398
|
configPath: options.configPath,
|
|
47331
48399
|
core: options.core,
|
|
47332
48400
|
cwd,
|
|
47333
|
-
project: options.project
|
|
48401
|
+
project: options.project,
|
|
48402
|
+
raw: options.raw
|
|
47334
48403
|
});
|
|
47335
48404
|
const flowDepth = options.flowDepth ?? 0;
|
|
47336
48405
|
const rootConfigPaths = [];
|
|
@@ -47424,11 +48493,36 @@ async function runBuildImpl(options) {
|
|
|
47424
48493
|
if (resolvedTarget.checkerTargets.length === 0) {
|
|
47425
48494
|
const selectionProblem = resolvedTarget.selectedChecker ? formatManagedBuildCheckerSelectionProblem({
|
|
47426
48495
|
availableCheckers: resolvedTarget.availableCheckers,
|
|
48496
|
+
commandLabel: "build",
|
|
47427
48497
|
projectRootDir,
|
|
47428
48498
|
selectedChecker: resolvedTarget.selectedChecker,
|
|
47429
48499
|
sourceConfigPath: resolvedTarget.sourceConfigPath
|
|
47430
|
-
}) :
|
|
47431
|
-
|
|
48500
|
+
}) : formatOutputBuildTargetResolutionProblem({
|
|
48501
|
+
matchingCheckers: resolvedTarget.matchingCheckers,
|
|
48502
|
+
projectRootDir,
|
|
48503
|
+
resolutionKind: resolvedTarget.resolutionKind,
|
|
48504
|
+
sourceConfigPath: resolvedTarget.sourceConfigPath
|
|
48505
|
+
});
|
|
48506
|
+
if (shouldLogCheckReport(options.report)) TypecheckLogger.error(formatCheckIssueSummaryReport({
|
|
48507
|
+
details: selectionProblem,
|
|
48508
|
+
issueCount: 1,
|
|
48509
|
+
pluralIssueLabel: "build selection issues",
|
|
48510
|
+
singularIssueLabel: "build selection issue",
|
|
48511
|
+
title: "Build summary"
|
|
48512
|
+
}));
|
|
48513
|
+
return {
|
|
48514
|
+
failedTargets: [],
|
|
48515
|
+
failureKind: "target-selection",
|
|
48516
|
+
passed: false,
|
|
48517
|
+
problems: [selectionProblem],
|
|
48518
|
+
projectRootDir,
|
|
48519
|
+
rootConfigPaths,
|
|
48520
|
+
sourceConfigPath: resolvedTarget.sourceConfigPath
|
|
48521
|
+
};
|
|
48522
|
+
}
|
|
48523
|
+
if (!resolvedTarget.selectedChecker && resolvedTarget.checkerTargets.length > 1) {
|
|
48524
|
+
const selectionProblem = formatMultipleOutputBuildPresetProblem({
|
|
48525
|
+
availableCheckers: resolvedTarget.availableCheckers,
|
|
47432
48526
|
projectRootDir,
|
|
47433
48527
|
sourceConfigPath: resolvedTarget.sourceConfigPath
|
|
47434
48528
|
});
|
|
@@ -47520,21 +48614,6 @@ async function runBuildImpl(options) {
|
|
|
47520
48614
|
})).filter((result) => result.status !== 0);
|
|
47521
48615
|
const failedTargets = collectFailedCheckerTargets(targets, failedResults);
|
|
47522
48616
|
const passed = failedResults.length === 0;
|
|
47523
|
-
reportBuildCheckerCombinationWarning({
|
|
47524
|
-
entries: collectBuildGraphCombinationEntries({
|
|
47525
|
-
generatedGraph: resolvedTarget.generatedGraph,
|
|
47526
|
-
projectRootDir,
|
|
47527
|
-
roots: buildTargetDescriptors.map(({ buildModule, checker, sourceConfigPath }) => ({
|
|
47528
|
-
checker,
|
|
47529
|
-
configPath: buildModule.path,
|
|
47530
|
-
entryConfigPath: sourceConfigPath
|
|
47531
|
-
}))
|
|
47532
|
-
}),
|
|
47533
|
-
flow: options.flow,
|
|
47534
|
-
flowDepth,
|
|
47535
|
-
projectRootDir,
|
|
47536
|
-
report: options.report
|
|
47537
|
-
});
|
|
47538
48617
|
if (!passed) {
|
|
47539
48618
|
if (shouldLogCheckReport(options.report)) TypecheckLogger.error(formatFailedTargetSummaryReport({
|
|
47540
48619
|
failedResults,
|
|
@@ -47843,7 +48922,7 @@ async function runBuild(options) {
|
|
|
47843
48922
|
failedTargets: result.failedTargets,
|
|
47844
48923
|
fallbackReason: "Checker build finished with failures.",
|
|
47845
48924
|
failureKind: result.failureKind,
|
|
47846
|
-
fix: "Inspect the
|
|
48925
|
+
fix: "Inspect the build output above, then rerun `limina build <config>`.",
|
|
47847
48926
|
projectRootDir: result.projectRootDir,
|
|
47848
48927
|
problems: result.problems,
|
|
47849
48928
|
task: "checker:build",
|
|
@@ -47868,7 +48947,7 @@ async function runBuild(options) {
|
|
|
47868
48947
|
const issue = createTaskFailureIssue({
|
|
47869
48948
|
code: "LIMINA_CHECKER_BUILD_FAILED",
|
|
47870
48949
|
detailLines: [formatErrorMessage(error)],
|
|
47871
|
-
fix: "Inspect the build error above, then rerun `limina
|
|
48950
|
+
fix: "Inspect the build error above, then rerun `limina build <config>`.",
|
|
47872
48951
|
reason: `Checker build failed: ${formatErrorMessage(error)}.`,
|
|
47873
48952
|
rootDir: options.config.rootDir,
|
|
47874
48953
|
task: "checker:build",
|
|
@@ -47960,32 +49039,44 @@ async function runCheckerTypecheck(options) {
|
|
|
47960
49039
|
|
|
47961
49040
|
//#endregion
|
|
47962
49041
|
//#region src/flow/process-renderer.ts
|
|
47963
|
-
|
|
47964
|
-
|
|
47965
|
-
|
|
49042
|
+
const requireFromRenderer = createRequire(import.meta.url);
|
|
49043
|
+
function resolveTsxCliPath(packageDir) {
|
|
49044
|
+
try {
|
|
49045
|
+
return requireFromRenderer.resolve("tsx/cli");
|
|
49046
|
+
} catch {
|
|
49047
|
+
return [posix.join(packageDir, "node_modules/tsx/dist/cli.mjs"), posix.join(packageDir, "../../node_modules/tsx/dist/cli.mjs")].find((candidate) => existsSync(candidate));
|
|
49048
|
+
}
|
|
47966
49049
|
}
|
|
47967
49050
|
function resolveRendererEntry() {
|
|
47968
49051
|
const currentDir = fileURLToPath(new URL(".", import.meta.url));
|
|
47969
|
-
const sourceEntries = [posix.resolve(currentDir, "
|
|
49052
|
+
const sourceEntries = [posix.resolve(currentDir, "renderer-process.ts"), posix.resolve(process.cwd(), "src/flow/renderer-process.ts")];
|
|
47970
49053
|
const distEntries = [
|
|
47971
49054
|
posix.resolve(currentDir, "flow-renderer-process.js"),
|
|
47972
49055
|
posix.resolve(currentDir, "../flow-renderer-process.js"),
|
|
47973
49056
|
posix.resolve(process.cwd(), "dist/flow-renderer-process.js")
|
|
47974
49057
|
];
|
|
47975
49058
|
const sourceEntry = sourceEntries.find((candidate) => existsSync(candidate));
|
|
47976
|
-
if (sourceEntry)
|
|
47977
|
-
|
|
47978
|
-
|
|
47979
|
-
|
|
49059
|
+
if (sourceEntry) {
|
|
49060
|
+
const tsxCliPath = resolveTsxCliPath(posix.resolve(posix.dirname(sourceEntry), "../.."));
|
|
49061
|
+
if (!tsxCliPath) return;
|
|
49062
|
+
return {
|
|
49063
|
+
args: [tsxCliPath, sourceEntry],
|
|
49064
|
+
command: process.execPath
|
|
49065
|
+
};
|
|
49066
|
+
}
|
|
47980
49067
|
const distEntry = distEntries.find((candidate) => existsSync(candidate));
|
|
47981
49068
|
if (distEntry) return {
|
|
47982
49069
|
args: [distEntry],
|
|
47983
49070
|
command: process.execPath
|
|
47984
49071
|
};
|
|
47985
49072
|
}
|
|
49073
|
+
function getWriteCallback(args) {
|
|
49074
|
+
if (args.length === 3) return args[2];
|
|
49075
|
+
if (typeof args[1] === "function") return args[1];
|
|
49076
|
+
}
|
|
47986
49077
|
function callWriteCallback(args) {
|
|
47987
|
-
const callback = args
|
|
47988
|
-
if (
|
|
49078
|
+
const callback = getWriteCallback(args);
|
|
49079
|
+
if (callback) queueMicrotask(callback);
|
|
47989
49080
|
}
|
|
47990
49081
|
var FlowProcessRenderer = class FlowProcessRenderer {
|
|
47991
49082
|
#child;
|
|
@@ -48018,7 +49109,6 @@ var FlowProcessRenderer = class FlowProcessRenderer {
|
|
|
48018
49109
|
if (!entry) return;
|
|
48019
49110
|
const renderer = new FlowProcessRenderer(spawn(entry.command, entry.args, {
|
|
48020
49111
|
env: process.env,
|
|
48021
|
-
shell: process.platform === "win32",
|
|
48022
49112
|
stdio: [
|
|
48023
49113
|
"ignore",
|
|
48024
49114
|
"inherit",
|
|
@@ -48092,7 +49182,7 @@ var FlowProcessRenderer = class FlowProcessRenderer {
|
|
|
48092
49182
|
callWriteCallback(args);
|
|
48093
49183
|
return true;
|
|
48094
49184
|
}
|
|
48095
|
-
return
|
|
49185
|
+
return writeWithFlowArgs(originalWrite, args);
|
|
48096
49186
|
});
|
|
48097
49187
|
return () => {
|
|
48098
49188
|
stream.write = originalWrite;
|
|
@@ -48108,15 +49198,48 @@ var FlowProcessRenderer = class FlowProcessRenderer {
|
|
|
48108
49198
|
}
|
|
48109
49199
|
};
|
|
48110
49200
|
|
|
49201
|
+
//#endregion
|
|
49202
|
+
//#region src/flow/tree-state.ts
|
|
49203
|
+
function createFlowTreeNode(message, depth) {
|
|
49204
|
+
return {
|
|
49205
|
+
children: [],
|
|
49206
|
+
depth,
|
|
49207
|
+
message,
|
|
49208
|
+
status: "planned"
|
|
49209
|
+
};
|
|
49210
|
+
}
|
|
49211
|
+
function appendFlowTreeChild(parent, message, depth) {
|
|
49212
|
+
const childNode = createFlowTreeNode(message, depth);
|
|
49213
|
+
parent.children.push(childNode);
|
|
49214
|
+
return childNode;
|
|
49215
|
+
}
|
|
49216
|
+
function cloneFlowTreeNode(node) {
|
|
49217
|
+
return {
|
|
49218
|
+
children: node.children.map(cloneFlowTreeNode),
|
|
49219
|
+
depth: node.depth,
|
|
49220
|
+
elapsedTimeMs: node.elapsedTimeMs,
|
|
49221
|
+
message: node.message,
|
|
49222
|
+
status: node.status
|
|
49223
|
+
};
|
|
49224
|
+
}
|
|
49225
|
+
function skipPlannedTreeDescendants(node) {
|
|
49226
|
+
for (const child of node.children) {
|
|
49227
|
+
if (child.status === "planned") child.status = "skipped";
|
|
49228
|
+
skipPlannedTreeDescendants(child);
|
|
49229
|
+
}
|
|
49230
|
+
}
|
|
49231
|
+
|
|
48111
49232
|
//#endregion
|
|
48112
49233
|
//#region src/flow.ts
|
|
48113
49234
|
const CHECK_FLOW_STATUS_ONLY_OPTION = Symbol("limina.checkFlowStatusOnly");
|
|
48114
49235
|
const DEFAULT_CI_ENV_VALUES = new Set(["1", "true"]);
|
|
48115
|
-
const
|
|
48116
|
-
const ANSI_ESCAPE = String.fromCodePoint(27);
|
|
48117
|
-
const ANSI_PATTERN = new RegExp(String.raw`${ANSI_ESCAPE}\[[\d:;<=>?]*[\u0020-\u002F]*[\u0040-\u007E]`, "gu");
|
|
49236
|
+
const FLOW_RENDERER_TEST_ROWS_ENV = "LIMINA_FLOW_RENDERER_TEST_ROWS";
|
|
48118
49237
|
function isCiEnvironment(env) {
|
|
48119
|
-
return DEFAULT_CI_ENV_VALUES.has(String(env.CI).toLowerCase());
|
|
49238
|
+
return DEFAULT_CI_ENV_VALUES.has(String(env.CI).toLowerCase()) || DEFAULT_CI_ENV_VALUES.has(String(env.CODEX_CI).toLowerCase());
|
|
49239
|
+
}
|
|
49240
|
+
function supportsInteractiveTerminal(env, stdout) {
|
|
49241
|
+
if (!stdout.isTTY || isCiEnvironment(env)) return false;
|
|
49242
|
+
return String(env.TERM).toLowerCase() !== "dumb";
|
|
48120
49243
|
}
|
|
48121
49244
|
function formatFailureMessage(message, error) {
|
|
48122
49245
|
if (error === void 0) return message;
|
|
@@ -48126,22 +49249,27 @@ function formatFailureMessage(message, error) {
|
|
|
48126
49249
|
function writeLine(output, message) {
|
|
48127
49250
|
output.write(`${message}\n`);
|
|
48128
49251
|
}
|
|
48129
|
-
function
|
|
48130
|
-
return
|
|
48131
|
-
|
|
48132
|
-
|
|
48133
|
-
|
|
49252
|
+
function createTaskFinishOptions(options, depth, startTime) {
|
|
49253
|
+
return {
|
|
49254
|
+
...options,
|
|
49255
|
+
depth,
|
|
49256
|
+
elapsedTimeMs: options?.elapsedTimeMs ?? performance.now() - startTime
|
|
49257
|
+
};
|
|
48134
49258
|
}
|
|
48135
|
-
function
|
|
48136
|
-
|
|
49259
|
+
function readPositiveInteger(value) {
|
|
49260
|
+
if (value === void 0) return;
|
|
49261
|
+
const parsed = Number.parseInt(value, 10);
|
|
49262
|
+
return Number.isInteger(parsed) && parsed > 0 ? parsed : void 0;
|
|
48137
49263
|
}
|
|
48138
49264
|
var LiminaFlowReporter = class {
|
|
48139
49265
|
#clack;
|
|
49266
|
+
#env;
|
|
48140
49267
|
#interactive;
|
|
48141
49268
|
#output;
|
|
48142
49269
|
#statusOnly;
|
|
48143
49270
|
#stderr;
|
|
48144
49271
|
#stdout;
|
|
49272
|
+
#terminalFrame;
|
|
48145
49273
|
#tracksProcessWrites;
|
|
48146
49274
|
#interactiveHistory = [];
|
|
48147
49275
|
#treeRoots = [];
|
|
@@ -48155,13 +49283,12 @@ var LiminaFlowReporter = class {
|
|
|
48155
49283
|
#spinnerFrameIndex = 0;
|
|
48156
49284
|
#spinnerTimer;
|
|
48157
49285
|
#trackedTaskCount = 0;
|
|
48158
|
-
#terminalColumn = 0;
|
|
48159
|
-
#terminalLineCount = 0;
|
|
48160
49286
|
constructor(options = {}) {
|
|
48161
49287
|
const env = options.env ?? process.env;
|
|
48162
49288
|
const stdout = options.stdout ?? process.stdout;
|
|
48163
49289
|
this.#statusOnly = options[CHECK_FLOW_STATUS_ONLY_OPTION] === true;
|
|
48164
|
-
this.#
|
|
49290
|
+
this.#env = env;
|
|
49291
|
+
this.#interactive = options.forceTty ?? supportsInteractiveTerminal(env, stdout);
|
|
48165
49292
|
this.#clack = options.clack ?? dist_exports;
|
|
48166
49293
|
this.#output = options.output ?? { write: (message) => {
|
|
48167
49294
|
if (typeof stdout.write === "function") {
|
|
@@ -48172,6 +49299,7 @@ var LiminaFlowReporter = class {
|
|
|
48172
49299
|
} };
|
|
48173
49300
|
this.#stdout = stdout;
|
|
48174
49301
|
this.#stderr = options.stderr ?? process.stderr;
|
|
49302
|
+
this.#terminalFrame = new TerminalFrameTracker(() => this.#stdout?.columns ?? DEFAULT_TERMINAL_COLUMNS);
|
|
48175
49303
|
this.#processRenderer = this.#createProcessRenderer(options);
|
|
48176
49304
|
this.#tracksProcessWrites = this.#interactive && !this.#statusOnly && options.output === void 0 && !this.#processRenderer;
|
|
48177
49305
|
}
|
|
@@ -48189,20 +49317,21 @@ var LiminaFlowReporter = class {
|
|
|
48189
49317
|
if (!this.#interactive || rendererMode === "inline" || options.output !== void 0 || options.stdout !== void 0 || options.stderr !== void 0 || options.clack !== void 0) return;
|
|
48190
49318
|
return FlowProcessRenderer.start();
|
|
48191
49319
|
}
|
|
48192
|
-
#cloneTreeNode(node) {
|
|
48193
|
-
return {
|
|
48194
|
-
children: node.children.map((child) => this.#cloneTreeNode(child)),
|
|
48195
|
-
depth: node.depth,
|
|
48196
|
-
elapsedTimeMs: node.elapsedTimeMs,
|
|
48197
|
-
message: node.message,
|
|
48198
|
-
status: node.status
|
|
48199
|
-
};
|
|
48200
|
-
}
|
|
48201
49320
|
#createRenderSnapshot() {
|
|
49321
|
+
const terminalDimensions = this.#getTerminalDimensions();
|
|
49322
|
+
const hasTerminalDimensions = terminalDimensions.columns !== void 0 || terminalDimensions.rows !== void 0;
|
|
48202
49323
|
return {
|
|
49324
|
+
...this.#statusOnly ? { compactMode: "check-flow" } : {},
|
|
48203
49325
|
entries: [...this.#interactiveHistory, ...this.#processTransientHistory.map(({ entry }) => entry)],
|
|
48204
49326
|
...this.#outroMessage === void 0 ? {} : { outroMessage: this.#outroMessage },
|
|
48205
|
-
|
|
49327
|
+
...hasTerminalDimensions ? { terminalDimensions } : {},
|
|
49328
|
+
treeRoots: this.#treeRoots.map(cloneFlowTreeNode)
|
|
49329
|
+
};
|
|
49330
|
+
}
|
|
49331
|
+
#getTerminalDimensions() {
|
|
49332
|
+
return {
|
|
49333
|
+
columns: this.#stdout?.columns,
|
|
49334
|
+
rows: readPositiveInteger(this.#env[FLOW_RENDERER_TEST_ROWS_ENV]) ?? this.#stdout?.rows
|
|
48206
49335
|
};
|
|
48207
49336
|
}
|
|
48208
49337
|
#sendProcessSnapshot() {
|
|
@@ -48210,7 +49339,8 @@ var LiminaFlowReporter = class {
|
|
|
48210
49339
|
this.#processRenderer.sendSnapshot(this.#createRenderSnapshot());
|
|
48211
49340
|
}
|
|
48212
49341
|
#writeRenderSnapshotInline(snapshot) {
|
|
48213
|
-
|
|
49342
|
+
const lines = renderSnapshotLinesForTerminal(snapshot, this.#spinnerFrameIndex, this.#getTerminalDimensions());
|
|
49343
|
+
for (const line of lines) writeLine(this.#output, line);
|
|
48214
49344
|
}
|
|
48215
49345
|
intro(message) {
|
|
48216
49346
|
if (this.#interactive) {
|
|
@@ -48227,7 +49357,7 @@ var LiminaFlowReporter = class {
|
|
|
48227
49357
|
kind: "line",
|
|
48228
49358
|
line: `┌ ${message}`
|
|
48229
49359
|
});
|
|
48230
|
-
this.#
|
|
49360
|
+
this.#terminalFrame.record(`${message}\n`);
|
|
48231
49361
|
return;
|
|
48232
49362
|
}
|
|
48233
49363
|
writeLine(this.#output, `[start] ${message}`);
|
|
@@ -48239,6 +49369,11 @@ var LiminaFlowReporter = class {
|
|
|
48239
49369
|
this.#sendProcessSnapshot();
|
|
48240
49370
|
return;
|
|
48241
49371
|
}
|
|
49372
|
+
if (this.#statusOnly) {
|
|
49373
|
+
this.#outroMessage = message;
|
|
49374
|
+
this.#redrawInteractiveHistory();
|
|
49375
|
+
return;
|
|
49376
|
+
}
|
|
48242
49377
|
this.#clack.outro(message);
|
|
48243
49378
|
return;
|
|
48244
49379
|
}
|
|
@@ -48249,7 +49384,7 @@ var LiminaFlowReporter = class {
|
|
|
48249
49384
|
const collapseOnSuccess = this.#statusOnly ? false : options.collapseOnSuccess ?? true;
|
|
48250
49385
|
const shouldTrackTask = this.#interactive && collapseOnSuccess;
|
|
48251
49386
|
const persistStart = !shouldTrackTask && this.#trackedTaskCount === 0;
|
|
48252
|
-
const startLine = this.#
|
|
49387
|
+
const startLine = this.#terminalFrame.lineCount;
|
|
48253
49388
|
const startTime = performance.now();
|
|
48254
49389
|
const processTransientTaskId = shouldTrackTask && this.#processRenderer ? this.#nextProcessTransientTaskId++ : void 0;
|
|
48255
49390
|
let completed = false;
|
|
@@ -48265,11 +49400,7 @@ var LiminaFlowReporter = class {
|
|
|
48265
49400
|
};
|
|
48266
49401
|
return {
|
|
48267
49402
|
fail: (nextMessage, nextOptions) => {
|
|
48268
|
-
const failOptions =
|
|
48269
|
-
...nextOptions,
|
|
48270
|
-
depth,
|
|
48271
|
-
elapsedTimeMs: nextOptions?.elapsedTimeMs ?? performance.now() - startTime
|
|
48272
|
-
};
|
|
49403
|
+
const failOptions = createTaskFinishOptions(nextOptions, depth, startTime);
|
|
48273
49404
|
const failMessage = this.#statusOnly ? message : nextMessage ?? message;
|
|
48274
49405
|
if (!shouldTrackTask && this.#interactive && persistedStartIndex !== void 0) {
|
|
48275
49406
|
this.#replaceInteractiveHistoryLine(persistedStartIndex, "fail", this.#formatFailureMessage(failMessage, nextOptions), failOptions);
|
|
@@ -48278,7 +49409,6 @@ var LiminaFlowReporter = class {
|
|
|
48278
49409
|
return;
|
|
48279
49410
|
}
|
|
48280
49411
|
this.#emit("fail", this.#formatFailureMessage(failMessage, nextOptions), failOptions, { persistInteractive: true });
|
|
48281
|
-
if (!this.#interactive) return;
|
|
48282
49412
|
finishTrackedTask();
|
|
48283
49413
|
},
|
|
48284
49414
|
info: (nextMessage, nextOptions) => {
|
|
@@ -48288,11 +49418,7 @@ var LiminaFlowReporter = class {
|
|
|
48288
49418
|
});
|
|
48289
49419
|
},
|
|
48290
49420
|
pass: (nextMessage, nextOptions) => {
|
|
48291
|
-
const passOptions =
|
|
48292
|
-
...nextOptions,
|
|
48293
|
-
depth,
|
|
48294
|
-
elapsedTimeMs: nextOptions?.elapsedTimeMs ?? performance.now() - startTime
|
|
48295
|
-
};
|
|
49421
|
+
const passOptions = createTaskFinishOptions(nextOptions, depth, startTime);
|
|
48296
49422
|
const persistInteractive = shouldTrackTask ? this.#trackedTaskCount <= 1 : this.#trackedTaskCount === 0;
|
|
48297
49423
|
if (shouldTrackTask) if (this.#processRenderer?.active) {
|
|
48298
49424
|
this.#processTransientHistory = this.#processTransientHistory.filter((entry) => entry.taskId !== processTransientTaskId);
|
|
@@ -48308,11 +49434,7 @@ var LiminaFlowReporter = class {
|
|
|
48308
49434
|
finishTrackedTask();
|
|
48309
49435
|
},
|
|
48310
49436
|
skip: (nextMessage, nextOptions) => {
|
|
48311
|
-
const skipOptions =
|
|
48312
|
-
...nextOptions,
|
|
48313
|
-
depth,
|
|
48314
|
-
elapsedTimeMs: nextOptions?.elapsedTimeMs ?? performance.now() - startTime
|
|
48315
|
-
};
|
|
49437
|
+
const skipOptions = createTaskFinishOptions(nextOptions, depth, startTime);
|
|
48316
49438
|
if (!shouldTrackTask && this.#interactive && persistedStartIndex !== void 0) {
|
|
48317
49439
|
this.#replaceInteractiveHistoryLine(persistedStartIndex, "skip", nextMessage ?? message, skipOptions);
|
|
48318
49440
|
this.#redrawInteractiveHistory();
|
|
@@ -48331,12 +49453,7 @@ var LiminaFlowReporter = class {
|
|
|
48331
49453
|
};
|
|
48332
49454
|
}
|
|
48333
49455
|
tree(message, options = {}) {
|
|
48334
|
-
const node =
|
|
48335
|
-
children: [],
|
|
48336
|
-
depth: options.depth ?? 0,
|
|
48337
|
-
message,
|
|
48338
|
-
status: "planned"
|
|
48339
|
-
};
|
|
49456
|
+
const node = createFlowTreeNode(message, options.depth ?? 0);
|
|
48340
49457
|
this.#treeRoots.push(node);
|
|
48341
49458
|
this.#ensureInteractiveTree();
|
|
48342
49459
|
this.#renderTreeChange();
|
|
@@ -48370,7 +49487,7 @@ var LiminaFlowReporter = class {
|
|
|
48370
49487
|
}
|
|
48371
49488
|
const stream = options.stream === "stderr" ? this.#stderr : this.#stdout;
|
|
48372
49489
|
if (this.#interactive && this.#tracksProcessWrites && typeof stream?.write === "function") {
|
|
48373
|
-
if (this.#restoreWriteStreams === void 0) this.#
|
|
49490
|
+
if (this.#restoreWriteStreams === void 0) this.#terminalFrame.record(message);
|
|
48374
49491
|
stream.write(message);
|
|
48375
49492
|
return;
|
|
48376
49493
|
}
|
|
@@ -48437,8 +49554,12 @@ var LiminaFlowReporter = class {
|
|
|
48437
49554
|
#beginTerminalTracking() {
|
|
48438
49555
|
this.#trackedTaskCount += 1;
|
|
48439
49556
|
if (this.#trackedTaskCount > 1 || !this.#tracksProcessWrites) return;
|
|
48440
|
-
const restoreStdout =
|
|
48441
|
-
|
|
49557
|
+
const restoreStdout = patchWriteStream(this.#stdout, (chunk) => {
|
|
49558
|
+
this.#terminalFrame.record(chunk);
|
|
49559
|
+
});
|
|
49560
|
+
const restoreStderr = patchWriteStream(this.#stderr, (chunk) => {
|
|
49561
|
+
this.#terminalFrame.record(chunk);
|
|
49562
|
+
});
|
|
48442
49563
|
this.#restoreWriteStreams = () => {
|
|
48443
49564
|
restoreStdout?.();
|
|
48444
49565
|
restoreStderr?.();
|
|
@@ -48446,64 +49567,30 @@ var LiminaFlowReporter = class {
|
|
|
48446
49567
|
};
|
|
48447
49568
|
}
|
|
48448
49569
|
#clearInteractiveTaskBlock(startLine, options = {}) {
|
|
48449
|
-
const linesToClear = this.#
|
|
49570
|
+
const linesToClear = this.#terminalFrame.lineCount - startLine;
|
|
48450
49571
|
if (linesToClear <= 0) return;
|
|
48451
49572
|
if (options.redrawHistory) {
|
|
48452
49573
|
this.#redrawInteractiveHistory();
|
|
48453
49574
|
return;
|
|
48454
49575
|
}
|
|
48455
49576
|
this.#writeControl(`\r\u001B[${linesToClear}A\u001B[J`);
|
|
48456
|
-
this.#
|
|
48457
|
-
this.#terminalColumn = 0;
|
|
49577
|
+
this.#terminalFrame.setLineCount(startLine);
|
|
48458
49578
|
}
|
|
48459
49579
|
#endTerminalTracking() {
|
|
48460
49580
|
this.#trackedTaskCount = Math.max(0, this.#trackedTaskCount - 1);
|
|
48461
49581
|
if (this.#trackedTaskCount === 0) this.#restoreWriteStreams?.();
|
|
48462
49582
|
}
|
|
48463
|
-
#patchWriteStream(stream) {
|
|
48464
|
-
if (typeof stream?.write !== "function") return;
|
|
48465
|
-
const originalWrite = stream.write;
|
|
48466
|
-
stream.write = (...args) => {
|
|
48467
|
-
this.#recordTerminalWrite(args[0]);
|
|
48468
|
-
return Reflect.apply(originalWrite, stream, args);
|
|
48469
|
-
};
|
|
48470
|
-
return () => {
|
|
48471
|
-
stream.write = originalWrite;
|
|
48472
|
-
};
|
|
48473
|
-
}
|
|
48474
|
-
#recordTerminalWrite(chunk) {
|
|
48475
|
-
const text = stripControlSequences(toWritableText(chunk));
|
|
48476
|
-
const columns = Math.max(1, this.#stdout?.columns ?? DEFAULT_TERMINAL_COLUMNS);
|
|
48477
|
-
for (const char of text) {
|
|
48478
|
-
if (char === "\n") {
|
|
48479
|
-
this.#terminalLineCount += 1;
|
|
48480
|
-
this.#terminalColumn = 0;
|
|
48481
|
-
continue;
|
|
48482
|
-
}
|
|
48483
|
-
this.#terminalColumn += 1;
|
|
48484
|
-
if (this.#terminalColumn >= columns) {
|
|
48485
|
-
this.#terminalLineCount += 1;
|
|
48486
|
-
this.#terminalColumn = 0;
|
|
48487
|
-
}
|
|
48488
|
-
}
|
|
48489
|
-
}
|
|
48490
49583
|
#redrawInteractiveHistory() {
|
|
48491
49584
|
if (this.#processRenderer?.active) {
|
|
48492
49585
|
this.#sendProcessSnapshot();
|
|
48493
49586
|
return;
|
|
48494
49587
|
}
|
|
48495
|
-
if (this.#
|
|
48496
|
-
this.#
|
|
48497
|
-
this.#
|
|
48498
|
-
for (const
|
|
48499
|
-
|
|
48500
|
-
|
|
48501
|
-
this.#writeTracked(message, { forceRecord: this.#restoreWriteStreams === void 0 });
|
|
48502
|
-
} }, line);
|
|
48503
|
-
}
|
|
48504
|
-
}
|
|
48505
|
-
#renderInteractiveHistoryFlowLine(entry) {
|
|
48506
|
-
return this.#formatInteractiveLine(entry.status, formatMessageWithElapsed(entry.message, entry.elapsedTimeMs), entry.depth);
|
|
49588
|
+
if (this.#terminalFrame.lineCount > 0) this.#writeControl(`\r\u001B[${this.#terminalFrame.lineCount}A\u001B[J`);
|
|
49589
|
+
this.#terminalFrame.reset();
|
|
49590
|
+
const frameLines = renderSnapshotLinesForTerminal(this.#createRenderSnapshot(), this.#spinnerFrameIndex, this.#getTerminalDimensions());
|
|
49591
|
+
for (const line of frameLines) writeLine({ write: (message) => {
|
|
49592
|
+
this.#writeTracked(message, { forceRecord: this.#restoreWriteStreams === void 0 });
|
|
49593
|
+
} }, line);
|
|
48507
49594
|
}
|
|
48508
49595
|
#formatInteractiveLine(status, message, depth) {
|
|
48509
49596
|
return formatInteractiveLine(status, message, depth, this.#spinnerFrameIndex);
|
|
@@ -48530,10 +49617,12 @@ var LiminaFlowReporter = class {
|
|
|
48530
49617
|
#createTreeNodeHandle(node) {
|
|
48531
49618
|
return {
|
|
48532
49619
|
child: (message, options = {}) => {
|
|
48533
|
-
|
|
49620
|
+
const childNode = appendFlowTreeChild(node, message, options.depth ?? node.depth + 1);
|
|
49621
|
+
this.#renderTreeChange();
|
|
49622
|
+
return this.#createTreeNodeHandle(childNode);
|
|
48534
49623
|
},
|
|
48535
49624
|
children: (messages, options = {}) => {
|
|
48536
|
-
const childNodes = messages.map((message) =>
|
|
49625
|
+
const childNodes = messages.map((message) => appendFlowTreeChild(node, message, options.depth ?? node.depth + 1));
|
|
48537
49626
|
if (childNodes.length > 0) this.#renderTreeChange();
|
|
48538
49627
|
return childNodes.map((childNode) => this.#createTreeNodeHandle(childNode));
|
|
48539
49628
|
},
|
|
@@ -48563,25 +49652,13 @@ var LiminaFlowReporter = class {
|
|
|
48563
49652
|
}
|
|
48564
49653
|
};
|
|
48565
49654
|
}
|
|
48566
|
-
#appendTreeChild(parent, message, options, meta) {
|
|
48567
|
-
const childNode = {
|
|
48568
|
-
children: [],
|
|
48569
|
-
depth: options.depth ?? parent.depth + 1,
|
|
48570
|
-
message,
|
|
48571
|
-
parent,
|
|
48572
|
-
status: "planned"
|
|
48573
|
-
};
|
|
48574
|
-
parent.children.push(childNode);
|
|
48575
|
-
if (meta.redraw) this.#renderTreeChange();
|
|
48576
|
-
return childNode;
|
|
48577
|
-
}
|
|
48578
49655
|
#ensureInteractiveTree() {
|
|
48579
49656
|
if (!this.#interactive || this.#hasInteractiveTree) return;
|
|
48580
49657
|
this.#interactiveHistory.push({ kind: "tree" });
|
|
48581
49658
|
this.#hasInteractiveTree = true;
|
|
48582
49659
|
}
|
|
48583
49660
|
#finishTreeNode(node, status, message, options) {
|
|
48584
|
-
|
|
49661
|
+
skipPlannedTreeDescendants(node);
|
|
48585
49662
|
if (message) node.message = status === "failed" ? this.#formatFailureMessage(message, options) : message;
|
|
48586
49663
|
else if (status === "failed") node.message = this.#formatFailureMessage(node.message, options);
|
|
48587
49664
|
if (options?.depth !== void 0) node.depth = options.depth;
|
|
@@ -48598,12 +49675,6 @@ var LiminaFlowReporter = class {
|
|
|
48598
49675
|
}
|
|
48599
49676
|
this.#renderTreeChange();
|
|
48600
49677
|
}
|
|
48601
|
-
#skipPlannedTreeDescendants(node) {
|
|
48602
|
-
for (const child of node.children) {
|
|
48603
|
-
if (child.status === "planned") child.status = "skipped";
|
|
48604
|
-
this.#skipPlannedTreeDescendants(child);
|
|
48605
|
-
}
|
|
48606
|
-
}
|
|
48607
49678
|
#renderTreeChange() {
|
|
48608
49679
|
if (!this.#interactive) return;
|
|
48609
49680
|
if (this.#processRenderer?.active) {
|
|
@@ -48613,13 +49684,6 @@ var LiminaFlowReporter = class {
|
|
|
48613
49684
|
this.#syncSpinnerTimer();
|
|
48614
49685
|
this.#redrawInteractiveHistory();
|
|
48615
49686
|
}
|
|
48616
|
-
#renderTreeLines() {
|
|
48617
|
-
return this.#treeRoots.flatMap((root) => this.#renderTreeNodeLines(root));
|
|
48618
|
-
}
|
|
48619
|
-
#renderTreeNodeLines(node) {
|
|
48620
|
-
const elapsedTimeMs = isTreeNodeTerminal(node) && areTreeNodeDescendantsTerminal(node) ? node.elapsedTimeMs : void 0;
|
|
48621
|
-
return [this.#formatInteractiveLine(toTreeFlowStatus(node.status), formatMessageWithElapsed(node.message, elapsedTimeMs), node.depth), ...node.children.flatMap((child) => this.#renderTreeNodeLines(child))];
|
|
48622
|
-
}
|
|
48623
49687
|
#hasRunningInteractiveWork() {
|
|
48624
49688
|
return hasRunningSnapshotWork(this.#createRenderSnapshot());
|
|
48625
49689
|
}
|
|
@@ -48646,7 +49710,7 @@ var LiminaFlowReporter = class {
|
|
|
48646
49710
|
this.#output.write(message);
|
|
48647
49711
|
}
|
|
48648
49712
|
#writeTracked(message, options = {}) {
|
|
48649
|
-
if (options.forceRecord || !this.#tracksProcessWrites) this.#
|
|
49713
|
+
if (options.forceRecord || !this.#tracksProcessWrites) this.#terminalFrame.record(message);
|
|
48650
49714
|
this.#output.write(message);
|
|
48651
49715
|
}
|
|
48652
49716
|
};
|
|
@@ -49549,10 +50613,10 @@ function parsePackageTool(tool) {
|
|
|
49549
50613
|
if (tool === "all" || tool === "publint" || tool === "attw" || tool === "boundary") return tool;
|
|
49550
50614
|
throw new Error(`Invalid package check --tool "${tool}". Expected one of: all, publint, attw, boundary.`);
|
|
49551
50615
|
}
|
|
49552
|
-
function parseBuildPreset(preset) {
|
|
50616
|
+
function parseBuildPreset(preset, commandLabel = "checker build") {
|
|
49553
50617
|
if (!preset) return;
|
|
49554
50618
|
if (preset === "tsc" || preset === "vue-tsc" || preset === "tsgo") return preset;
|
|
49555
|
-
throw new Error(`Invalid
|
|
50619
|
+
throw new Error(`Invalid ${commandLabel} --preset "${preset}". Expected one of: tsc, vue-tsc, tsgo.`);
|
|
49556
50620
|
}
|
|
49557
50621
|
function rejectUnknownCheckerOptions(flags) {
|
|
49558
50622
|
if (flags.checker !== void 0) throw new Error("Unknown option: --checker. Use --preset instead.");
|
|
@@ -49570,9 +50634,25 @@ function rejectUnknownCheckerOptions(flags) {
|
|
|
49570
50634
|
]);
|
|
49571
50635
|
for (const option of Object.keys(flags)) if (!knownOptions.has(option)) throw new Error(`Unknown option: --${option}.`);
|
|
49572
50636
|
}
|
|
50637
|
+
function rejectUnknownBuildOptions(flags) {
|
|
50638
|
+
const knownOptions = new Set([
|
|
50639
|
+
"--",
|
|
50640
|
+
"config",
|
|
50641
|
+
"mode",
|
|
50642
|
+
"preset",
|
|
50643
|
+
"raw",
|
|
50644
|
+
"verbose",
|
|
50645
|
+
"w",
|
|
50646
|
+
"watch"
|
|
50647
|
+
]);
|
|
50648
|
+
for (const option of Object.keys(flags)) if (!knownOptions.has(option)) throw new Error(`Unknown option: --${option}.`);
|
|
50649
|
+
}
|
|
49573
50650
|
function getCheckerWatchFlag(flags) {
|
|
49574
50651
|
return flags.watch ?? flags.w;
|
|
49575
50652
|
}
|
|
50653
|
+
function getBuildWatchFlag(flags) {
|
|
50654
|
+
return flags.watch ?? flags.w;
|
|
50655
|
+
}
|
|
49576
50656
|
function parsePackageAttwProfile(profile) {
|
|
49577
50657
|
if (!profile) return;
|
|
49578
50658
|
if (profile === "strict" || profile === "node16" || profile === "esm-only") return profile;
|
|
@@ -49937,6 +51017,35 @@ function createLiminaCli() {
|
|
|
49937
51017
|
if (!passed) process.exitCode = 1;
|
|
49938
51018
|
await closeCliFlow(flow, passed ? "limina source passed" : "limina source failed");
|
|
49939
51019
|
});
|
|
51020
|
+
cli.command("build <config>", "Build user-facing artifacts").option("--preset <preset>", "Build checker preset: tsc, vue-tsc, or tsgo").option("--raw", "Run the selected checker directly against the config").option("-w, --watch", "Watch input files and rebuild on changes").option("--verbose", "Show full build issue details").allowUnknownOptions().action(async (configPath, flags) => {
|
|
51021
|
+
rejectUnknownBuildOptions(flags);
|
|
51022
|
+
const watch = getBuildWatchFlag(flags);
|
|
51023
|
+
if (flags.raw && !flags.preset) throw new Error("limina build --raw requires --preset.");
|
|
51024
|
+
const checker = parseBuildPreset(flags.preset, "build");
|
|
51025
|
+
const flow = createCliFlow();
|
|
51026
|
+
flow.intro("limina build");
|
|
51027
|
+
const config = await load(flags, "build");
|
|
51028
|
+
await writeNotRunCheckIssueSnapshot({
|
|
51029
|
+
command: "limina build",
|
|
51030
|
+
rootDir: config.rootDir
|
|
51031
|
+
});
|
|
51032
|
+
const result = await runBuild({
|
|
51033
|
+
checker,
|
|
51034
|
+
clearScreen: false,
|
|
51035
|
+
config,
|
|
51036
|
+
configPath,
|
|
51037
|
+
cwd: process.cwd(),
|
|
51038
|
+
flow,
|
|
51039
|
+
raw: flags.raw,
|
|
51040
|
+
report: {
|
|
51041
|
+
command: "limina build",
|
|
51042
|
+
verbose: flags.verbose
|
|
51043
|
+
},
|
|
51044
|
+
watch
|
|
51045
|
+
});
|
|
51046
|
+
if (!result.passed) process.exitCode = 1;
|
|
51047
|
+
await closeCliFlow(flow, result.passed ? "limina build passed" : "limina build failed");
|
|
51048
|
+
});
|
|
49940
51049
|
cli.command("checker <action> [config]", "Run checker build or typecheck entries").option("--preset <preset>", "Build checker preset: tsc, vue-tsc, or tsgo").option("-w, --watch", "Watch input files and rebuild on changes").option("--verbose", "Show full checker issue details").allowUnknownOptions().action(async (action, configPath, flags) => {
|
|
49941
51050
|
rejectUnknownCheckerOptions(flags);
|
|
49942
51051
|
if (action !== "typecheck" && action !== "build") throw new Error(`Unknown checker action "${action}". Expected build or typecheck.`);
|
|
@@ -49951,19 +51060,12 @@ function createLiminaCli() {
|
|
|
49951
51060
|
command: "limina checker build",
|
|
49952
51061
|
rootDir: config.rootDir
|
|
49953
51062
|
});
|
|
49954
|
-
const result =
|
|
49955
|
-
|
|
49956
|
-
|
|
49957
|
-
|
|
49958
|
-
|
|
49959
|
-
|
|
49960
|
-
flow,
|
|
49961
|
-
report: {
|
|
49962
|
-
command: "limina checker build",
|
|
49963
|
-
verbose: flags.verbose
|
|
49964
|
-
},
|
|
49965
|
-
watch
|
|
49966
|
-
}) : await runCheckerBuild({
|
|
51063
|
+
const result = await runCheckerBuild({
|
|
51064
|
+
...configPath ? {
|
|
51065
|
+
checker: parseBuildPreset(flags.preset),
|
|
51066
|
+
configPath,
|
|
51067
|
+
watch
|
|
51068
|
+
} : {},
|
|
49967
51069
|
clearScreen: false,
|
|
49968
51070
|
config,
|
|
49969
51071
|
cwd: process.cwd(),
|