@nx/js 24.0.0-beta.2 → 24.0.0-beta.4
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/dist/internal.d.ts +2 -0
- package/dist/internal.js +8 -2
- package/dist/src/generators/init/init.js +3 -33
- package/dist/src/generators/init/schema.d.ts +0 -1
- package/dist/src/generators/library/library.d.ts +1 -1
- package/dist/src/generators/library/library.js +3 -16
- package/dist/src/generators/library/schema.d.ts +0 -1
- package/dist/src/generators/setup-build/generator.js +0 -5
- package/dist/src/plugins/scripts/create-script-nodes.d.ts +6 -2
- package/dist/src/plugins/scripts/create-script-nodes.js +18 -71
- package/dist/src/plugins/scripts/node-plugin.d.ts +2 -1
- package/dist/src/plugins/scripts/shebang.d.ts +7 -2
- package/dist/src/plugins/scripts/shebang.js +27 -10
- package/dist/src/plugins/scripts/target-name.d.ts +9 -0
- package/dist/src/plugins/scripts/target-name.js +19 -0
- package/dist/src/plugins/scripts/tsx-plugin.d.ts +3 -2
- package/dist/src/plugins/typescript/build-typechecks.d.ts +8 -0
- package/dist/src/plugins/typescript/build-typechecks.js +45 -0
- package/dist/src/plugins/typescript/plugin.js +107 -38
- package/dist/src/plugins/typescript/typecheck-target.d.ts +54 -0
- package/dist/src/plugins/typescript/typecheck-target.js +81 -0
- package/dist/src/utils/add-linting-to-project.d.ts +0 -2
- package/dist/src/utils/add-linting-to-project.js +0 -3
- package/dist/src/utils/swc/compile-swc.d.ts +2 -0
- package/dist/src/utils/swc/compile-swc.js +2 -1
- package/dist/src/utils/typescript/add-typescript-plugin.d.ts +22 -0
- package/dist/src/utils/typescript/add-typescript-plugin.js +145 -0
- package/dist/src/utils/typescript/ts-solution-setup.d.ts +1 -1
- package/dist/src/utils/typescript/ts-solution-setup.js +1 -10
- package/package.json +11 -11
- package/dist/src/plugins/scripts/frontmatter.d.ts +0 -6
- package/dist/src/plugins/scripts/frontmatter.js +0 -52
|
@@ -7,6 +7,9 @@ const node_fs_1 = require("node:fs");
|
|
|
7
7
|
const node_path_1 = require("node:path");
|
|
8
8
|
const picomatch = require("picomatch");
|
|
9
9
|
const util_1 = require("./util");
|
|
10
|
+
const typecheck_target_1 = require("./typecheck-target");
|
|
11
|
+
const build_typechecks_1 = require("./build-typechecks");
|
|
12
|
+
const ts_solution_setup_1 = require("../../utils/typescript/ts-solution-setup");
|
|
10
13
|
let ts;
|
|
11
14
|
const resolvedTypescriptPaths = {};
|
|
12
15
|
function resolveTypescriptPath(projectRoot, workspaceRoot) {
|
|
@@ -119,14 +122,16 @@ exports.createNodesV2 = [
|
|
|
119
122
|
projectContexts: new Map(),
|
|
120
123
|
configContexts: new Map(),
|
|
121
124
|
referenceExpansionCache: new Map(),
|
|
125
|
+
siblingFiles: new Map(),
|
|
122
126
|
});
|
|
123
127
|
const cache = cacheStore.get(cacheKey);
|
|
124
128
|
initializeTsConfigCache(configFilePaths, context.workspaceRoot, cache);
|
|
125
129
|
const normalizedOptions = normalizePluginOptions(options);
|
|
130
|
+
const isUsingTsSolutionSetup = (0, ts_solution_setup_1.isUsingTsSolutionSetup)(new internal_1.FsTree(context.workspaceRoot, false));
|
|
126
131
|
const packageManager = (0, devkit_1.detectPackageManager)(context.workspaceRoot);
|
|
127
132
|
const pmc = (0, devkit_1.getPackageManagerCommand)(packageManager);
|
|
128
133
|
const lockFileName = (0, internal_1.getLockFileName)(packageManager);
|
|
129
|
-
const { configFilePaths: validConfigFilePaths, hashes, projectRoots, } = await resolveValidConfigFilesAndHashes(configFilePaths, normalizedOptions,
|
|
134
|
+
const { configFilePaths: validConfigFilePaths, hashes, projectRoots, } = await resolveValidConfigFilesAndHashes(configFilePaths, normalizedOptions, (0, internal_1.hashObject)({ options, isUsingTsSolutionSetup }), context, cache, lockFileName, isUsingTsSolutionSetup);
|
|
130
135
|
try {
|
|
131
136
|
return await (0, devkit_1.createNodesFromFiles)((configFilePath, options, context, idx) => {
|
|
132
137
|
const projectRoot = projectRoots[idx];
|
|
@@ -134,7 +139,7 @@ exports.createNodesV2 = [
|
|
|
134
139
|
const targetsCacheKey = `${hash}_${configFilePath}`;
|
|
135
140
|
const absolutePath = (0, node_path_1.join)(context.workspaceRoot, configFilePath);
|
|
136
141
|
const configContext = getConfigContext(absolutePath, context.workspaceRoot, cache);
|
|
137
|
-
targetsCache[targetsCacheKey] ??= buildTscTargets(configContext, options, context, validConfigFilePaths, cache, pmc);
|
|
142
|
+
targetsCache[targetsCacheKey] ??= buildTscTargets(configContext, options, context, validConfigFilePaths, cache, pmc, isUsingTsSolutionSetup);
|
|
138
143
|
const { targets } = targetsCache[targetsCacheKey];
|
|
139
144
|
return {
|
|
140
145
|
projects: {
|
|
@@ -159,7 +164,7 @@ exports.createNodesV2 = [
|
|
|
159
164
|
},
|
|
160
165
|
];
|
|
161
166
|
exports.createNodes = exports.createNodesV2;
|
|
162
|
-
async function resolveValidConfigFilesAndHashes(configFilePaths, options, optionsHash, context, cache, lockFileName) {
|
|
167
|
+
async function resolveValidConfigFilesAndHashes(configFilePaths, options, optionsHash, context, cache, lockFileName, isUsingTsSolutionSetup) {
|
|
163
168
|
const lockFileHash = (0, internal_1.hashFile)((0, node_path_1.join)(context.workspaceRoot, lockFileName)) ?? '';
|
|
164
169
|
const validConfigFilePaths = [];
|
|
165
170
|
const hashes = [];
|
|
@@ -180,7 +185,13 @@ async function resolveValidConfigFilesAndHashes(configFilePaths, options, option
|
|
|
180
185
|
}
|
|
181
186
|
projectRoots.push(projectRoot);
|
|
182
187
|
validConfigFilePaths.push(configFilePath);
|
|
183
|
-
|
|
188
|
+
const configFileHash = await getConfigFileHash(configFilePath, context.workspaceRoot, configContext.project, optionsHash, lockFileHash, cache);
|
|
189
|
+
hashes.push(isUsingTsSolutionSetup
|
|
190
|
+
? configFileHash
|
|
191
|
+
: (0, devkit_1.hashArray)([
|
|
192
|
+
configFileHash,
|
|
193
|
+
...getNoEmitTypecheckHashInputs(configContext.project, context.workspaceRoot, cache),
|
|
194
|
+
]));
|
|
184
195
|
}
|
|
185
196
|
return { configFilePaths: validConfigFilePaths, hashes, projectRoots };
|
|
186
197
|
}
|
|
@@ -226,7 +237,7 @@ function checkIfConfigFileShouldBeProject(config, cache) {
|
|
|
226
237
|
return false;
|
|
227
238
|
}
|
|
228
239
|
// Do not create a project if package.json and project.json isn't there.
|
|
229
|
-
const siblingFiles = (
|
|
240
|
+
const siblingFiles = readSiblingFiles(config.project, cache);
|
|
230
241
|
if (!siblingFiles.includes('package.json') &&
|
|
231
242
|
!siblingFiles.includes('project.json')) {
|
|
232
243
|
return false;
|
|
@@ -247,7 +258,7 @@ function checkIfConfigFileShouldBeProject(config, cache) {
|
|
|
247
258
|
}
|
|
248
259
|
return true;
|
|
249
260
|
}
|
|
250
|
-
function buildTscTargets(config, options, context, configFiles, cache, pmc) {
|
|
261
|
+
function buildTscTargets(config, options, context, configFiles, cache, pmc, isUsingTsSolutionSetup) {
|
|
251
262
|
const targets = {};
|
|
252
263
|
const namedInputs = (0, internal_1.getNamedInputs)(config.project.root, context);
|
|
253
264
|
const tsConfig = retrieveTsConfigFromCache(config.absolutePath, context.workspaceRoot, cache);
|
|
@@ -259,18 +270,28 @@ function buildTscTargets(config, options, context, configFiles, cache, pmc) {
|
|
|
259
270
|
const externalProjectReferences = resolveShallowExternalProjectReferences(tsConfig, context.workspaceRoot, config.project, cache);
|
|
260
271
|
const targetName = options.typecheck.targetName;
|
|
261
272
|
const compiler = options.compiler;
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
273
|
+
// `tsc --build` needs composite projects, so other setups check without
|
|
274
|
+
// emitting, and skip projects whose build already type-checks.
|
|
275
|
+
if (!isUsingTsSolutionSetup) {
|
|
276
|
+
const siblingFiles = readSiblingFiles(config.project, cache);
|
|
277
|
+
if (!(0, build_typechecks_1.buildTypechecksProject)(siblingFiles, readProjectTargets(config.project.absolute, siblingFiles))) {
|
|
278
|
+
targets[targetName] = (0, typecheck_target_1.createTypecheckTarget)({
|
|
279
|
+
mode: 'noEmit',
|
|
280
|
+
projectRoot: config.project.normalized,
|
|
281
|
+
pmc,
|
|
282
|
+
tsConfig: (0, typecheck_target_1.selectTypecheckTsConfig)(siblingFiles.filter((file) => /^tsconfig.*\.json$/.test(file))),
|
|
283
|
+
compiler,
|
|
284
|
+
// Like the framework targets it replaces: `{workspaceRoot}` inputs
|
|
285
|
+
// would mark the project affected by any root tsconfig change.
|
|
286
|
+
namedInputs,
|
|
287
|
+
});
|
|
269
288
|
}
|
|
270
|
-
|
|
289
|
+
}
|
|
290
|
+
else if (!targets[targetName]) {
|
|
291
|
+
let buildTargetName;
|
|
271
292
|
if (options.build && targets[options.build.targetName]) {
|
|
272
293
|
// we already processed and have a build target
|
|
273
|
-
|
|
294
|
+
buildTargetName = options.build.targetName;
|
|
274
295
|
}
|
|
275
296
|
else if (options.build) {
|
|
276
297
|
// check if the project will have a build target
|
|
@@ -278,29 +299,29 @@ function buildTscTargets(config, options, context, configFiles, cache, pmc) {
|
|
|
278
299
|
if (configFiles.some((f) => f === buildConfigPath) &&
|
|
279
300
|
(options.build.skipBuildCheck ||
|
|
280
301
|
(0, util_1.isValidPackageJsonBuildConfig)(retrieveTsConfigFromCache(buildConfigPath, context.workspaceRoot, cache), context.workspaceRoot, config.project.root))) {
|
|
281
|
-
|
|
302
|
+
buildTargetName = options.build.targetName;
|
|
282
303
|
}
|
|
283
304
|
}
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
305
|
+
const target = (0, typecheck_target_1.createTypecheckTarget)({
|
|
306
|
+
mode: 'build',
|
|
307
|
+
projectRoot: config.project.normalized,
|
|
308
|
+
pmc,
|
|
309
|
+
tsConfig: options.typecheck.configName,
|
|
310
|
+
compiler,
|
|
311
|
+
targetName,
|
|
312
|
+
buildTargetName,
|
|
313
|
+
verboseOutput: options.verboseOutput,
|
|
289
314
|
inputs: getInputs(namedInputs, config, tsConfig, internalProjectReferences, context.workspaceRoot, cache),
|
|
290
315
|
outputs: getOutputs(config, tsConfig, internalProjectReferences, context.workspaceRoot,
|
|
291
316
|
/* emitDeclarationOnly */ true),
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
},
|
|
301
|
-
},
|
|
302
|
-
},
|
|
303
|
-
};
|
|
317
|
+
});
|
|
318
|
+
if (tsConfig.options.noEmit ||
|
|
319
|
+
Object.values(internalProjectReferences).some((ref) => ref.options.noEmit) ||
|
|
320
|
+
Object.values(externalProjectReferences).some((ref) => ref.options.noEmit)) {
|
|
321
|
+
// `tsc --build` does not work with `noEmit: true`
|
|
322
|
+
target.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."`;
|
|
323
|
+
}
|
|
324
|
+
targets[targetName] = target;
|
|
304
325
|
}
|
|
305
326
|
}
|
|
306
327
|
// Build target
|
|
@@ -313,7 +334,7 @@ function buildTscTargets(config, options, context, configFiles, cache, pmc) {
|
|
|
313
334
|
const compiler = options.compiler;
|
|
314
335
|
targets[targetName] = {
|
|
315
336
|
dependsOn: [`^${targetName}`],
|
|
316
|
-
command: `${compiler} --build
|
|
337
|
+
command: `${compiler} --build${(0, typecheck_target_1.getTsConfigArg)(options.build.configName)}${options.verboseOutput ? ' --verbose' : ''}`,
|
|
317
338
|
options: { cwd: config.project.normalized },
|
|
318
339
|
cache: true,
|
|
319
340
|
inputs: getInputs(namedInputs, config, tsConfig, internalProjectReferences, context.workspaceRoot, cache),
|
|
@@ -339,6 +360,48 @@ function buildTscTargets(config, options, context, configFiles, cache, pmc) {
|
|
|
339
360
|
}
|
|
340
361
|
return { targets };
|
|
341
362
|
}
|
|
363
|
+
/**
|
|
364
|
+
* Files that decide the `noEmit` typecheck target: the sibling tsconfigs and
|
|
365
|
+
* bundler configs by name, and `project.json` by content.
|
|
366
|
+
*/
|
|
367
|
+
function getNoEmitTypecheckHashInputs(project, workspaceRoot, cache) {
|
|
368
|
+
const siblingFiles = readSiblingFiles(project, cache);
|
|
369
|
+
return [
|
|
370
|
+
...siblingFiles
|
|
371
|
+
.filter((file) => /^(tsconfig.*\.json|(webpack|rspack|rollup)\.config\..+)$/.test(file))
|
|
372
|
+
.sort(),
|
|
373
|
+
...(siblingFiles.includes('project.json')
|
|
374
|
+
? [
|
|
375
|
+
getFileHash((0, node_path_1.join)(project.absolute, 'project.json'), workspaceRoot, cache),
|
|
376
|
+
]
|
|
377
|
+
: []),
|
|
378
|
+
];
|
|
379
|
+
}
|
|
380
|
+
function readSiblingFiles(project, cache) {
|
|
381
|
+
let files = cache.siblingFiles.get(project.absolute);
|
|
382
|
+
if (!files) {
|
|
383
|
+
files = (0, node_fs_1.readdirSync)(project.absolute);
|
|
384
|
+
cache.siblingFiles.set(project.absolute, files);
|
|
385
|
+
}
|
|
386
|
+
return files;
|
|
387
|
+
}
|
|
388
|
+
function readProjectTargets(projectRoot, siblingFiles) {
|
|
389
|
+
return {
|
|
390
|
+
...readTargets(projectRoot, siblingFiles, 'package.json', (json) => json.nx?.targets),
|
|
391
|
+
...readTargets(projectRoot, siblingFiles, 'project.json', (json) => json.targets),
|
|
392
|
+
};
|
|
393
|
+
}
|
|
394
|
+
function readTargets(projectRoot, siblingFiles, file, getTargets) {
|
|
395
|
+
if (!siblingFiles.includes(file)) {
|
|
396
|
+
return undefined;
|
|
397
|
+
}
|
|
398
|
+
try {
|
|
399
|
+
return getTargets((0, devkit_1.readJsonFile)((0, node_path_1.join)(projectRoot, file)));
|
|
400
|
+
}
|
|
401
|
+
catch {
|
|
402
|
+
return undefined;
|
|
403
|
+
}
|
|
404
|
+
}
|
|
342
405
|
function getInputs(namedInputs, config, tsConfig, internalProjectReferences, workspaceRoot, cache) {
|
|
343
406
|
const configFiles = new Set();
|
|
344
407
|
// TODO(leo): temporary disable external dependencies until we support hashing
|
|
@@ -983,15 +1046,21 @@ function getFileHash(filePath, workspaceRoot, cache) {
|
|
|
983
1046
|
const relativePath = posixRelative(workspaceRoot, filePath);
|
|
984
1047
|
if (!cache.fileHashes[relativePath]) {
|
|
985
1048
|
const content = readFile(filePath, workspaceRoot, cache);
|
|
986
|
-
cache.fileHashes[relativePath] = (0, devkit_1.hashArray)([content]);
|
|
1049
|
+
cache.fileHashes[relativePath] = (0, devkit_1.hashArray)([content ?? '<missing>']);
|
|
987
1050
|
}
|
|
988
1051
|
return cache.fileHashes[relativePath];
|
|
989
1052
|
}
|
|
1053
|
+
/**
|
|
1054
|
+
* Returns `undefined` for a missing file, as `ts.sys.readFile` does, so a
|
|
1055
|
+
* tsconfig extending a deleted file is reported by TypeScript instead of
|
|
1056
|
+
* throwing.
|
|
1057
|
+
*/
|
|
990
1058
|
function readFile(filePath, workspaceRoot, cache) {
|
|
991
1059
|
const relativePath = posixRelative(workspaceRoot, filePath);
|
|
992
|
-
if (!cache.rawFiles
|
|
993
|
-
|
|
994
|
-
|
|
1060
|
+
if (!(relativePath in cache.rawFiles)) {
|
|
1061
|
+
cache.rawFiles[relativePath] = (0, node_fs_1.existsSync)(filePath)
|
|
1062
|
+
? (0, node_fs_1.readFileSync)(filePath, 'utf8')
|
|
1063
|
+
: undefined;
|
|
995
1064
|
}
|
|
996
1065
|
return cache.rawFiles[relativePath];
|
|
997
1066
|
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import type { getPackageManagerCommand, TargetConfiguration } from '@nx/devkit';
|
|
2
|
+
export interface TypecheckTargetOptions {
|
|
3
|
+
/**
|
|
4
|
+
* `build` runs `tsc --build --emitDeclarationOnly` for TS solution setups.
|
|
5
|
+
* `noEmit` runs `tsc -p <tsconfig> --noEmit`.
|
|
6
|
+
*/
|
|
7
|
+
mode: 'build' | 'noEmit';
|
|
8
|
+
/**
|
|
9
|
+
* Project root, used as the command's cwd.
|
|
10
|
+
*/
|
|
11
|
+
projectRoot: string;
|
|
12
|
+
pmc: ReturnType<typeof getPackageManagerCommand>;
|
|
13
|
+
/**
|
|
14
|
+
* Defaults to `tsconfig.json`, which is left out of the command.
|
|
15
|
+
*/
|
|
16
|
+
tsConfig?: string;
|
|
17
|
+
/**
|
|
18
|
+
* Defaults to `tsc`.
|
|
19
|
+
*/
|
|
20
|
+
compiler?: string;
|
|
21
|
+
/**
|
|
22
|
+
* Name of the typecheck target, for the dependency on referenced projects
|
|
23
|
+
* in `build` mode. Defaults to `typecheck`.
|
|
24
|
+
*/
|
|
25
|
+
targetName?: string;
|
|
26
|
+
/**
|
|
27
|
+
* The project's build target, which `build` mode runs first.
|
|
28
|
+
*/
|
|
29
|
+
buildTargetName?: string;
|
|
30
|
+
/**
|
|
31
|
+
* Defaults to the `production` (or `default`) named input plus the
|
|
32
|
+
* compiler package.
|
|
33
|
+
*/
|
|
34
|
+
inputs?: TargetConfiguration['inputs'];
|
|
35
|
+
namedInputs?: Record<string, unknown>;
|
|
36
|
+
outputs?: string[];
|
|
37
|
+
technologies?: string[];
|
|
38
|
+
verboseOutput?: boolean;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Builds a `typecheck` target. Plugins that infer a `tsc` one share this
|
|
42
|
+
* shape so it stays compatible with the one `@nx/js/typescript` infers.
|
|
43
|
+
*/
|
|
44
|
+
export declare function createTypecheckTarget(options: TypecheckTargetOptions): TargetConfiguration;
|
|
45
|
+
/**
|
|
46
|
+
* The tsconfig a `noEmit` typecheck target should check, from the files next
|
|
47
|
+
* to the project's config: the app, then the lib, then the root tsconfig.
|
|
48
|
+
*/
|
|
49
|
+
export declare function selectTypecheckTsConfig(tsConfigFiles: string[]): string | undefined;
|
|
50
|
+
/**
|
|
51
|
+
* ` <tsconfig>` for a tsc command, or an empty string for `tsconfig.json`,
|
|
52
|
+
* which tsc reads by default.
|
|
53
|
+
*/
|
|
54
|
+
export declare function getTsConfigArg(tsConfig: string | undefined): string;
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createTypecheckTarget = createTypecheckTarget;
|
|
4
|
+
exports.selectTypecheckTsConfig = selectTypecheckTsConfig;
|
|
5
|
+
exports.getTsConfigArg = getTsConfigArg;
|
|
6
|
+
const DEFAULT_TSCONFIG = 'tsconfig.json';
|
|
7
|
+
/**
|
|
8
|
+
* Builds a `typecheck` target. Plugins that infer a `tsc` one share this
|
|
9
|
+
* shape so it stays compatible with the one `@nx/js/typescript` infers.
|
|
10
|
+
*/
|
|
11
|
+
function createTypecheckTarget(options) {
|
|
12
|
+
const compiler = options.compiler ?? 'tsc';
|
|
13
|
+
const tsConfigArg = getTsConfigArg(options.tsConfig);
|
|
14
|
+
const target = {
|
|
15
|
+
command: options.mode === 'build'
|
|
16
|
+
? `${compiler} --build${tsConfigArg} --emitDeclarationOnly${options.verboseOutput ? ' --verbose' : ''}`
|
|
17
|
+
: `${compiler}${tsConfigArg ? ` -p${tsConfigArg}` : ''} --noEmit`,
|
|
18
|
+
options: { cwd: options.projectRoot },
|
|
19
|
+
cache: true,
|
|
20
|
+
inputs: options.inputs ??
|
|
21
|
+
getDefaultTypecheckInputs(options.namedInputs ?? {}, compiler),
|
|
22
|
+
metadata: {
|
|
23
|
+
technologies: options.technologies ?? ['typescript'],
|
|
24
|
+
description: 'Runs type-checking for the project.',
|
|
25
|
+
help: options.mode === 'build'
|
|
26
|
+
? {
|
|
27
|
+
command: `${options.pmc.exec} ${compiler} --build --help`,
|
|
28
|
+
example: { args: ['--force'] },
|
|
29
|
+
}
|
|
30
|
+
: {
|
|
31
|
+
command: `${options.pmc.exec} ${compiler}${tsConfigArg ? ` -p${tsConfigArg}` : ''} --help`,
|
|
32
|
+
example: { options: { noEmit: true } },
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
};
|
|
36
|
+
if (options.outputs) {
|
|
37
|
+
target.outputs = options.outputs;
|
|
38
|
+
}
|
|
39
|
+
if (options.mode === 'build') {
|
|
40
|
+
target.dependsOn = [`^${options.targetName ?? 'typecheck'}`];
|
|
41
|
+
if (options.buildTargetName) {
|
|
42
|
+
target.dependsOn.unshift(options.buildTargetName);
|
|
43
|
+
}
|
|
44
|
+
target.syncGenerators = ['@nx/js:typescript-sync'];
|
|
45
|
+
}
|
|
46
|
+
return target;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* The tsconfig a `noEmit` typecheck target should check, from the files next
|
|
50
|
+
* to the project's config: the app, then the lib, then the root tsconfig.
|
|
51
|
+
*/
|
|
52
|
+
function selectTypecheckTsConfig(tsConfigFiles) {
|
|
53
|
+
return (['tsconfig.app.json', 'tsconfig.lib.json', DEFAULT_TSCONFIG].find((file) => tsConfigFiles.includes(file)) ?? tsConfigFiles.find((file) => SHELL_SAFE_TSCONFIG.test(file)));
|
|
54
|
+
}
|
|
55
|
+
// The name goes unquoted into a shell command.
|
|
56
|
+
const SHELL_SAFE_TSCONFIG = /^tsconfig[\w.-]*\.json$/;
|
|
57
|
+
/**
|
|
58
|
+
* ` <tsconfig>` for a tsc command, or an empty string for `tsconfig.json`,
|
|
59
|
+
* which tsc reads by default.
|
|
60
|
+
*/
|
|
61
|
+
function getTsConfigArg(tsConfig) {
|
|
62
|
+
return !tsConfig || tsConfig === DEFAULT_TSCONFIG ? '' : ` ${tsConfig}`;
|
|
63
|
+
}
|
|
64
|
+
function getDefaultTypecheckInputs(namedInputs, compiler) {
|
|
65
|
+
return [
|
|
66
|
+
...('production' in namedInputs
|
|
67
|
+
? ['production', '^production']
|
|
68
|
+
: ['default', '^default']),
|
|
69
|
+
{ externalDependencies: getCompilerPackages(compiler) },
|
|
70
|
+
];
|
|
71
|
+
}
|
|
72
|
+
function getCompilerPackages(compiler) {
|
|
73
|
+
switch (compiler) {
|
|
74
|
+
case 'tsgo':
|
|
75
|
+
return ['@typescript/native-preview'];
|
|
76
|
+
case 'vue-tsc':
|
|
77
|
+
return ['vue-tsc', 'typescript'];
|
|
78
|
+
default:
|
|
79
|
+
return ['typescript'];
|
|
80
|
+
}
|
|
81
|
+
}
|
|
@@ -6,7 +6,6 @@ export interface AddLintingToProjectOptions {
|
|
|
6
6
|
project: string;
|
|
7
7
|
skipPackageJson?: boolean;
|
|
8
8
|
keepExistingVersions?: boolean;
|
|
9
|
-
addPlugin?: boolean;
|
|
10
9
|
/** ESLint-only. Ignored by other linters. */
|
|
11
10
|
tsConfigPaths?: string[];
|
|
12
11
|
unitTestRunner?: string;
|
|
@@ -15,7 +14,6 @@ export interface AddLintingToProjectOptions {
|
|
|
15
14
|
/** ESLint-only. Ignored by other linters. */
|
|
16
15
|
enableTypedLinting?: boolean;
|
|
17
16
|
/** ESLint-only. Oxlint is inference-only, so it writes no explicit target. */
|
|
18
|
-
addExplicitTargets?: boolean;
|
|
19
17
|
/**
|
|
20
18
|
* ESLint-only. The `@nx/dependency-checks` rule lints `package.json`, which
|
|
21
19
|
* Oxlint cannot read.
|
|
@@ -60,7 +60,6 @@ async function addLintingToProject(tree, options) {
|
|
|
60
60
|
skipFormat: true,
|
|
61
61
|
skipPackageJson: options.skipPackageJson,
|
|
62
62
|
keepExistingVersions: options.keepExistingVersions,
|
|
63
|
-
// No `addPlugin`: `@nx/oxlint` is inference-only, so it always registers.
|
|
64
63
|
});
|
|
65
64
|
}
|
|
66
65
|
if (linter === 'eslint') {
|
|
@@ -72,12 +71,10 @@ async function addLintingToProject(tree, options) {
|
|
|
72
71
|
unitTestRunner: options.unitTestRunner,
|
|
73
72
|
rootProject: options.rootProject,
|
|
74
73
|
enableTypedLinting: options.enableTypedLinting,
|
|
75
|
-
addExplicitTargets: options.addExplicitTargets,
|
|
76
74
|
addPackageJsonDependencyChecks: options.addPackageJsonDependencyChecks,
|
|
77
75
|
skipFormat: true,
|
|
78
76
|
skipPackageJson: options.skipPackageJson,
|
|
79
77
|
keepExistingVersions: options.keepExistingVersions,
|
|
80
|
-
addPlugin: options.addPlugin,
|
|
81
78
|
});
|
|
82
79
|
}
|
|
83
80
|
// Spelling ESLint out as its own branch rather than letting it be the
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { ExecutorContext } from '@nx/devkit';
|
|
2
2
|
import { NormalizedSwcExecutorOptions } from '../schema';
|
|
3
|
+
import { TypeCheckOptions } from '../typescript/run-type-check';
|
|
3
4
|
export declare function getSwcCmd({ swcCliOptions: { swcrcPath, destPath, stripLeadingPaths }, root, projectRoot, sourceRoot, main, }: NormalizedSwcExecutorOptions, watch?: boolean): string;
|
|
5
|
+
export declare function getTypeCheckOptions(normalizedOptions: NormalizedSwcExecutorOptions): TypeCheckOptions;
|
|
4
6
|
export declare function compileSwc(context: ExecutorContext, normalizedOptions: NormalizedSwcExecutorOptions, postCompilationCallback: () => Promise<void>): Promise<{
|
|
5
7
|
success: boolean;
|
|
6
8
|
outfile?: undefined;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.getSwcCmd = getSwcCmd;
|
|
4
|
+
exports.getTypeCheckOptions = getTypeCheckOptions;
|
|
4
5
|
exports.compileSwc = compileSwc;
|
|
5
6
|
exports.compileSwcWatch = compileSwcWatch;
|
|
6
7
|
const devkit_1 = require("@nx/devkit");
|
|
@@ -45,7 +46,7 @@ function getTypeCheckOptions(normalizedOptions) {
|
|
|
45
46
|
tsConfigPath: tsConfig,
|
|
46
47
|
outDir: outputPath,
|
|
47
48
|
workspaceRoot: root,
|
|
48
|
-
rootDir: inputDir,
|
|
49
|
+
rootDir: (0, node_path_1.join)(root, inputDir),
|
|
49
50
|
};
|
|
50
51
|
if (watch) {
|
|
51
52
|
typeCheckOptions.incremental = true;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { type Tree } from '@nx/devkit';
|
|
2
|
+
export declare function addTypescriptPlugin(tree: Tree, updatePackageScripts?: boolean): Promise<void>;
|
|
3
|
+
/**
|
|
4
|
+
* Registers `@nx/js/typescript` in a workspace where no registration of it
|
|
5
|
+
* infers `typecheck` yet, adding a typecheck-only entry next to an existing
|
|
6
|
+
* unscoped one. Outside TS solution setups it only infers `typecheck`. Callers decide
|
|
7
|
+
* whether inference plugins are in use. Pass `frameworkPlugin` when that
|
|
8
|
+
* plugin still infers `typecheck` for some projects, so its target wins.
|
|
9
|
+
*/
|
|
10
|
+
export declare function ensureTypescriptPlugin(tree: Tree, updatePackageScripts?: boolean, frameworkPlugin?: string): Promise<void>;
|
|
11
|
+
/**
|
|
12
|
+
* Registers `@nx/js/typescript`, with only its typecheck target, in a
|
|
13
|
+
* workspace where `frameworkPlugin` no longer infers `typecheck`. Reuses the
|
|
14
|
+
* framework plugin's `typecheckTargetName` and a `tsgo` compiler, and skips
|
|
15
|
+
* workspaces where `@nx/js/typescript` already infers it or where
|
|
16
|
+
* `typecheckTargetName` is `false`. With
|
|
17
|
+
* `removeTypecheckTargetName`, the option is also dropped from the framework
|
|
18
|
+
* plugin's registrations. Returns whether nx.json changed.
|
|
19
|
+
*/
|
|
20
|
+
export declare function registerTypescriptPluginForTypecheck(tree: Tree, frameworkPlugin: string, { removeTypecheckTargetName }?: {
|
|
21
|
+
removeTypecheckTargetName?: boolean;
|
|
22
|
+
}): boolean;
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.addTypescriptPlugin = addTypescriptPlugin;
|
|
4
|
+
exports.ensureTypescriptPlugin = ensureTypescriptPlugin;
|
|
5
|
+
exports.registerTypescriptPluginForTypecheck = registerTypescriptPluginForTypecheck;
|
|
6
|
+
const internal_1 = require("@nx/devkit/internal");
|
|
7
|
+
const devkit_1 = require("@nx/devkit");
|
|
8
|
+
const plugin_1 = require("../../plugins/typescript/plugin");
|
|
9
|
+
const ts_solution_setup_1 = require("./ts-solution-setup");
|
|
10
|
+
async function addTypescriptPlugin(tree, updatePackageScripts) {
|
|
11
|
+
await (0, internal_1.addPlugin)(tree, await (0, devkit_1.createProjectGraphAsync)(), '@nx/js/typescript', plugin_1.createNodesV2, {
|
|
12
|
+
typecheck: TYPECHECK_OPTIONS,
|
|
13
|
+
build: [
|
|
14
|
+
{
|
|
15
|
+
targetName: 'build',
|
|
16
|
+
configName: 'tsconfig.lib.json',
|
|
17
|
+
buildDepsName: 'build-deps',
|
|
18
|
+
watchDepsName: 'watch-deps',
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
targetName: 'tsc:build',
|
|
22
|
+
configName: 'tsconfig.lib.json',
|
|
23
|
+
buildDepsName: 'tsc:build-deps',
|
|
24
|
+
watchDepsName: 'tsc:watch-deps',
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
targetName: 'tsc-build',
|
|
28
|
+
configName: 'tsconfig.lib.json',
|
|
29
|
+
buildDepsName: 'tsc-build-deps',
|
|
30
|
+
watchDepsName: 'tsc-watch-deps',
|
|
31
|
+
},
|
|
32
|
+
],
|
|
33
|
+
}, updatePackageScripts);
|
|
34
|
+
}
|
|
35
|
+
const TYPECHECK_OPTIONS = [
|
|
36
|
+
{ targetName: 'typecheck' },
|
|
37
|
+
{ targetName: 'tsc:typecheck' },
|
|
38
|
+
{ targetName: 'tsc-typecheck' },
|
|
39
|
+
];
|
|
40
|
+
/**
|
|
41
|
+
* Registers `@nx/js/typescript` in a workspace where no registration of it
|
|
42
|
+
* infers `typecheck` yet, adding a typecheck-only entry next to an existing
|
|
43
|
+
* unscoped one. Outside TS solution setups it only infers `typecheck`. Callers decide
|
|
44
|
+
* whether inference plugins are in use. Pass `frameworkPlugin` when that
|
|
45
|
+
* plugin still infers `typecheck` for some projects, so its target wins.
|
|
46
|
+
*/
|
|
47
|
+
async function ensureTypescriptPlugin(tree, updatePackageScripts, frameworkPlugin) {
|
|
48
|
+
const nxJson = (0, devkit_1.readNxJson)(tree);
|
|
49
|
+
if (nxJson?.plugins?.some(infersTypecheck)) {
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
if (nxJson?.plugins?.some((p) => typeof p !== 'string' && p.plugin === '@nx/js/typescript' && !p.include)) {
|
|
53
|
+
// `addPlugin` skips workspaces that have an unscoped registration.
|
|
54
|
+
nxJson.plugins.push({
|
|
55
|
+
plugin: '@nx/js/typescript',
|
|
56
|
+
options: { typecheck: { targetName: 'typecheck' } },
|
|
57
|
+
});
|
|
58
|
+
(0, devkit_1.updateNxJson)(tree, nxJson);
|
|
59
|
+
}
|
|
60
|
+
else if ((0, ts_solution_setup_1.isUsingTsSolutionSetup)(tree)) {
|
|
61
|
+
await addTypescriptPlugin(tree, updatePackageScripts);
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
await (0, internal_1.addPlugin)(tree, await (0, devkit_1.createProjectGraphAsync)(), '@nx/js/typescript', plugin_1.createNodesV2, { typecheck: TYPECHECK_OPTIONS }, updatePackageScripts);
|
|
65
|
+
}
|
|
66
|
+
if (frameworkPlugin) {
|
|
67
|
+
const updated = (0, devkit_1.readNxJson)(tree);
|
|
68
|
+
if (moveTypescriptPluginBefore(updated.plugins, frameworkPlugin)) {
|
|
69
|
+
(0, devkit_1.updateNxJson)(tree, updated);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Registers `@nx/js/typescript`, with only its typecheck target, in a
|
|
75
|
+
* workspace where `frameworkPlugin` no longer infers `typecheck`. Reuses the
|
|
76
|
+
* framework plugin's `typecheckTargetName` and a `tsgo` compiler, and skips
|
|
77
|
+
* workspaces where `@nx/js/typescript` already infers it or where
|
|
78
|
+
* `typecheckTargetName` is `false`. With
|
|
79
|
+
* `removeTypecheckTargetName`, the option is also dropped from the framework
|
|
80
|
+
* plugin's registrations. Returns whether nx.json changed.
|
|
81
|
+
*/
|
|
82
|
+
function registerTypescriptPluginForTypecheck(tree, frameworkPlugin, { removeTypecheckTargetName = false } = {}) {
|
|
83
|
+
const nxJson = (0, devkit_1.readNxJson)(tree);
|
|
84
|
+
if (!nxJson?.plugins?.length) {
|
|
85
|
+
return false;
|
|
86
|
+
}
|
|
87
|
+
const frameworkRegistrations = nxJson.plugins.filter((p) => getPluginName(p) === frameworkPlugin);
|
|
88
|
+
const typecheckOptions = frameworkRegistrations
|
|
89
|
+
.map((p) => (typeof p === 'string' ? {} : (p.options ?? {})))
|
|
90
|
+
.find((options) => options.typecheckTargetName !== false);
|
|
91
|
+
const targetName = typecheckOptions
|
|
92
|
+
? (typecheckOptions.typecheckTargetName ?? 'typecheck')
|
|
93
|
+
: undefined;
|
|
94
|
+
let changed = false;
|
|
95
|
+
if (removeTypecheckTargetName) {
|
|
96
|
+
for (const p of frameworkRegistrations) {
|
|
97
|
+
const options = typeof p === 'string'
|
|
98
|
+
? undefined
|
|
99
|
+
: p.options;
|
|
100
|
+
if (options && 'typecheckTargetName' in options) {
|
|
101
|
+
delete options['typecheckTargetName'];
|
|
102
|
+
changed = true;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
if (targetName && !nxJson.plugins.some(infersTypecheck)) {
|
|
107
|
+
nxJson.plugins.push({
|
|
108
|
+
plugin: '@nx/js/typescript',
|
|
109
|
+
options: {
|
|
110
|
+
typecheck: { targetName },
|
|
111
|
+
...(typecheckOptions.compiler === 'tsgo' ? { compiler: 'tsgo' } : {}),
|
|
112
|
+
},
|
|
113
|
+
});
|
|
114
|
+
moveTypescriptPluginBefore(nxJson.plugins, frameworkPlugin);
|
|
115
|
+
changed = true;
|
|
116
|
+
}
|
|
117
|
+
if (changed) {
|
|
118
|
+
(0, devkit_1.updateNxJson)(tree, nxJson);
|
|
119
|
+
}
|
|
120
|
+
return changed;
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Plugins registered later override same-named targets, so `@nx/js/typescript`
|
|
124
|
+
* goes before a framework plugin that still infers `typecheck`.
|
|
125
|
+
*/
|
|
126
|
+
function moveTypescriptPluginBefore(plugins, frameworkPlugin) {
|
|
127
|
+
const tsIndex = plugins.findIndex(infersTypecheck);
|
|
128
|
+
const frameworkIndex = plugins.findIndex((p) => getPluginName(p) === frameworkPlugin);
|
|
129
|
+
if (tsIndex === -1 || frameworkIndex === -1 || tsIndex < frameworkIndex) {
|
|
130
|
+
return false;
|
|
131
|
+
}
|
|
132
|
+
const [tsPlugin] = plugins.splice(tsIndex, 1);
|
|
133
|
+
plugins.splice(frameworkIndex, 0, tsPlugin);
|
|
134
|
+
return true;
|
|
135
|
+
}
|
|
136
|
+
// Scoped build-only registrations, like `@nx/node`'s tsc apps, set `typecheck: false`.
|
|
137
|
+
function infersTypecheck(plugin) {
|
|
138
|
+
return (getPluginName(plugin) === '@nx/js/typescript' &&
|
|
139
|
+
(typeof plugin === 'string' ||
|
|
140
|
+
plugin.options?.typecheck !==
|
|
141
|
+
false));
|
|
142
|
+
}
|
|
143
|
+
function getPluginName(plugin) {
|
|
144
|
+
return typeof plugin === 'string' ? plugin : plugin.plugin;
|
|
145
|
+
}
|
|
@@ -2,7 +2,7 @@ import { type ProjectConfiguration, type Tree } from '@nx/devkit';
|
|
|
2
2
|
import type { JsonInput } from '@nx/devkit/internal';
|
|
3
3
|
export declare const TS_SOLUTION_SETUP_TSCONFIG_INPUT: JsonInput;
|
|
4
4
|
export declare function isUsingTypeScriptPlugin(tree: Tree): boolean;
|
|
5
|
-
export declare function shouldConfigureTsSolutionSetup(tree: Tree,
|
|
5
|
+
export declare function shouldConfigureTsSolutionSetup(tree: Tree, addTsPlugin?: boolean): boolean;
|
|
6
6
|
export declare function isUsingTsSolutionSetup(tree?: Tree): boolean;
|
|
7
7
|
export declare function assertNotUsingTsSolutionSetup(tree: Tree, pluginName: string, generatorName: string): void;
|
|
8
8
|
export declare function findRuntimeTsConfigName(projectRoot: string, tree?: Tree): string | null;
|
|
@@ -28,19 +28,10 @@ function isUsingTypeScriptPlugin(tree) {
|
|
|
28
28
|
? p === '@nx/js/typescript'
|
|
29
29
|
: p.plugin === '@nx/js/typescript') ?? false);
|
|
30
30
|
}
|
|
31
|
-
function shouldConfigureTsSolutionSetup(tree,
|
|
31
|
+
function shouldConfigureTsSolutionSetup(tree, addTsPlugin) {
|
|
32
32
|
if (addTsPlugin !== undefined) {
|
|
33
33
|
return addTsPlugin;
|
|
34
34
|
}
|
|
35
|
-
if (addPlugins === undefined) {
|
|
36
|
-
const nxJson = (0, devkit_1.readNxJson)(tree);
|
|
37
|
-
addPlugins =
|
|
38
|
-
process.env.NX_ADD_PLUGINS !== 'false' &&
|
|
39
|
-
nxJson.useInferencePlugins !== false;
|
|
40
|
-
}
|
|
41
|
-
if (!addPlugins) {
|
|
42
|
-
return false;
|
|
43
|
-
}
|
|
44
35
|
if (!(0, package_manager_workspaces_1.isUsingPackageManagerWorkspaces)(tree)) {
|
|
45
36
|
return false;
|
|
46
37
|
}
|