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