@nx/js 21.0.0-beta.0 → 21.0.0-beta.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/migrations.json +18 -0
- package/package.json +7 -8
- package/src/executors/node/node.impl.js +2 -2
- package/src/executors/release-publish/release-publish.impl.js +58 -17
- package/src/generators/init/files/ts-solution/tsconfig.base.json__tmpl__ +2 -1
- package/src/generators/init/init.js +1 -2
- package/src/generators/library/library.js +29 -135
- package/src/generators/library/utils/add-release-config.d.ts +11 -0
- package/src/generators/library/utils/add-release-config.js +150 -0
- package/src/generators/release-version/release-version.d.ts +1 -1
- package/src/generators/release-version/release-version.js +16 -14
- package/src/generators/release-version/schema.d.ts +1 -1
- package/src/generators/release-version/schema.json +23 -4
- package/src/generators/setup-build/generator.js +4 -0
- package/src/plugins/jest/start-local-registry.js +7 -3
- package/src/plugins/typescript/plugin.js +433 -211
- package/src/plugins/typescript/util.d.ts +9 -0
- package/src/plugins/typescript/util.js +74 -0
- package/src/release/utils/update-lock-file.d.ts +10 -0
- package/src/{generators/release-version → release}/utils/update-lock-file.js +12 -9
- package/src/release/version-actions.d.ts +22 -0
- package/src/release/version-actions.js +189 -0
- package/src/utils/assets/copy-assets-handler.js +11 -5
- package/src/utils/buildable-libs-utils.d.ts +0 -2
- package/src/utils/buildable-libs-utils.js +12 -42
- package/src/utils/find-npm-dependencies.d.ts +1 -0
- package/src/utils/find-npm-dependencies.js +12 -2
- package/src/utils/npm-config.js +1 -4
- package/src/utils/package-json/update-package-json.d.ts +1 -0
- package/src/utils/package-json/update-package-json.js +42 -1
- package/src/utils/package-manager-workspaces.d.ts +1 -0
- package/src/utils/package-manager-workspaces.js +12 -7
- package/src/utils/swc/add-swc-config.d.ts +1 -1
- package/src/utils/swc/add-swc-config.js +3 -3
- package/src/utils/typescript/plugin.d.ts +1 -1
- package/src/utils/typescript/plugin.js +27 -16
- package/src/utils/typescript/ts-solution-setup.d.ts +3 -2
- package/src/utils/typescript/ts-solution-setup.js +32 -9
- package/src/utils/versions.d.ts +2 -2
- package/src/utils/versions.js +2 -2
- package/src/generators/release-version/utils/update-lock-file.d.ts +0 -5
- package/src/utils/typescript/tsnode-register.d.ts +0 -1
- package/src/utils/typescript/tsnode-register.js +0 -23
|
@@ -3,23 +3,32 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.createNodes = exports.createNodesV2 = exports.PLUGIN_NAME = exports.createDependencies = void 0;
|
|
4
4
|
const devkit_1 = require("@nx/devkit");
|
|
5
5
|
const get_named_inputs_1 = require("@nx/devkit/src/utils/get-named-inputs");
|
|
6
|
-
const minimatch_1 = require("minimatch");
|
|
7
6
|
const node_fs_1 = require("node:fs");
|
|
8
7
|
const node_path_1 = require("node:path");
|
|
8
|
+
const posix = require("node:path/posix");
|
|
9
9
|
const file_hasher_1 = require("nx/src/hasher/file-hasher");
|
|
10
|
+
const picomatch = require("picomatch");
|
|
10
11
|
// eslint-disable-next-line @typescript-eslint/no-restricted-imports
|
|
11
12
|
const lock_file_1 = require("nx/src/plugins/js/lock-file/lock-file");
|
|
12
13
|
const cache_directory_1 = require("nx/src/utils/cache-directory");
|
|
13
|
-
const ts_config_1 = require("../../utils/typescript/ts-config");
|
|
14
14
|
const util_1 = require("./util");
|
|
15
|
+
let ts;
|
|
15
16
|
const pmc = (0, devkit_1.getPackageManagerCommand)();
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
17
|
+
let tsConfigCache;
|
|
18
|
+
const tsConfigCachePath = (0, node_path_1.join)(cache_directory_1.workspaceDataDirectory, 'tsconfig-files.hash');
|
|
19
|
+
let cache;
|
|
20
|
+
function readFromCache(cachePath) {
|
|
21
|
+
try {
|
|
22
|
+
return process.env.NX_CACHE_PROJECT_GRAPH !== 'false'
|
|
23
|
+
? (0, devkit_1.readJsonFile)(cachePath)
|
|
24
|
+
: {};
|
|
25
|
+
}
|
|
26
|
+
catch {
|
|
27
|
+
return {};
|
|
28
|
+
}
|
|
20
29
|
}
|
|
21
|
-
function
|
|
22
|
-
(0, devkit_1.writeJsonFile)(cachePath,
|
|
30
|
+
function writeToCache(cachePath, data) {
|
|
31
|
+
(0, devkit_1.writeJsonFile)(cachePath, data, { spaces: 0 });
|
|
23
32
|
}
|
|
24
33
|
/**
|
|
25
34
|
* @deprecated The 'createDependencies' function is now a no-op. This functionality is included in 'createNodesV2'.
|
|
@@ -34,15 +43,32 @@ exports.createNodesV2 = [
|
|
|
34
43
|
tsConfigGlob,
|
|
35
44
|
async (configFilePaths, options, context) => {
|
|
36
45
|
const optionsHash = (0, file_hasher_1.hashObject)(options);
|
|
37
|
-
const
|
|
38
|
-
const targetsCache =
|
|
46
|
+
const targetsCachePath = (0, node_path_1.join)(cache_directory_1.workspaceDataDirectory, `tsc-${optionsHash}.hash`);
|
|
47
|
+
const targetsCache = readFromCache(targetsCachePath);
|
|
48
|
+
cache = { fileHashes: {}, rawFiles: {}, isExternalProjectReference: {} };
|
|
49
|
+
initializeTsConfigCache(configFilePaths, context.workspaceRoot);
|
|
39
50
|
const normalizedOptions = normalizePluginOptions(options);
|
|
40
|
-
const
|
|
51
|
+
const { configFilePaths: validConfigFilePaths, hashes, projectRoots, } = await resolveValidConfigFilesAndHashes(configFilePaths, optionsHash, context);
|
|
41
52
|
try {
|
|
42
|
-
return await (0, devkit_1.createNodesFromFiles)((
|
|
53
|
+
return await (0, devkit_1.createNodesFromFiles)((configFilePath, options, context, idx) => {
|
|
54
|
+
const projectRoot = projectRoots[idx];
|
|
55
|
+
const hash = hashes[idx];
|
|
56
|
+
const cacheKey = `${hash}_${configFilePath}`;
|
|
57
|
+
targetsCache[cacheKey] ??= buildTscTargets((0, node_path_1.join)(context.workspaceRoot, configFilePath), projectRoot, options, context);
|
|
58
|
+
const { targets } = targetsCache[cacheKey];
|
|
59
|
+
return {
|
|
60
|
+
projects: {
|
|
61
|
+
[projectRoot]: {
|
|
62
|
+
projectType: 'library',
|
|
63
|
+
targets,
|
|
64
|
+
},
|
|
65
|
+
},
|
|
66
|
+
};
|
|
67
|
+
}, validConfigFilePaths, normalizedOptions, context);
|
|
43
68
|
}
|
|
44
69
|
finally {
|
|
45
|
-
|
|
70
|
+
writeToCache(targetsCachePath, targetsCache);
|
|
71
|
+
writeToCache(tsConfigCachePath, toRelativePaths(tsConfigCache, context.workspaceRoot));
|
|
46
72
|
}
|
|
47
73
|
},
|
|
48
74
|
];
|
|
@@ -50,28 +76,95 @@ exports.createNodes = [
|
|
|
50
76
|
tsConfigGlob,
|
|
51
77
|
async (configFilePath, options, context) => {
|
|
52
78
|
devkit_1.logger.warn('`createNodes` is deprecated. Update your plugin to utilize createNodesV2 instead. In Nx 20, this will change to the createNodesV2 API.');
|
|
79
|
+
const projectRoot = (0, node_path_1.dirname)(configFilePath);
|
|
80
|
+
if (!checkIfConfigFileShouldBeProject(configFilePath, projectRoot, context)) {
|
|
81
|
+
return {};
|
|
82
|
+
}
|
|
53
83
|
const normalizedOptions = normalizePluginOptions(options);
|
|
54
|
-
|
|
55
|
-
|
|
84
|
+
cache = { fileHashes: {}, rawFiles: {}, isExternalProjectReference: {} };
|
|
85
|
+
initializeTsConfigCache([configFilePath], context.workspaceRoot);
|
|
86
|
+
const { targets } = buildTscTargets((0, node_path_1.join)(context.workspaceRoot, configFilePath), projectRoot, normalizedOptions, context);
|
|
87
|
+
writeToCache(tsConfigCachePath, toRelativePaths(tsConfigCache, context.workspaceRoot));
|
|
88
|
+
return {
|
|
89
|
+
projects: {
|
|
90
|
+
[projectRoot]: {
|
|
91
|
+
projectType: 'library',
|
|
92
|
+
targets,
|
|
93
|
+
},
|
|
94
|
+
},
|
|
95
|
+
};
|
|
56
96
|
},
|
|
57
97
|
];
|
|
58
|
-
async function
|
|
59
|
-
const
|
|
60
|
-
const
|
|
98
|
+
async function resolveValidConfigFilesAndHashes(configFilePaths, optionsHash, context) {
|
|
99
|
+
const lockFileHash = (0, file_hasher_1.hashFile)((0, node_path_1.join)(context.workspaceRoot, (0, lock_file_1.getLockFileName)((0, devkit_1.detectPackageManager)(context.workspaceRoot)))) ?? '';
|
|
100
|
+
const validConfigFilePaths = [];
|
|
101
|
+
const hashes = [];
|
|
102
|
+
const projectRoots = [];
|
|
103
|
+
for await (const configFilePath of configFilePaths) {
|
|
104
|
+
const projectRoot = (0, node_path_1.dirname)(configFilePath);
|
|
105
|
+
if (!checkIfConfigFileShouldBeProject(configFilePath, projectRoot, context)) {
|
|
106
|
+
continue;
|
|
107
|
+
}
|
|
108
|
+
projectRoots.push(projectRoot);
|
|
109
|
+
validConfigFilePaths.push(configFilePath);
|
|
110
|
+
hashes.push(await getConfigFileHash(configFilePath, context.workspaceRoot, projectRoot, optionsHash, lockFileHash));
|
|
111
|
+
}
|
|
112
|
+
return { configFilePaths: validConfigFilePaths, hashes, projectRoots };
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* The cache key is composed by:
|
|
116
|
+
* - hashes of the content of the relevant files that can affect what's inferred by the plugin:
|
|
117
|
+
* - current config file
|
|
118
|
+
* - config files extended by the current config file (recursively up to the root config file)
|
|
119
|
+
* - referenced config files that are internal to the owning Nx project of the current config file,
|
|
120
|
+
* or is a shallow external reference of the owning Nx project
|
|
121
|
+
* - lock file
|
|
122
|
+
* - project's package.json
|
|
123
|
+
* - hash of the plugin options
|
|
124
|
+
* - current config file path
|
|
125
|
+
*/
|
|
126
|
+
async function getConfigFileHash(configFilePath, workspaceRoot, projectRoot, optionsHash, lockFileHash) {
|
|
127
|
+
const fullConfigPath = (0, node_path_1.join)(workspaceRoot, configFilePath);
|
|
128
|
+
const tsConfig = retrieveTsConfigFromCache(fullConfigPath, workspaceRoot);
|
|
129
|
+
const extendedConfigFiles = getExtendedConfigFiles(tsConfig, workspaceRoot);
|
|
130
|
+
const internalReferencedFiles = resolveInternalProjectReferences(tsConfig, workspaceRoot, projectRoot);
|
|
131
|
+
const externalProjectReferences = resolveShallowExternalProjectReferences(tsConfig, workspaceRoot, projectRoot);
|
|
132
|
+
let packageJson = null;
|
|
133
|
+
try {
|
|
134
|
+
packageJson = (0, devkit_1.readJsonFile)((0, node_path_1.join)(workspaceRoot, projectRoot, 'package.json'));
|
|
135
|
+
}
|
|
136
|
+
catch { }
|
|
137
|
+
return (0, file_hasher_1.hashArray)([
|
|
138
|
+
...[
|
|
139
|
+
fullConfigPath,
|
|
140
|
+
...extendedConfigFiles.files.sort(),
|
|
141
|
+
...Object.keys(internalReferencedFiles).sort(),
|
|
142
|
+
...Object.keys(externalProjectReferences).sort(),
|
|
143
|
+
].map((file) => getFileHash(file, workspaceRoot)),
|
|
144
|
+
...extendedConfigFiles.packages.sort(),
|
|
145
|
+
lockFileHash,
|
|
146
|
+
optionsHash,
|
|
147
|
+
...(packageJson ? [(0, file_hasher_1.hashObject)(packageJson)] : []),
|
|
148
|
+
// change this to bust the cache when making changes that would yield
|
|
149
|
+
// different results for the same hash
|
|
150
|
+
(0, file_hasher_1.hashObject)({ bust: 2 }),
|
|
151
|
+
]);
|
|
152
|
+
}
|
|
153
|
+
function checkIfConfigFileShouldBeProject(configFilePath, projectRoot, context) {
|
|
61
154
|
// Do not create a project for the workspace root tsconfig files.
|
|
62
155
|
if (projectRoot === '.') {
|
|
63
|
-
return
|
|
156
|
+
return false;
|
|
64
157
|
}
|
|
65
158
|
// Do not create a project if package.json and project.json isn't there.
|
|
66
159
|
const siblingFiles = (0, node_fs_1.readdirSync)((0, node_path_1.join)(context.workspaceRoot, projectRoot));
|
|
67
160
|
if (!siblingFiles.includes('package.json') &&
|
|
68
161
|
!siblingFiles.includes('project.json')) {
|
|
69
|
-
return
|
|
162
|
+
return false;
|
|
70
163
|
}
|
|
71
164
|
// Do not create a project if it's not a tsconfig.json and there is no tsconfig.json in the same directory
|
|
72
165
|
if ((0, node_path_1.basename)(configFilePath) !== 'tsconfig.json' &&
|
|
73
166
|
!siblingFiles.includes('tsconfig.json')) {
|
|
74
|
-
return
|
|
167
|
+
return false;
|
|
75
168
|
}
|
|
76
169
|
// Do not create project for Next.js projects since they are not compatible with
|
|
77
170
|
// project references and typecheck will fail.
|
|
@@ -79,56 +172,19 @@ async function createNodesInternal(configFilePath, options, context, lockFileNam
|
|
|
79
172
|
siblingFiles.includes('next.config.cjs') ||
|
|
80
173
|
siblingFiles.includes('next.config.mjs') ||
|
|
81
174
|
siblingFiles.includes('next.config.ts')) {
|
|
82
|
-
return
|
|
175
|
+
return false;
|
|
83
176
|
}
|
|
84
|
-
|
|
85
|
-
* The cache key is composed by:
|
|
86
|
-
* - hashes of the content of the relevant files that can affect what's inferred by the plugin:
|
|
87
|
-
* - current config file
|
|
88
|
-
* - config files extended by the current config file (recursively up to the root config file)
|
|
89
|
-
* - referenced config files that are internal to the owning Nx project of the current config file, or is a shallow external reference of the owning Nx project
|
|
90
|
-
* - lock file
|
|
91
|
-
* - hash of the plugin options
|
|
92
|
-
* - current config file path
|
|
93
|
-
*/
|
|
94
|
-
const tsConfig = readCachedTsConfig(fullConfigPath);
|
|
95
|
-
const extendedConfigFiles = getExtendedConfigFiles(fullConfigPath, tsConfig);
|
|
96
|
-
const internalReferencedFiles = resolveInternalProjectReferences(tsConfig, context.workspaceRoot, projectRoot);
|
|
97
|
-
const externalProjectReferences = resolveShallowExternalProjectReferences(tsConfig, context.workspaceRoot, projectRoot);
|
|
98
|
-
const packageJsonPath = (0, devkit_1.joinPathFragments)(projectRoot, 'package.json');
|
|
99
|
-
const packageJson = (0, node_fs_1.existsSync)(packageJsonPath)
|
|
100
|
-
? (0, devkit_1.readJsonFile)(packageJsonPath)
|
|
101
|
-
: null;
|
|
102
|
-
const nodeHash = (0, file_hasher_1.hashArray)([
|
|
103
|
-
...[
|
|
104
|
-
fullConfigPath,
|
|
105
|
-
...extendedConfigFiles.files,
|
|
106
|
-
...Object.keys(internalReferencedFiles),
|
|
107
|
-
...Object.keys(externalProjectReferences),
|
|
108
|
-
(0, node_path_1.join)(context.workspaceRoot, lockFileName),
|
|
109
|
-
].map(file_hasher_1.hashFile),
|
|
110
|
-
(0, file_hasher_1.hashObject)(options),
|
|
111
|
-
...(packageJson ? [(0, file_hasher_1.hashObject)(packageJson)] : []),
|
|
112
|
-
]);
|
|
113
|
-
const cacheKey = `${nodeHash}_${configFilePath}`;
|
|
114
|
-
targetsCache[cacheKey] ??= buildTscTargets(fullConfigPath, projectRoot, options, context);
|
|
115
|
-
const { targets } = targetsCache[cacheKey];
|
|
116
|
-
return {
|
|
117
|
-
projects: {
|
|
118
|
-
[projectRoot]: {
|
|
119
|
-
projectType: 'library',
|
|
120
|
-
targets,
|
|
121
|
-
},
|
|
122
|
-
},
|
|
123
|
-
};
|
|
177
|
+
return true;
|
|
124
178
|
}
|
|
125
179
|
function buildTscTargets(configFilePath, projectRoot, options, context) {
|
|
126
180
|
const targets = {};
|
|
127
181
|
const namedInputs = (0, get_named_inputs_1.getNamedInputs)(projectRoot, context);
|
|
128
|
-
const tsConfig =
|
|
182
|
+
const tsConfig = retrieveTsConfigFromCache(configFilePath, context.workspaceRoot);
|
|
129
183
|
let internalProjectReferences;
|
|
130
184
|
// Typecheck target
|
|
131
|
-
if ((0, node_path_1.basename)(configFilePath) === 'tsconfig.json' &&
|
|
185
|
+
if ((0, node_path_1.basename)(configFilePath) === 'tsconfig.json' &&
|
|
186
|
+
options.typecheck &&
|
|
187
|
+
tsConfig.raw?.['nx']?.addTypecheckTarget !== false) {
|
|
132
188
|
internalProjectReferences = resolveInternalProjectReferences(tsConfig, context.workspaceRoot, projectRoot);
|
|
133
189
|
const externalProjectReferences = resolveShallowExternalProjectReferences(tsConfig, context.workspaceRoot, projectRoot);
|
|
134
190
|
const targetName = options.typecheck.targetName;
|
|
@@ -140,13 +196,27 @@ function buildTscTargets(configFilePath, projectRoot, options, context) {
|
|
|
140
196
|
// `tsc --build` does not work with `noEmit: true`
|
|
141
197
|
command = `echo "The 'typecheck' target is disabled because one or more project references set 'noEmit: true' in their tsconfig. Remove this property to resolve this issue."`;
|
|
142
198
|
}
|
|
199
|
+
const dependsOn = [`^${targetName}`];
|
|
200
|
+
if (options.build && targets[options.build.targetName]) {
|
|
201
|
+
// we already processed and have a build target
|
|
202
|
+
dependsOn.unshift(options.build.targetName);
|
|
203
|
+
}
|
|
204
|
+
else if (options.build) {
|
|
205
|
+
// check if the project will have a build target
|
|
206
|
+
const buildConfigPath = (0, devkit_1.joinPathFragments)(projectRoot, options.build.configName);
|
|
207
|
+
if (context.configFiles.some((f) => f === buildConfigPath) &&
|
|
208
|
+
(0, util_1.isValidPackageJsonBuildConfig)(retrieveTsConfigFromCache(buildConfigPath, context.workspaceRoot), context.workspaceRoot, projectRoot)) {
|
|
209
|
+
dependsOn.unshift(options.build.targetName);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
143
212
|
targets[targetName] = {
|
|
144
|
-
dependsOn
|
|
213
|
+
dependsOn,
|
|
145
214
|
command,
|
|
146
215
|
options: { cwd: projectRoot },
|
|
147
216
|
cache: true,
|
|
148
217
|
inputs: getInputs(namedInputs, configFilePath, tsConfig, internalProjectReferences, context.workspaceRoot, projectRoot),
|
|
149
|
-
outputs: getOutputs(configFilePath, tsConfig, internalProjectReferences, context.workspaceRoot, projectRoot
|
|
218
|
+
outputs: getOutputs(configFilePath, tsConfig, internalProjectReferences, context.workspaceRoot, projectRoot,
|
|
219
|
+
/* emitDeclarationOnly */ true),
|
|
150
220
|
syncGenerators: ['@nx/js:typescript-sync'],
|
|
151
221
|
metadata: {
|
|
152
222
|
technologies: ['typescript'],
|
|
@@ -164,7 +234,7 @@ function buildTscTargets(configFilePath, projectRoot, options, context) {
|
|
|
164
234
|
// Build target
|
|
165
235
|
if (options.build &&
|
|
166
236
|
(0, node_path_1.basename)(configFilePath) === options.build.configName &&
|
|
167
|
-
isValidPackageJsonBuildConfig(tsConfig, context.workspaceRoot, projectRoot)) {
|
|
237
|
+
(0, util_1.isValidPackageJsonBuildConfig)(tsConfig, context.workspaceRoot, projectRoot)) {
|
|
168
238
|
internalProjectReferences ??= resolveInternalProjectReferences(tsConfig, context.workspaceRoot, projectRoot);
|
|
169
239
|
const targetName = options.build.targetName;
|
|
170
240
|
targets[targetName] = {
|
|
@@ -173,7 +243,9 @@ function buildTscTargets(configFilePath, projectRoot, options, context) {
|
|
|
173
243
|
options: { cwd: projectRoot },
|
|
174
244
|
cache: true,
|
|
175
245
|
inputs: getInputs(namedInputs, configFilePath, tsConfig, internalProjectReferences, context.workspaceRoot, projectRoot),
|
|
176
|
-
outputs: getOutputs(configFilePath, tsConfig, internalProjectReferences, context.workspaceRoot, projectRoot
|
|
246
|
+
outputs: getOutputs(configFilePath, tsConfig, internalProjectReferences, context.workspaceRoot, projectRoot,
|
|
247
|
+
// should be false for build target, but providing it just in case is set to true
|
|
248
|
+
tsConfig.options.emitDeclarationOnly),
|
|
177
249
|
syncGenerators: ['@nx/js:typescript-sync'],
|
|
178
250
|
metadata: {
|
|
179
251
|
technologies: ['typescript'],
|
|
@@ -196,7 +268,7 @@ function buildTscTargets(configFilePath, projectRoot, options, context) {
|
|
|
196
268
|
function getInputs(namedInputs, configFilePath, tsConfig, internalProjectReferences, workspaceRoot, projectRoot) {
|
|
197
269
|
const configFiles = new Set();
|
|
198
270
|
const externalDependencies = ['typescript'];
|
|
199
|
-
const extendedConfigFiles = getExtendedConfigFiles(
|
|
271
|
+
const extendedConfigFiles = getExtendedConfigFiles(tsConfig, workspaceRoot);
|
|
200
272
|
extendedConfigFiles.files.forEach((configPath) => {
|
|
201
273
|
configFiles.add(configPath);
|
|
202
274
|
});
|
|
@@ -208,10 +280,57 @@ function getInputs(namedInputs, configFilePath, tsConfig, internalProjectReferen
|
|
|
208
280
|
...Object.entries(internalProjectReferences),
|
|
209
281
|
];
|
|
210
282
|
const absoluteProjectRoot = (0, node_path_1.join)(workspaceRoot, projectRoot);
|
|
283
|
+
if (!ts) {
|
|
284
|
+
ts = require('typescript');
|
|
285
|
+
}
|
|
286
|
+
// https://github.com/microsoft/TypeScript/blob/19b777260b26aac5707b1efd34202054164d4a9d/src/compiler/utilities.ts#L9869
|
|
287
|
+
const supportedTSExtensions = [
|
|
288
|
+
ts.Extension.Ts,
|
|
289
|
+
ts.Extension.Tsx,
|
|
290
|
+
ts.Extension.Dts,
|
|
291
|
+
ts.Extension.Cts,
|
|
292
|
+
ts.Extension.Dcts,
|
|
293
|
+
ts.Extension.Mts,
|
|
294
|
+
ts.Extension.Dmts,
|
|
295
|
+
];
|
|
296
|
+
// https://github.com/microsoft/TypeScript/blob/19b777260b26aac5707b1efd34202054164d4a9d/src/compiler/utilities.ts#L9878
|
|
297
|
+
const allSupportedExtensions = [
|
|
298
|
+
ts.Extension.Ts,
|
|
299
|
+
ts.Extension.Tsx,
|
|
300
|
+
ts.Extension.Dts,
|
|
301
|
+
ts.Extension.Js,
|
|
302
|
+
ts.Extension.Jsx,
|
|
303
|
+
ts.Extension.Cts,
|
|
304
|
+
ts.Extension.Dcts,
|
|
305
|
+
ts.Extension.Cjs,
|
|
306
|
+
ts.Extension.Mts,
|
|
307
|
+
ts.Extension.Dmts,
|
|
308
|
+
ts.Extension.Mjs,
|
|
309
|
+
];
|
|
310
|
+
const normalizeInput = (input, config) => {
|
|
311
|
+
const extensions = config.options.allowJs
|
|
312
|
+
? [...allSupportedExtensions]
|
|
313
|
+
: [...supportedTSExtensions];
|
|
314
|
+
if (config.options.resolveJsonModule) {
|
|
315
|
+
extensions.push(ts.Extension.Json);
|
|
316
|
+
}
|
|
317
|
+
const segments = input.split('/');
|
|
318
|
+
// An "includes" path "foo" is implicitly a glob "foo/**/*" if its last
|
|
319
|
+
// segment has no extension, and does not contain any glob characters
|
|
320
|
+
// itself.
|
|
321
|
+
// https://github.com/microsoft/TypeScript/blob/19b777260b26aac5707b1efd34202054164d4a9d/src/compiler/utilities.ts#L9577-L9585
|
|
322
|
+
if (!/[.*?]/.test(segments.at(-1))) {
|
|
323
|
+
return extensions.map((ext) => `${segments.join('/')}/**/*${ext}`);
|
|
324
|
+
}
|
|
325
|
+
return [input];
|
|
326
|
+
};
|
|
211
327
|
projectTsConfigFiles.forEach(([configPath, config]) => {
|
|
212
328
|
configFiles.add(configPath);
|
|
213
329
|
const offset = (0, node_path_1.relative)(absoluteProjectRoot, (0, node_path_1.dirname)(configPath));
|
|
214
|
-
(config.raw?.include ?? []).forEach((p) =>
|
|
330
|
+
(config.raw?.include ?? []).forEach((p) => {
|
|
331
|
+
const normalized = normalizeInput((0, node_path_1.join)(offset, p), config);
|
|
332
|
+
normalized.forEach((input) => includePaths.add(input));
|
|
333
|
+
});
|
|
215
334
|
if (config.raw?.exclude) {
|
|
216
335
|
/**
|
|
217
336
|
* We need to filter out the exclude paths that are already included in
|
|
@@ -226,8 +345,8 @@ function getInputs(namedInputs, configFilePath, tsConfig, internalProjectReferen
|
|
|
226
345
|
});
|
|
227
346
|
const normalize = (p) => (p.startsWith('./') ? p.slice(2) : p);
|
|
228
347
|
config.raw.exclude.forEach((excludePath) => {
|
|
229
|
-
if (!otherFilesInclude.some((includePath) => (
|
|
230
|
-
(
|
|
348
|
+
if (!otherFilesInclude.some((includePath) => picomatch(normalize(excludePath))(normalize(includePath)) ||
|
|
349
|
+
picomatch(normalize(includePath))(normalize(excludePath)))) {
|
|
231
350
|
excludePaths.add(excludePath);
|
|
232
351
|
}
|
|
233
352
|
});
|
|
@@ -259,7 +378,7 @@ function getInputs(namedInputs, configFilePath, tsConfig, internalProjectReferen
|
|
|
259
378
|
inputs.push({ externalDependencies });
|
|
260
379
|
return inputs;
|
|
261
380
|
}
|
|
262
|
-
function getOutputs(configFilePath, tsConfig, internalProjectReferences, workspaceRoot, projectRoot) {
|
|
381
|
+
function getOutputs(configFilePath, tsConfig, internalProjectReferences, workspaceRoot, projectRoot, emitDeclarationOnly) {
|
|
263
382
|
const outputs = new Set();
|
|
264
383
|
// We could have more surgical outputs based on the tsconfig options, but the
|
|
265
384
|
// user could override them through the command line and that wouldn't be
|
|
@@ -281,9 +400,18 @@ function getOutputs(configFilePath, tsConfig, internalProjectReferences, workspa
|
|
|
281
400
|
: pathToInputOrOutput((0, devkit_1.joinPathFragments)(outDir, `${outFileName}.tsbuildinfo`), workspaceRoot, projectRoot));
|
|
282
401
|
}
|
|
283
402
|
else if (config.options.outDir) {
|
|
284
|
-
|
|
403
|
+
if (emitDeclarationOnly) {
|
|
404
|
+
outputs.add(pathToInputOrOutput((0, devkit_1.joinPathFragments)(config.options.outDir, '**/*.d.ts'), workspaceRoot, projectRoot));
|
|
405
|
+
if (tsConfig.options.declarationMap) {
|
|
406
|
+
outputs.add(pathToInputOrOutput((0, devkit_1.joinPathFragments)(config.options.outDir, '**/*.d.ts.map'), workspaceRoot, projectRoot));
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
else {
|
|
410
|
+
outputs.add(pathToInputOrOutput(config.options.outDir, workspaceRoot, projectRoot));
|
|
411
|
+
}
|
|
285
412
|
if (config.options.tsBuildInfoFile) {
|
|
286
|
-
if (
|
|
413
|
+
if (emitDeclarationOnly ||
|
|
414
|
+
!(0, node_path_1.normalize)(config.options.tsBuildInfoFile).startsWith(`${(0, node_path_1.normalize)(config.options.outDir)}${node_path_1.sep}`)) {
|
|
287
415
|
// https://www.typescriptlang.org/tsconfig#tsBuildInfoFile
|
|
288
416
|
outputs.add(pathToInputOrOutput(config.options.tsBuildInfoFile, workspaceRoot, projectRoot));
|
|
289
417
|
}
|
|
@@ -293,8 +421,15 @@ function getOutputs(configFilePath, tsConfig, internalProjectReferences, workspa
|
|
|
293
421
|
const relativeRootDir = (0, node_path_1.relative)(config.options.rootDir, (0, node_path_1.join)(workspaceRoot, projectRoot));
|
|
294
422
|
outputs.add(pathToInputOrOutput((0, devkit_1.joinPathFragments)(config.options.outDir, relativeRootDir, `*.tsbuildinfo`), workspaceRoot, projectRoot));
|
|
295
423
|
}
|
|
424
|
+
else if (emitDeclarationOnly) {
|
|
425
|
+
// https://www.typescriptlang.org/tsconfig#tsBuildInfoFile
|
|
426
|
+
const name = (0, node_path_1.basename)(configFilePath, '.json');
|
|
427
|
+
outputs.add(pathToInputOrOutput((0, devkit_1.joinPathFragments)(config.options.outDir, `${name}.tsbuildinfo`), workspaceRoot, projectRoot));
|
|
428
|
+
}
|
|
296
429
|
}
|
|
297
|
-
else if (config.
|
|
430
|
+
else if (config.raw?.include?.length ||
|
|
431
|
+
config.raw?.files?.length ||
|
|
432
|
+
(!config.raw?.include && !config.raw?.files)) {
|
|
298
433
|
// tsc produce files in place when no outDir or outFile is set
|
|
299
434
|
outputs.add((0, devkit_1.joinPathFragments)('{projectRoot}', '**/*.js'));
|
|
300
435
|
outputs.add((0, devkit_1.joinPathFragments)('{projectRoot}', '**/*.cjs'));
|
|
@@ -317,87 +452,6 @@ function getOutputs(configFilePath, tsConfig, internalProjectReferences, workspa
|
|
|
317
452
|
});
|
|
318
453
|
return Array.from(outputs);
|
|
319
454
|
}
|
|
320
|
-
/**
|
|
321
|
-
* Validates the build configuration of a `package.json` file by ensuring that paths in the `exports`, `module`,
|
|
322
|
-
* and `main` fields reference valid output paths within the `outDir` defined in the TypeScript configuration.
|
|
323
|
-
* Priority is given to the `exports` field, specifically the `.` export if defined. If `exports` is not defined,
|
|
324
|
-
* the function falls back to validating `main` and `module` fields. If `outFile` is specified, it validates that the file
|
|
325
|
-
* is located within the output directory.
|
|
326
|
-
* If no `package.json` file exists, it assumes the configuration is valid.
|
|
327
|
-
*
|
|
328
|
-
* @param tsConfig The TypeScript configuration object.
|
|
329
|
-
* @param workspaceRoot The workspace root path.
|
|
330
|
-
* @param projectRoot The project root path.
|
|
331
|
-
* @returns `true` if the package has a valid build configuration; otherwise, `false`.
|
|
332
|
-
*/
|
|
333
|
-
function isValidPackageJsonBuildConfig(tsConfig, workspaceRoot, projectRoot) {
|
|
334
|
-
const packageJsonPath = (0, node_path_1.join)(workspaceRoot, projectRoot, 'package.json');
|
|
335
|
-
if (!(0, node_fs_1.existsSync)(packageJsonPath)) {
|
|
336
|
-
// If the package.json file does not exist.
|
|
337
|
-
// Assume it's valid because it would be using `project.json` instead.
|
|
338
|
-
return true;
|
|
339
|
-
}
|
|
340
|
-
const packageJson = (0, devkit_1.readJsonFile)(packageJsonPath);
|
|
341
|
-
const outDir = tsConfig.options.outFile
|
|
342
|
-
? (0, node_path_1.dirname)(tsConfig.options.outFile)
|
|
343
|
-
: tsConfig.options.outDir;
|
|
344
|
-
const resolvedOutDir = outDir
|
|
345
|
-
? (0, node_path_1.resolve)(workspaceRoot, projectRoot, outDir)
|
|
346
|
-
: undefined;
|
|
347
|
-
const isPathSourceFile = (path) => {
|
|
348
|
-
if (resolvedOutDir) {
|
|
349
|
-
const pathToCheck = (0, node_path_1.resolve)(workspaceRoot, projectRoot, path);
|
|
350
|
-
return !pathToCheck.startsWith(resolvedOutDir);
|
|
351
|
-
}
|
|
352
|
-
const ext = (0, node_path_1.extname)(path);
|
|
353
|
-
// Check that the file extension is a TS file extension. As the source files are in the same directory as the output files.
|
|
354
|
-
return ['.ts', '.tsx', '.cts', '.mts'].includes(ext);
|
|
355
|
-
};
|
|
356
|
-
// Checks if the value is a path within the `src` directory.
|
|
357
|
-
const containsInvalidPath = (value) => {
|
|
358
|
-
if (typeof value === 'string') {
|
|
359
|
-
return isPathSourceFile(value);
|
|
360
|
-
}
|
|
361
|
-
else if (typeof value === 'object') {
|
|
362
|
-
return Object.entries(value).some(([currentKey, subValue]) => {
|
|
363
|
-
// Skip types field
|
|
364
|
-
if (currentKey === 'types') {
|
|
365
|
-
return false;
|
|
366
|
-
}
|
|
367
|
-
if (typeof subValue === 'string') {
|
|
368
|
-
return isPathSourceFile(subValue);
|
|
369
|
-
}
|
|
370
|
-
return false;
|
|
371
|
-
});
|
|
372
|
-
}
|
|
373
|
-
return false;
|
|
374
|
-
};
|
|
375
|
-
const exports = packageJson?.exports;
|
|
376
|
-
// Check the `.` export if `exports` is defined.
|
|
377
|
-
if (exports) {
|
|
378
|
-
if (typeof exports === 'string') {
|
|
379
|
-
return !isPathSourceFile(exports);
|
|
380
|
-
}
|
|
381
|
-
if (typeof exports === 'object' && '.' in exports) {
|
|
382
|
-
return !containsInvalidPath(exports['.']);
|
|
383
|
-
}
|
|
384
|
-
// Check other exports if `.` is not defined or valid.
|
|
385
|
-
for (const key in exports) {
|
|
386
|
-
if (key !== '.' && containsInvalidPath(exports[key])) {
|
|
387
|
-
return false;
|
|
388
|
-
}
|
|
389
|
-
}
|
|
390
|
-
return true;
|
|
391
|
-
}
|
|
392
|
-
// If `exports` is not defined, fallback to `main` and `module` fields.
|
|
393
|
-
const buildPaths = ['main', 'module'];
|
|
394
|
-
for (const field of buildPaths) {
|
|
395
|
-
if (packageJson[field] && isPathSourceFile(packageJson[field])) {
|
|
396
|
-
return false;
|
|
397
|
-
}
|
|
398
|
-
}
|
|
399
|
-
return true;
|
|
400
|
-
}
|
|
401
455
|
function pathToInputOrOutput(path, workspaceRoot, projectRoot) {
|
|
402
456
|
const fullProjectRoot = (0, node_path_1.resolve)(workspaceRoot, projectRoot);
|
|
403
457
|
const fullPath = (0, node_path_1.resolve)(workspaceRoot, path);
|
|
@@ -407,23 +461,15 @@ function pathToInputOrOutput(path, workspaceRoot, projectRoot) {
|
|
|
407
461
|
}
|
|
408
462
|
return (0, devkit_1.joinPathFragments)('{projectRoot}', pathRelativeToProjectRoot);
|
|
409
463
|
}
|
|
410
|
-
function getExtendedConfigFiles(
|
|
411
|
-
const
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
}
|
|
420
|
-
if (extendedConfigPath.externalPackage) {
|
|
421
|
-
extendedExternalPackages.add(extendedConfigPath.externalPackage);
|
|
422
|
-
break;
|
|
423
|
-
}
|
|
424
|
-
extendedConfigFiles.add(extendedConfigPath.filePath);
|
|
425
|
-
currentConfig = readCachedTsConfig(extendedConfigPath.filePath);
|
|
426
|
-
currentConfigPath = extendedConfigPath.filePath;
|
|
464
|
+
function getExtendedConfigFiles(tsConfig, workspaceRoot, extendedConfigFiles = new Set(), extendedExternalPackages = new Set()) {
|
|
465
|
+
for (const extendedConfigFile of tsConfig.extendedConfigFiles) {
|
|
466
|
+
if (extendedConfigFile.externalPackage) {
|
|
467
|
+
extendedExternalPackages.add(extendedConfigFile.externalPackage);
|
|
468
|
+
}
|
|
469
|
+
else if (extendedConfigFile.filePath) {
|
|
470
|
+
extendedConfigFiles.add(extendedConfigFile.filePath);
|
|
471
|
+
getExtendedConfigFiles(retrieveTsConfigFromCache(extendedConfigFile.filePath, workspaceRoot), workspaceRoot, extendedConfigFiles, extendedExternalPackages);
|
|
472
|
+
}
|
|
427
473
|
}
|
|
428
474
|
return {
|
|
429
475
|
files: Array.from(extendedConfigFiles),
|
|
@@ -431,27 +477,31 @@ function getExtendedConfigFiles(tsConfigPath, tsConfig) {
|
|
|
431
477
|
};
|
|
432
478
|
}
|
|
433
479
|
function resolveInternalProjectReferences(tsConfig, workspaceRoot, projectRoot, projectReferences = {}) {
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
480
|
+
if (!tsConfig.projectReferences?.length) {
|
|
481
|
+
return {};
|
|
482
|
+
}
|
|
483
|
+
for (const ref of tsConfig.projectReferences) {
|
|
484
|
+
let refConfigPath = ref.path;
|
|
485
|
+
if (projectReferences[refConfigPath]) {
|
|
486
|
+
// Already resolved
|
|
487
|
+
continue;
|
|
437
488
|
}
|
|
438
|
-
|
|
439
|
-
|
|
489
|
+
if (!(0, node_fs_1.existsSync)(refConfigPath)) {
|
|
490
|
+
// the referenced tsconfig doesn't exist, ignore it
|
|
491
|
+
continue;
|
|
440
492
|
}
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
}
|
|
444
|
-
function resolveShallowExternalProjectReferences(tsConfig, workspaceRoot, projectRoot, projectReferences = {}) {
|
|
445
|
-
walkProjectReferences(tsConfig, workspaceRoot, projectRoot, (configPath, config) => {
|
|
446
|
-
if (isExternalProjectReference(configPath, workspaceRoot, projectRoot)) {
|
|
447
|
-
projectReferences[configPath] = config;
|
|
493
|
+
if (isExternalProjectReference(refConfigPath, workspaceRoot, projectRoot)) {
|
|
494
|
+
continue;
|
|
448
495
|
}
|
|
449
|
-
|
|
450
|
-
|
|
496
|
+
if (!refConfigPath.endsWith('.json')) {
|
|
497
|
+
refConfigPath = (0, node_path_1.join)(refConfigPath, 'tsconfig.json');
|
|
498
|
+
}
|
|
499
|
+
projectReferences[refConfigPath] = retrieveTsConfigFromCache(refConfigPath, workspaceRoot);
|
|
500
|
+
resolveInternalProjectReferences(projectReferences[refConfigPath], workspaceRoot, projectRoot, projectReferences);
|
|
501
|
+
}
|
|
451
502
|
return projectReferences;
|
|
452
503
|
}
|
|
453
|
-
function
|
|
454
|
-
projectReferences = {}) {
|
|
504
|
+
function resolveShallowExternalProjectReferences(tsConfig, workspaceRoot, projectRoot, projectReferences = {}) {
|
|
455
505
|
if (!tsConfig.projectReferences?.length) {
|
|
456
506
|
return projectReferences;
|
|
457
507
|
}
|
|
@@ -465,13 +515,11 @@ projectReferences = {}) {
|
|
|
465
515
|
// the referenced tsconfig doesn't exist, ignore it
|
|
466
516
|
continue;
|
|
467
517
|
}
|
|
468
|
-
if (
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
if (result !== false) {
|
|
474
|
-
walkProjectReferences(refTsConfig, workspaceRoot, projectRoot, visitor);
|
|
518
|
+
if (isExternalProjectReference(refConfigPath, workspaceRoot, projectRoot)) {
|
|
519
|
+
if (!refConfigPath.endsWith('.json')) {
|
|
520
|
+
refConfigPath = (0, node_path_1.join)(refConfigPath, 'tsconfig.json');
|
|
521
|
+
}
|
|
522
|
+
projectReferences[refConfigPath] = retrieveTsConfigFromCache(refConfigPath, workspaceRoot);
|
|
475
523
|
}
|
|
476
524
|
}
|
|
477
525
|
return projectReferences;
|
|
@@ -497,7 +545,7 @@ function hasExternalProjectReferences(tsConfigPath, tsConfig, workspaceRoot, pro
|
|
|
497
545
|
if (!refConfigPath.endsWith('.json')) {
|
|
498
546
|
refConfigPath = (0, node_path_1.join)(refConfigPath, 'tsconfig.json');
|
|
499
547
|
}
|
|
500
|
-
const refTsConfig =
|
|
548
|
+
const refTsConfig = retrieveTsConfigFromCache(refConfigPath, workspaceRoot);
|
|
501
549
|
const result = hasExternalProjectReferences(refConfigPath, refTsConfig, workspaceRoot, projectRoot, seen);
|
|
502
550
|
if (result) {
|
|
503
551
|
return true;
|
|
@@ -506,21 +554,28 @@ function hasExternalProjectReferences(tsConfigPath, tsConfig, workspaceRoot, pro
|
|
|
506
554
|
return false;
|
|
507
555
|
}
|
|
508
556
|
function isExternalProjectReference(refTsConfigPath, workspaceRoot, projectRoot) {
|
|
557
|
+
const relativePath = posixRelative(workspaceRoot, refTsConfigPath);
|
|
558
|
+
if (cache.isExternalProjectReference[relativePath] !== undefined) {
|
|
559
|
+
return cache.isExternalProjectReference[relativePath];
|
|
560
|
+
}
|
|
509
561
|
const absoluteProjectRoot = (0, node_path_1.join)(workspaceRoot, projectRoot);
|
|
510
562
|
let currentPath = getTsConfigDirName(refTsConfigPath);
|
|
511
563
|
if ((0, node_path_1.relative)(absoluteProjectRoot, currentPath).startsWith('..')) {
|
|
512
564
|
// it's outside of the project root, so it's an external project reference
|
|
565
|
+
cache.isExternalProjectReference[relativePath] = true;
|
|
513
566
|
return true;
|
|
514
567
|
}
|
|
515
568
|
while (currentPath !== absoluteProjectRoot) {
|
|
516
569
|
if ((0, node_fs_1.existsSync)((0, node_path_1.join)(currentPath, 'package.json')) ||
|
|
517
570
|
(0, node_fs_1.existsSync)((0, node_path_1.join)(currentPath, 'project.json'))) {
|
|
518
571
|
// it's inside a nested project root, so it's and external project reference
|
|
572
|
+
cache.isExternalProjectReference[relativePath] = true;
|
|
519
573
|
return true;
|
|
520
574
|
}
|
|
521
575
|
currentPath = (0, node_path_1.dirname)(currentPath);
|
|
522
576
|
}
|
|
523
577
|
// it's inside the project root, so it's an internal project reference
|
|
578
|
+
cache.isExternalProjectReference[relativePath] = false;
|
|
524
579
|
return false;
|
|
525
580
|
}
|
|
526
581
|
function getTsConfigDirName(tsConfigPath) {
|
|
@@ -528,19 +583,89 @@ function getTsConfigDirName(tsConfigPath) {
|
|
|
528
583
|
? (0, node_path_1.dirname)(tsConfigPath)
|
|
529
584
|
: (0, node_path_1.normalize)(tsConfigPath);
|
|
530
585
|
}
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
586
|
+
function retrieveTsConfigFromCache(tsConfigPath, workspaceRoot) {
|
|
587
|
+
const relativePath = posixRelative(workspaceRoot, tsConfigPath);
|
|
588
|
+
// we don't need to check the hash if it's in the cache, because we've already
|
|
589
|
+
// checked it when we initially populated the cache
|
|
590
|
+
return tsConfigCache[relativePath]
|
|
591
|
+
? tsConfigCache[relativePath].data
|
|
592
|
+
: readTsConfigAndCache(tsConfigPath, workspaceRoot);
|
|
593
|
+
}
|
|
594
|
+
function initializeTsConfigCache(configFilePaths, workspaceRoot) {
|
|
595
|
+
tsConfigCache = toAbsolutePaths(readFromCache(tsConfigCachePath), workspaceRoot);
|
|
596
|
+
// ensure hashes are checked and the cache is invalidated and populated as needed
|
|
597
|
+
for (const configFilePath of configFilePaths) {
|
|
598
|
+
const fullConfigPath = (0, node_path_1.join)(workspaceRoot, configFilePath);
|
|
599
|
+
readTsConfigAndCache(fullConfigPath, workspaceRoot);
|
|
600
|
+
}
|
|
601
|
+
}
|
|
602
|
+
function readTsConfigAndCache(tsConfigPath, workspaceRoot) {
|
|
603
|
+
const relativePath = posixRelative(workspaceRoot, tsConfigPath);
|
|
604
|
+
const hash = getFileHash(tsConfigPath, workspaceRoot);
|
|
605
|
+
let extendedFilesHash;
|
|
606
|
+
if (tsConfigCache[relativePath] &&
|
|
607
|
+
tsConfigCache[relativePath].hash === hash) {
|
|
608
|
+
extendedFilesHash = getExtendedFilesHash(tsConfigCache[relativePath].data.extendedConfigFiles, workspaceRoot);
|
|
609
|
+
if (tsConfigCache[relativePath].extendedFilesHash === extendedFilesHash) {
|
|
610
|
+
return tsConfigCache[relativePath].data;
|
|
611
|
+
}
|
|
612
|
+
}
|
|
613
|
+
const tsConfig = readTsConfig(tsConfigPath, workspaceRoot);
|
|
614
|
+
const extendedConfigFiles = [];
|
|
615
|
+
if (tsConfig.raw?.extends) {
|
|
616
|
+
const extendsArray = typeof tsConfig.raw.extends === 'string'
|
|
617
|
+
? [tsConfig.raw.extends]
|
|
618
|
+
: tsConfig.raw.extends;
|
|
619
|
+
for (const extendsPath of extendsArray) {
|
|
620
|
+
const extendedConfigFile = resolveExtendedTsConfigPath(extendsPath, (0, node_path_1.dirname)(tsConfigPath));
|
|
621
|
+
if (extendedConfigFile) {
|
|
622
|
+
extendedConfigFiles.push(extendedConfigFile);
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
}
|
|
626
|
+
extendedFilesHash ??= getExtendedFilesHash(extendedConfigFiles, workspaceRoot);
|
|
627
|
+
tsConfigCache[relativePath] = {
|
|
628
|
+
data: {
|
|
629
|
+
options: tsConfig.options,
|
|
630
|
+
projectReferences: tsConfig.projectReferences,
|
|
631
|
+
raw: tsConfig.raw,
|
|
632
|
+
extendedConfigFiles,
|
|
633
|
+
},
|
|
634
|
+
hash,
|
|
635
|
+
extendedFilesHash,
|
|
636
|
+
};
|
|
637
|
+
return tsConfigCache[relativePath].data;
|
|
638
|
+
}
|
|
639
|
+
function getExtendedFilesHash(extendedConfigFiles, workspaceRoot) {
|
|
640
|
+
const hashes = [];
|
|
641
|
+
if (!extendedConfigFiles.length) {
|
|
642
|
+
return '';
|
|
643
|
+
}
|
|
644
|
+
for (const extendedConfigFile of extendedConfigFiles) {
|
|
645
|
+
if (extendedConfigFile.externalPackage) {
|
|
646
|
+
hashes.push(extendedConfigFile.externalPackage);
|
|
647
|
+
}
|
|
648
|
+
else if (extendedConfigFile.filePath) {
|
|
649
|
+
hashes.push(getFileHash(extendedConfigFile.filePath, workspaceRoot));
|
|
650
|
+
hashes.push(getExtendedFilesHash(readTsConfigAndCache(extendedConfigFile.filePath, workspaceRoot)
|
|
651
|
+
.extendedConfigFiles, workspaceRoot));
|
|
652
|
+
}
|
|
653
|
+
}
|
|
654
|
+
return hashes.join('|');
|
|
540
655
|
}
|
|
541
|
-
function
|
|
542
|
-
|
|
543
|
-
|
|
656
|
+
function readTsConfig(tsConfigPath, workspaceRoot) {
|
|
657
|
+
if (!ts) {
|
|
658
|
+
ts = require('typescript');
|
|
659
|
+
}
|
|
660
|
+
const tsSys = {
|
|
661
|
+
...ts.sys,
|
|
662
|
+
readFile: (path) => readFile(path, workspaceRoot),
|
|
663
|
+
readDirectory: () => [],
|
|
664
|
+
};
|
|
665
|
+
const readResult = ts.readConfigFile(tsConfigPath, tsSys.readFile);
|
|
666
|
+
// read with a custom host that won't read directories which is only used
|
|
667
|
+
// to identify the filenames included in the program, which we won't use
|
|
668
|
+
return ts.parseJsonConfigFileContent(readResult.config, tsSys, (0, node_path_1.dirname)(tsConfigPath));
|
|
544
669
|
}
|
|
545
670
|
function normalizePluginOptions(pluginOptions = {}) {
|
|
546
671
|
const defaultTypecheckTargetName = 'typecheck';
|
|
@@ -587,7 +712,8 @@ function resolveExtendedTsConfigPath(tsConfigPath, directory) {
|
|
|
587
712
|
const resolvedPath = require.resolve(tsConfigPath, {
|
|
588
713
|
paths: directory ? [directory] : undefined,
|
|
589
714
|
});
|
|
590
|
-
if (tsConfigPath.startsWith('.')
|
|
715
|
+
if (tsConfigPath.startsWith('.') ||
|
|
716
|
+
!resolvedPath.includes('/node_modules/')) {
|
|
591
717
|
return { filePath: resolvedPath };
|
|
592
718
|
}
|
|
593
719
|
// parse the package from the tsconfig path
|
|
@@ -600,3 +726,99 @@ function resolveExtendedTsConfigPath(tsConfigPath, directory) {
|
|
|
600
726
|
return null;
|
|
601
727
|
}
|
|
602
728
|
}
|
|
729
|
+
function getFileHash(filePath, workspaceRoot) {
|
|
730
|
+
const relativePath = posixRelative(workspaceRoot, filePath);
|
|
731
|
+
if (!cache.fileHashes[relativePath]) {
|
|
732
|
+
const content = readFile(filePath, workspaceRoot);
|
|
733
|
+
cache.fileHashes[relativePath] = (0, file_hasher_1.hashArray)([content]);
|
|
734
|
+
}
|
|
735
|
+
return cache.fileHashes[relativePath];
|
|
736
|
+
}
|
|
737
|
+
function readFile(filePath, workspaceRoot) {
|
|
738
|
+
const relativePath = posixRelative(workspaceRoot, filePath);
|
|
739
|
+
if (!cache.rawFiles[relativePath]) {
|
|
740
|
+
const content = (0, node_fs_1.readFileSync)(filePath, 'utf8');
|
|
741
|
+
cache.rawFiles[relativePath] = content;
|
|
742
|
+
}
|
|
743
|
+
return cache.rawFiles[relativePath];
|
|
744
|
+
}
|
|
745
|
+
function toAbsolutePaths(cache, workspaceRoot) {
|
|
746
|
+
const updatedCache = {};
|
|
747
|
+
for (const [key, { data, extendedFilesHash, hash }] of Object.entries(cache)) {
|
|
748
|
+
updatedCache[key] = {
|
|
749
|
+
data: {
|
|
750
|
+
options: { noEmit: data.options.noEmit },
|
|
751
|
+
raw: {
|
|
752
|
+
nx: { addTypecheckTarget: data.raw?.['nx']?.addTypecheckTarget },
|
|
753
|
+
},
|
|
754
|
+
extendedConfigFiles: data.extendedConfigFiles,
|
|
755
|
+
},
|
|
756
|
+
extendedFilesHash,
|
|
757
|
+
hash,
|
|
758
|
+
};
|
|
759
|
+
if (data.options.rootDir) {
|
|
760
|
+
updatedCache[key].data.options.rootDir = (0, node_path_1.join)(workspaceRoot, data.options.rootDir);
|
|
761
|
+
}
|
|
762
|
+
if (data.options.outDir) {
|
|
763
|
+
updatedCache[key].data.options.outDir = (0, node_path_1.join)(workspaceRoot, data.options.outDir);
|
|
764
|
+
}
|
|
765
|
+
if (data.options.outFile) {
|
|
766
|
+
updatedCache[key].data.options.outFile = (0, node_path_1.join)(workspaceRoot, data.options.outFile);
|
|
767
|
+
}
|
|
768
|
+
if (data.options.tsBuildInfoFile) {
|
|
769
|
+
updatedCache[key].data.options.tsBuildInfoFile = (0, node_path_1.join)(workspaceRoot, data.options.tsBuildInfoFile);
|
|
770
|
+
}
|
|
771
|
+
if (data.extendedConfigFiles.length) {
|
|
772
|
+
updatedCache[key].data.extendedConfigFiles.forEach((file) => {
|
|
773
|
+
file.filePath = (0, node_path_1.join)(workspaceRoot, file.filePath);
|
|
774
|
+
});
|
|
775
|
+
}
|
|
776
|
+
if (data.projectReferences) {
|
|
777
|
+
updatedCache[key].data.projectReferences = data.projectReferences.map((ref) => ({ ...ref, path: (0, node_path_1.join)(workspaceRoot, ref.path) }));
|
|
778
|
+
}
|
|
779
|
+
}
|
|
780
|
+
return updatedCache;
|
|
781
|
+
}
|
|
782
|
+
function toRelativePaths(cache, workspaceRoot) {
|
|
783
|
+
const updatedCache = {};
|
|
784
|
+
for (const [key, { data, extendedFilesHash, hash }] of Object.entries(cache)) {
|
|
785
|
+
updatedCache[key] = {
|
|
786
|
+
data: {
|
|
787
|
+
options: { noEmit: data.options.noEmit },
|
|
788
|
+
raw: {
|
|
789
|
+
nx: { addTypecheckTarget: data.raw?.['nx']?.addTypecheckTarget },
|
|
790
|
+
},
|
|
791
|
+
extendedConfigFiles: data.extendedConfigFiles,
|
|
792
|
+
},
|
|
793
|
+
extendedFilesHash,
|
|
794
|
+
hash,
|
|
795
|
+
};
|
|
796
|
+
if (data.options.rootDir) {
|
|
797
|
+
updatedCache[key].data.options.rootDir = posixRelative(workspaceRoot, data.options.rootDir);
|
|
798
|
+
}
|
|
799
|
+
if (data.options.outDir) {
|
|
800
|
+
updatedCache[key].data.options.outDir = posixRelative(workspaceRoot, data.options.outDir);
|
|
801
|
+
}
|
|
802
|
+
if (data.options.outFile) {
|
|
803
|
+
updatedCache[key].data.options.outFile = posixRelative(workspaceRoot, data.options.outFile);
|
|
804
|
+
}
|
|
805
|
+
if (data.options.tsBuildInfoFile) {
|
|
806
|
+
updatedCache[key].data.options.tsBuildInfoFile = posixRelative(workspaceRoot, data.options.tsBuildInfoFile);
|
|
807
|
+
}
|
|
808
|
+
if (data.extendedConfigFiles.length) {
|
|
809
|
+
updatedCache[key].data.extendedConfigFiles.forEach((file) => {
|
|
810
|
+
file.filePath = posixRelative(workspaceRoot, file.filePath);
|
|
811
|
+
});
|
|
812
|
+
}
|
|
813
|
+
if (data.projectReferences) {
|
|
814
|
+
updatedCache[key].data.projectReferences = data.projectReferences.map((ref) => ({
|
|
815
|
+
...ref,
|
|
816
|
+
path: posixRelative(workspaceRoot, ref.path),
|
|
817
|
+
}));
|
|
818
|
+
}
|
|
819
|
+
}
|
|
820
|
+
return updatedCache;
|
|
821
|
+
}
|
|
822
|
+
function posixRelative(workspaceRoot, path) {
|
|
823
|
+
return posix.normalize((0, node_path_1.relative)(workspaceRoot, path));
|
|
824
|
+
}
|