@nx/js 19.0.0-beta.4 → 19.0.0-beta.6
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/generators.json +6 -0
- package/package.json +4 -4
- package/src/generators/sync/schema.d.ts +1 -0
- package/src/generators/sync/schema.json +8 -0
- package/src/generators/sync/sync.d.ts +3 -0
- package/src/generators/sync/sync.js +76 -0
- package/src/plugins/typescript/plugin.d.ts +13 -0
- package/src/plugins/typescript/plugin.js +346 -0
- package/typescript.d.ts +1 -0
- package/typescript.js +6 -0
package/generators.json
CHANGED
|
@@ -41,6 +41,12 @@
|
|
|
41
41
|
"schema": "./src/generators/setup-build/schema.json",
|
|
42
42
|
"alias": ["build"],
|
|
43
43
|
"description": "setup-build generator"
|
|
44
|
+
},
|
|
45
|
+
"sync": {
|
|
46
|
+
"factory": "./src/generators/sync/sync#syncGenerator",
|
|
47
|
+
"schema": "./src/generators/sync/schema.json",
|
|
48
|
+
"description": "Synchronize TypeScript project references based on the project graph",
|
|
49
|
+
"hidden": true
|
|
44
50
|
}
|
|
45
51
|
}
|
|
46
52
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nx/js",
|
|
3
|
-
"version": "19.0.0-beta.
|
|
3
|
+
"version": "19.0.0-beta.6",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "The JS plugin for Nx contains executors and generators that provide the best experience for developing JavaScript and TypeScript projects. ",
|
|
6
6
|
"repository": {
|
|
@@ -57,9 +57,9 @@
|
|
|
57
57
|
"semver": "^7.5.3",
|
|
58
58
|
"source-map-support": "0.5.19",
|
|
59
59
|
"tslib": "^2.3.0",
|
|
60
|
-
"@nx/devkit": "19.0.0-beta.
|
|
61
|
-
"@nx/workspace": "19.0.0-beta.
|
|
62
|
-
"@nrwl/js": "19.0.0-beta.
|
|
60
|
+
"@nx/devkit": "19.0.0-beta.6",
|
|
61
|
+
"@nx/workspace": "19.0.0-beta.6",
|
|
62
|
+
"@nrwl/js": "19.0.0-beta.6"
|
|
63
63
|
},
|
|
64
64
|
"peerDependencies": {
|
|
65
65
|
"verdaccio": "^5.0.4"
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export interface SyncSchema {}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.syncGenerator = void 0;
|
|
4
|
+
const devkit_1 = require("@nx/devkit");
|
|
5
|
+
const node_path_1 = require("node:path");
|
|
6
|
+
const plugin_1 = require("../../plugins/typescript/plugin");
|
|
7
|
+
async function syncGenerator(tree, options) {
|
|
8
|
+
// Ensure that the plugin has been wired up in nx.json
|
|
9
|
+
const nxJson = (0, devkit_1.readNxJson)(tree);
|
|
10
|
+
let tscPluginConfig = nxJson.plugins.find((p) => {
|
|
11
|
+
if (typeof p === 'string') {
|
|
12
|
+
return p === plugin_1.PLUGIN_NAME;
|
|
13
|
+
}
|
|
14
|
+
return p.plugin === plugin_1.PLUGIN_NAME;
|
|
15
|
+
});
|
|
16
|
+
if (!tscPluginConfig) {
|
|
17
|
+
throw new Error(`The ${plugin_1.PLUGIN_NAME} plugin must be added to the "plugins" array in nx.json before syncing tsconfigs`);
|
|
18
|
+
}
|
|
19
|
+
const projectGraph = await (0, devkit_1.createProjectGraphAsync)();
|
|
20
|
+
const firstPartyDeps = Object.entries(projectGraph.dependencies).filter(([name, data]) => !name.startsWith('npm:') && data.length > 0);
|
|
21
|
+
// Root tsconfig containing project references for the whole workspace
|
|
22
|
+
const rootTsconfigPath = 'tsconfig.json';
|
|
23
|
+
const rootTsconfig = (0, devkit_1.readJson)(tree, rootTsconfigPath);
|
|
24
|
+
const tsconfigProjectNodeValues = Object.values(projectGraph.nodes).filter((node) => {
|
|
25
|
+
const projectTsconfigPath = (0, devkit_1.joinPathFragments)(node.data.root, 'tsconfig.json');
|
|
26
|
+
return tree.exists(projectTsconfigPath);
|
|
27
|
+
});
|
|
28
|
+
if (tsconfigProjectNodeValues.length > 0) {
|
|
29
|
+
// Sync the root tsconfig references from the project graph (do not destroy existing references)
|
|
30
|
+
rootTsconfig.references = rootTsconfig.references || [];
|
|
31
|
+
const referencesSet = new Set(rootTsconfig.references.map((ref) => normalizeReferencePath(ref.path)));
|
|
32
|
+
for (const node of tsconfigProjectNodeValues) {
|
|
33
|
+
const normalizedPath = normalizeReferencePath(node.data.root);
|
|
34
|
+
// Skip the root tsconfig itself
|
|
35
|
+
if (node.data.root !== '.' && !referencesSet.has(normalizedPath)) {
|
|
36
|
+
rootTsconfig.references.push({ path: `./${normalizedPath}` });
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
(0, devkit_1.writeJson)(tree, rootTsconfigPath, rootTsconfig);
|
|
40
|
+
}
|
|
41
|
+
for (const [name, data] of firstPartyDeps) {
|
|
42
|
+
// Get the source project nodes for the source and target
|
|
43
|
+
const sourceProjectNode = projectGraph.nodes[name];
|
|
44
|
+
// Find the relevant tsconfig files for the source project
|
|
45
|
+
const sourceProjectTsconfigPath = (0, devkit_1.joinPathFragments)(sourceProjectNode.data.root, 'tsconfig.json');
|
|
46
|
+
if (!tree.exists(sourceProjectTsconfigPath)) {
|
|
47
|
+
console.warn(`Skipping project "${name}" as there is no tsconfig.json file found in the project root "${sourceProjectNode.data.root}"`);
|
|
48
|
+
continue;
|
|
49
|
+
}
|
|
50
|
+
const sourceTsconfig = (0, devkit_1.readJson)(tree, sourceProjectTsconfigPath);
|
|
51
|
+
for (const dep of data) {
|
|
52
|
+
// Get the target project node
|
|
53
|
+
const targetProjectNode = projectGraph.nodes[dep.target];
|
|
54
|
+
if (!targetProjectNode) {
|
|
55
|
+
// It's an external dependency
|
|
56
|
+
continue;
|
|
57
|
+
}
|
|
58
|
+
// Set defaults only in the case where we have at least one dependency so that we don't patch files when not necessary
|
|
59
|
+
sourceTsconfig.references = sourceTsconfig.references || [];
|
|
60
|
+
// Ensure the project reference for the target is set
|
|
61
|
+
const relativePathToTargetRoot = (0, node_path_1.relative)(sourceProjectNode.data.root, targetProjectNode.data.root);
|
|
62
|
+
if (!sourceTsconfig.references.some((ref) => ref.path === relativePathToTargetRoot)) {
|
|
63
|
+
// Make sure we unshift rather than push so that dependencies are built in the right order by TypeScript when it is run directly from the root of the workspace
|
|
64
|
+
sourceTsconfig.references.unshift({ path: relativePathToTargetRoot });
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
// Update the source tsconfig files
|
|
68
|
+
(0, devkit_1.writeJson)(tree, sourceProjectTsconfigPath, sourceTsconfig);
|
|
69
|
+
}
|
|
70
|
+
await (0, devkit_1.formatFiles)(tree);
|
|
71
|
+
}
|
|
72
|
+
exports.syncGenerator = syncGenerator;
|
|
73
|
+
// Normalize the paths to strip leading `./` and trailing `/tsconfig.json`
|
|
74
|
+
function normalizeReferencePath(path) {
|
|
75
|
+
return path.replace(/\/tsconfig.json$/, '').replace(/^\.\//, '');
|
|
76
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { type CreateDependencies, type CreateNodes } from '@nx/devkit';
|
|
2
|
+
export interface TscPluginOptions {
|
|
3
|
+
typecheck?: boolean | {
|
|
4
|
+
targetName?: string;
|
|
5
|
+
};
|
|
6
|
+
build?: boolean | {
|
|
7
|
+
targetName?: string;
|
|
8
|
+
configName?: string;
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
export declare const createDependencies: CreateDependencies;
|
|
12
|
+
export declare const PLUGIN_NAME = "@nx/js/typescript";
|
|
13
|
+
export declare const createNodes: CreateNodes<TscPluginOptions>;
|
|
@@ -0,0 +1,346 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createNodes = exports.PLUGIN_NAME = exports.createDependencies = void 0;
|
|
4
|
+
const devkit_1 = require("@nx/devkit");
|
|
5
|
+
const calculate_hash_for_create_nodes_1 = require("@nx/devkit/src/utils/calculate-hash-for-create-nodes");
|
|
6
|
+
const get_named_inputs_1 = require("@nx/devkit/src/utils/get-named-inputs");
|
|
7
|
+
const node_fs_1 = require("node:fs");
|
|
8
|
+
const node_path_1 = require("node:path");
|
|
9
|
+
const minimatch_1 = require("minimatch");
|
|
10
|
+
// eslint-disable-next-line @typescript-eslint/no-restricted-imports
|
|
11
|
+
const lock_file_1 = require("nx/src/plugins/js/lock-file/lock-file");
|
|
12
|
+
const cache_directory_1 = require("nx/src/utils/cache-directory");
|
|
13
|
+
const ts_config_1 = require("../../utils/typescript/ts-config");
|
|
14
|
+
const cachePath = (0, node_path_1.join)(cache_directory_1.projectGraphCacheDirectory, 'tsc.hash');
|
|
15
|
+
const targetsCache = (0, node_fs_1.existsSync)(cachePath) ? readTargetsCache() : {};
|
|
16
|
+
const calculatedTargets = {};
|
|
17
|
+
function readTargetsCache() {
|
|
18
|
+
return (0, devkit_1.readJsonFile)(cachePath);
|
|
19
|
+
}
|
|
20
|
+
function writeTargetsToCache(targets) {
|
|
21
|
+
(0, devkit_1.writeJsonFile)(cachePath, targets);
|
|
22
|
+
}
|
|
23
|
+
const createDependencies = () => {
|
|
24
|
+
writeTargetsToCache(calculatedTargets);
|
|
25
|
+
return [];
|
|
26
|
+
};
|
|
27
|
+
exports.createDependencies = createDependencies;
|
|
28
|
+
exports.PLUGIN_NAME = '@nx/js/typescript';
|
|
29
|
+
exports.createNodes = [
|
|
30
|
+
'**/tsconfig*.json',
|
|
31
|
+
(configFilePath, options, context) => {
|
|
32
|
+
const pluginOptions = normalizePluginOptions(options);
|
|
33
|
+
const projectRoot = (0, node_path_1.dirname)(configFilePath);
|
|
34
|
+
const fullConfigPath = (0, devkit_1.joinPathFragments)(context.workspaceRoot, configFilePath);
|
|
35
|
+
// Do not create a project if package.json and project.json isn't there.
|
|
36
|
+
const siblingFiles = (0, node_fs_1.readdirSync)((0, node_path_1.join)(context.workspaceRoot, projectRoot));
|
|
37
|
+
if (!siblingFiles.includes('package.json') &&
|
|
38
|
+
!siblingFiles.includes('project.json')) {
|
|
39
|
+
return {};
|
|
40
|
+
}
|
|
41
|
+
// Do not create a project if it's not a tsconfig.json and there is no tsconfig.json in the same directory
|
|
42
|
+
if ((0, node_path_1.basename)(configFilePath) !== 'tsconfig.json' &&
|
|
43
|
+
!siblingFiles.includes('tsconfig.json')) {
|
|
44
|
+
return {};
|
|
45
|
+
}
|
|
46
|
+
const hash = (0, calculate_hash_for_create_nodes_1.calculateHashForCreateNodes)(projectRoot, pluginOptions, context, [(0, lock_file_1.getLockFileName)((0, devkit_1.detectPackageManager)(context.workspaceRoot))]);
|
|
47
|
+
const targets = targetsCache[hash]
|
|
48
|
+
? targetsCache[hash]
|
|
49
|
+
: buildTscTargets(fullConfigPath, projectRoot, pluginOptions, context);
|
|
50
|
+
calculatedTargets[hash] = targets;
|
|
51
|
+
return {
|
|
52
|
+
projects: {
|
|
53
|
+
[projectRoot]: {
|
|
54
|
+
projectType: 'library',
|
|
55
|
+
targets,
|
|
56
|
+
},
|
|
57
|
+
},
|
|
58
|
+
};
|
|
59
|
+
},
|
|
60
|
+
];
|
|
61
|
+
function buildTscTargets(configFilePath, projectRoot, options, context) {
|
|
62
|
+
const targets = {};
|
|
63
|
+
const namedInputs = (0, get_named_inputs_1.getNamedInputs)(projectRoot, context);
|
|
64
|
+
const tsConfig = readCachedTsConfig(configFilePath);
|
|
65
|
+
// TODO: check whether we want to always run with --pretty --verbose, it makes replacing scripts harder
|
|
66
|
+
// `--verbose` conflicts with `tsc -b --clean`, might be another reason for not using it, it would
|
|
67
|
+
// prevent users from running the task with `--clean` flag.
|
|
68
|
+
// Should we consider creating a different optional target for `--clean`?
|
|
69
|
+
// Should we consider having a plugin option to disable `--pretty` and `--verbose`?
|
|
70
|
+
let internalProjectReferences;
|
|
71
|
+
// Typecheck target
|
|
72
|
+
if ((0, node_path_1.basename)(configFilePath) === 'tsconfig.json' && options.typecheck) {
|
|
73
|
+
internalProjectReferences = resolveInternalProjectReferences(configFilePath, tsConfig);
|
|
74
|
+
const targetName = options.typecheck.targetName;
|
|
75
|
+
if (!targets[targetName]) {
|
|
76
|
+
let command = `tsc --build --emitDeclarationOnly --pretty --verbose`;
|
|
77
|
+
if (tsConfig.options.noEmit ||
|
|
78
|
+
Object.values(internalProjectReferences).some((ref) => ref.options.noEmit)) {
|
|
79
|
+
// `--emitDeclarationOnly` and `--noEmit` are mutually exclusive, so
|
|
80
|
+
// we remove `--emitDeclarationOnly` if `--noEmit` is set.
|
|
81
|
+
command = `tsc --build --pretty --verbose`;
|
|
82
|
+
}
|
|
83
|
+
targets[targetName] = {
|
|
84
|
+
dependsOn: [`^${targetName}`],
|
|
85
|
+
command,
|
|
86
|
+
options: { cwd: projectRoot },
|
|
87
|
+
cache: true,
|
|
88
|
+
inputs: getInputs(namedInputs, configFilePath, tsConfig, internalProjectReferences, context.workspaceRoot, projectRoot),
|
|
89
|
+
outputs: getOutputs(configFilePath, tsConfig, internalProjectReferences, context.workspaceRoot, projectRoot),
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
// Build target
|
|
94
|
+
if (options.build && (0, node_path_1.basename)(configFilePath) === options.build.configName) {
|
|
95
|
+
internalProjectReferences ??= resolveInternalProjectReferences(configFilePath, tsConfig);
|
|
96
|
+
const targetName = options.build.targetName;
|
|
97
|
+
targets[targetName] = {
|
|
98
|
+
dependsOn: [`^${targetName}`],
|
|
99
|
+
command: `tsc --build ${options.build.configName} --pretty --verbose`,
|
|
100
|
+
options: { cwd: projectRoot },
|
|
101
|
+
cache: true,
|
|
102
|
+
inputs: getInputs(namedInputs, configFilePath, tsConfig, internalProjectReferences, context.workspaceRoot, projectRoot),
|
|
103
|
+
outputs: getOutputs(configFilePath, tsConfig, internalProjectReferences, context.workspaceRoot, projectRoot),
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
return targets;
|
|
107
|
+
}
|
|
108
|
+
function getInputs(namedInputs, configFilePath, tsConfig, internalProjectReferences, workspaceRoot, projectRoot) {
|
|
109
|
+
const configFiles = new Set();
|
|
110
|
+
const includePaths = new Set();
|
|
111
|
+
const excludePaths = new Set();
|
|
112
|
+
const extendedConfigFiles = getExtendedConfigFiles(configFilePath, tsConfig);
|
|
113
|
+
extendedConfigFiles.forEach((configPath) => {
|
|
114
|
+
configFiles.add(configPath);
|
|
115
|
+
});
|
|
116
|
+
const projectTsConfigFiles = [
|
|
117
|
+
[configFilePath, tsConfig],
|
|
118
|
+
...Object.entries(internalProjectReferences),
|
|
119
|
+
];
|
|
120
|
+
projectTsConfigFiles.forEach(([configPath, config]) => {
|
|
121
|
+
configFiles.add(configPath);
|
|
122
|
+
(config.raw?.include ?? []).forEach((p) => includePaths.add(p));
|
|
123
|
+
if (config.raw?.exclude) {
|
|
124
|
+
/**
|
|
125
|
+
* We need to filter out the exclude paths that are already included in
|
|
126
|
+
* other tsconfig files. If they are not included in other tsconfig files,
|
|
127
|
+
* they still correctly apply to the current file and we should keep them.
|
|
128
|
+
*/
|
|
129
|
+
const otherFilesInclude = [];
|
|
130
|
+
projectTsConfigFiles.forEach(([path, c]) => {
|
|
131
|
+
if (path !== configPath) {
|
|
132
|
+
otherFilesInclude.push(...(c.raw?.include ?? []));
|
|
133
|
+
}
|
|
134
|
+
});
|
|
135
|
+
const normalize = (p) => (p.startsWith('./') ? p.slice(2) : p);
|
|
136
|
+
config.raw.exclude.forEach((excludePath) => {
|
|
137
|
+
if (!otherFilesInclude.some((includePath) => (0, minimatch_1.minimatch)(normalize(includePath), normalize(excludePath)) ||
|
|
138
|
+
(0, minimatch_1.minimatch)(normalize(excludePath), normalize(includePath)))) {
|
|
139
|
+
excludePaths.add(excludePath);
|
|
140
|
+
}
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
});
|
|
144
|
+
const inputs = [];
|
|
145
|
+
if (includePaths.size) {
|
|
146
|
+
inputs.push(...Array.from(configFiles).map((p) => pathToInputOrOutput(p, workspaceRoot, projectRoot)), ...Array.from(includePaths).map((p) => (0, devkit_1.joinPathFragments)('{projectRoot}', p)));
|
|
147
|
+
}
|
|
148
|
+
else {
|
|
149
|
+
// If we couldn't identify any include paths, we default to the default
|
|
150
|
+
// named inputs.
|
|
151
|
+
inputs.push('production' in namedInputs ? 'production' : 'default');
|
|
152
|
+
}
|
|
153
|
+
if (excludePaths.size) {
|
|
154
|
+
inputs.push(...Array.from(excludePaths).map((p) => `!${(0, devkit_1.joinPathFragments)('{projectRoot}', p)}`));
|
|
155
|
+
}
|
|
156
|
+
if (hasExternalProjectReferences(configFilePath, tsConfig)) {
|
|
157
|
+
// Importing modules from a referenced project will load its output declaration files (d.ts)
|
|
158
|
+
// https://www.typescriptlang.org/docs/handbook/project-references.html#what-is-a-project-reference
|
|
159
|
+
inputs.push({ dependentTasksOutputFiles: '**/*.d.ts' });
|
|
160
|
+
}
|
|
161
|
+
else {
|
|
162
|
+
inputs.push('production' in namedInputs ? '^production' : '^default');
|
|
163
|
+
}
|
|
164
|
+
inputs.push({ externalDependencies: ['typescript'] });
|
|
165
|
+
return inputs;
|
|
166
|
+
}
|
|
167
|
+
function getOutputs(configFilePath, tsConfig, internalProjectReferences, workspaceRoot, projectRoot) {
|
|
168
|
+
const outputs = new Set();
|
|
169
|
+
// We could have more surgical outputs based on the tsconfig options, but the
|
|
170
|
+
// user could override them through the command line and that wouldn't be
|
|
171
|
+
// reflected in the outputs. So, we just include everything that could be
|
|
172
|
+
// produced by the tsc command.
|
|
173
|
+
[tsConfig, ...Object.values(internalProjectReferences)].forEach((config) => {
|
|
174
|
+
if (config.options.outFile) {
|
|
175
|
+
const outFileName = (0, node_path_1.basename)(config.options.outFile, '.js');
|
|
176
|
+
const outFileDir = (0, node_path_1.dirname)(config.options.outFile);
|
|
177
|
+
outputs.add((0, devkit_1.joinPathFragments)('{workspaceRoot}', (0, node_path_1.relative)(workspaceRoot, config.options.outFile)));
|
|
178
|
+
// outFile is not be used with .cjs, .mjs, .jsx, so the list is simpler
|
|
179
|
+
const outDir = (0, node_path_1.relative)(workspaceRoot, outFileDir);
|
|
180
|
+
outputs.add((0, devkit_1.joinPathFragments)('{workspaceRoot}', outDir, `${outFileName}.js.map`));
|
|
181
|
+
outputs.add((0, devkit_1.joinPathFragments)('{workspaceRoot}', outDir, `${outFileName}.d.ts`));
|
|
182
|
+
outputs.add((0, devkit_1.joinPathFragments)('{workspaceRoot}', outDir, `${outFileName}.d.ts.map`));
|
|
183
|
+
// https://www.typescriptlang.org/tsconfig#tsBuildInfoFile
|
|
184
|
+
outputs.add(tsConfig.options.tsBuildInfoFile
|
|
185
|
+
? pathToInputOrOutput(tsConfig.options.tsBuildInfoFile, workspaceRoot, projectRoot)
|
|
186
|
+
: (0, devkit_1.joinPathFragments)('{workspaceRoot}', outDir, `${outFileName}.tsbuildinfo`));
|
|
187
|
+
}
|
|
188
|
+
else if (config.options.outDir) {
|
|
189
|
+
outputs.add((0, devkit_1.joinPathFragments)('{workspaceRoot}', (0, node_path_1.relative)(workspaceRoot, config.options.outDir)));
|
|
190
|
+
}
|
|
191
|
+
else if (config.fileNames.length) {
|
|
192
|
+
// tsc produce files in place when no outDir or outFile is set
|
|
193
|
+
outputs.add((0, devkit_1.joinPathFragments)('{projectRoot}', '**/*.js'));
|
|
194
|
+
outputs.add((0, devkit_1.joinPathFragments)('{projectRoot}', '**/*.cjs'));
|
|
195
|
+
outputs.add((0, devkit_1.joinPathFragments)('{projectRoot}', '**/*.mjs'));
|
|
196
|
+
outputs.add((0, devkit_1.joinPathFragments)('{projectRoot}', '**/*.jsx'));
|
|
197
|
+
outputs.add((0, devkit_1.joinPathFragments)('{projectRoot}', '**/*.js.map')); // should also include .cjs and .mjs data
|
|
198
|
+
outputs.add((0, devkit_1.joinPathFragments)('{projectRoot}', '**/*.jsx.map'));
|
|
199
|
+
outputs.add((0, devkit_1.joinPathFragments)('{projectRoot}', '**/*.d.ts'));
|
|
200
|
+
outputs.add((0, devkit_1.joinPathFragments)('{projectRoot}', '**/*.d.cts'));
|
|
201
|
+
outputs.add((0, devkit_1.joinPathFragments)('{projectRoot}', '**/*.d.mts'));
|
|
202
|
+
outputs.add((0, devkit_1.joinPathFragments)('{projectRoot}', '**/*.d.ts.map'));
|
|
203
|
+
outputs.add((0, devkit_1.joinPathFragments)('{projectRoot}', '**/*.d.cts.map'));
|
|
204
|
+
outputs.add((0, devkit_1.joinPathFragments)('{projectRoot}', '**/*.d.mts.map'));
|
|
205
|
+
// https://www.typescriptlang.org/tsconfig#tsBuildInfoFile
|
|
206
|
+
const name = (0, node_path_1.basename)(configFilePath, '.json');
|
|
207
|
+
outputs.add(tsConfig.options.tsBuildInfoFile
|
|
208
|
+
? pathToInputOrOutput(tsConfig.options.tsBuildInfoFile, workspaceRoot, projectRoot)
|
|
209
|
+
: (0, devkit_1.joinPathFragments)('{projectRoot}', `${name}.tsbuildinfo`));
|
|
210
|
+
}
|
|
211
|
+
});
|
|
212
|
+
return Array.from(outputs);
|
|
213
|
+
}
|
|
214
|
+
function pathToInputOrOutput(path, workspaceRoot, projectRoot) {
|
|
215
|
+
const pathRelativeToProjectRoot = (0, devkit_1.normalizePath)((0, node_path_1.relative)(projectRoot, path));
|
|
216
|
+
if (pathRelativeToProjectRoot.startsWith('..')) {
|
|
217
|
+
return (0, devkit_1.joinPathFragments)('{workspaceRoot}', (0, node_path_1.relative)(workspaceRoot, path));
|
|
218
|
+
}
|
|
219
|
+
return (0, devkit_1.joinPathFragments)('{projectRoot}', pathRelativeToProjectRoot);
|
|
220
|
+
}
|
|
221
|
+
function getExtendedConfigFiles(tsConfigPath, tsConfig) {
|
|
222
|
+
const extendedConfigFiles = new Set();
|
|
223
|
+
let currentConfigPath = tsConfigPath;
|
|
224
|
+
let currentConfig = tsConfig;
|
|
225
|
+
while (currentConfig.raw?.extends) {
|
|
226
|
+
const extendedConfigPath = (0, node_path_1.join)((0, node_path_1.dirname)(currentConfigPath), currentConfig.raw.extends);
|
|
227
|
+
extendedConfigFiles.add(extendedConfigPath);
|
|
228
|
+
const extendedConfig = readCachedTsConfig(extendedConfigPath);
|
|
229
|
+
currentConfigPath = extendedConfigPath;
|
|
230
|
+
currentConfig = extendedConfig;
|
|
231
|
+
}
|
|
232
|
+
return Array.from(extendedConfigFiles);
|
|
233
|
+
}
|
|
234
|
+
function resolveInternalProjectReferences(configFilePath, tsConfig, projectReferences = {}) {
|
|
235
|
+
if (!tsConfig.projectReferences?.length) {
|
|
236
|
+
return projectReferences;
|
|
237
|
+
}
|
|
238
|
+
const basePath = getTsConfigBasePath(configFilePath);
|
|
239
|
+
for (const ref of tsConfig.projectReferences) {
|
|
240
|
+
let refConfigPath = ref.path;
|
|
241
|
+
if (projectReferences[refConfigPath]) {
|
|
242
|
+
// Already resolved
|
|
243
|
+
continue;
|
|
244
|
+
}
|
|
245
|
+
if (isExternalProjectReference(refConfigPath, basePath)) {
|
|
246
|
+
continue;
|
|
247
|
+
}
|
|
248
|
+
if (!refConfigPath.endsWith('.json')) {
|
|
249
|
+
refConfigPath = (0, node_path_1.join)(refConfigPath, 'tsconfig.json');
|
|
250
|
+
}
|
|
251
|
+
const refTsConfig = readCachedTsConfig(refConfigPath);
|
|
252
|
+
projectReferences[refConfigPath] = refTsConfig;
|
|
253
|
+
resolveInternalProjectReferences(refConfigPath, refTsConfig, projectReferences);
|
|
254
|
+
}
|
|
255
|
+
return projectReferences;
|
|
256
|
+
}
|
|
257
|
+
function hasExternalProjectReferences(tsConfigPath, tsConfig, seen = new Set()) {
|
|
258
|
+
if (!tsConfig.projectReferences?.length) {
|
|
259
|
+
return false;
|
|
260
|
+
}
|
|
261
|
+
seen.add(tsConfigPath);
|
|
262
|
+
const basePath = getTsConfigBasePath(tsConfigPath);
|
|
263
|
+
for (const ref of tsConfig.projectReferences) {
|
|
264
|
+
let refConfigPath = ref.path;
|
|
265
|
+
if (seen.has(refConfigPath)) {
|
|
266
|
+
// Already seen
|
|
267
|
+
continue;
|
|
268
|
+
}
|
|
269
|
+
if (isExternalProjectReference(refConfigPath, basePath)) {
|
|
270
|
+
return true;
|
|
271
|
+
}
|
|
272
|
+
if (!refConfigPath.endsWith('.json')) {
|
|
273
|
+
refConfigPath = (0, node_path_1.join)(refConfigPath, 'tsconfig.json');
|
|
274
|
+
}
|
|
275
|
+
const refTsConfig = readCachedTsConfig(refConfigPath);
|
|
276
|
+
const result = hasExternalProjectReferences(refConfigPath, refTsConfig);
|
|
277
|
+
if (result) {
|
|
278
|
+
return true;
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
return false;
|
|
282
|
+
}
|
|
283
|
+
function isExternalProjectReference(refTsConfigPath, basePath) {
|
|
284
|
+
const refBasePath = getTsConfigBasePath(refTsConfigPath);
|
|
285
|
+
// TODO: there could be internal project references in nested dirs (e.g.
|
|
286
|
+
// our storybook generator generates a nested `.storybook/tsconfig.json`),
|
|
287
|
+
// which would be considered an external project reference but it's not.
|
|
288
|
+
// We could instead check if the referenced tsconfig is outside the project
|
|
289
|
+
// root, but that would cause issues with standalone workspaces with nested
|
|
290
|
+
// projects.
|
|
291
|
+
return refBasePath !== basePath;
|
|
292
|
+
}
|
|
293
|
+
function getTsConfigBasePath(tsConfigPath) {
|
|
294
|
+
return (0, node_fs_1.statSync)(tsConfigPath).isFile() ? (0, node_path_1.dirname)(tsConfigPath) : tsConfigPath;
|
|
295
|
+
}
|
|
296
|
+
// TODO: we could probably persist this to disk to avoid reading the same
|
|
297
|
+
// tsconfig files over multiple runs
|
|
298
|
+
const tsConfigCache = new Map();
|
|
299
|
+
function readCachedTsConfig(tsConfigPath) {
|
|
300
|
+
const cacheKey = getTsConfigCacheKey(tsConfigPath);
|
|
301
|
+
if (tsConfigCache.has(cacheKey)) {
|
|
302
|
+
return tsConfigCache.get(cacheKey);
|
|
303
|
+
}
|
|
304
|
+
const tsConfig = (0, ts_config_1.readTsConfig)(tsConfigPath);
|
|
305
|
+
tsConfigCache.set(cacheKey, tsConfig);
|
|
306
|
+
return tsConfig;
|
|
307
|
+
}
|
|
308
|
+
function getTsConfigCacheKey(tsConfigPath) {
|
|
309
|
+
const timestamp = (0, node_fs_1.statSync)(tsConfigPath).mtimeMs;
|
|
310
|
+
return `${tsConfigPath}-${timestamp}`;
|
|
311
|
+
}
|
|
312
|
+
function normalizePluginOptions(pluginOptions = {}) {
|
|
313
|
+
const defaultTypecheckTargetName = 'typecheck';
|
|
314
|
+
let typecheck = {
|
|
315
|
+
targetName: defaultTypecheckTargetName,
|
|
316
|
+
};
|
|
317
|
+
if (pluginOptions.typecheck === false) {
|
|
318
|
+
typecheck = false;
|
|
319
|
+
}
|
|
320
|
+
else if (pluginOptions.typecheck &&
|
|
321
|
+
typeof pluginOptions.typecheck !== 'boolean') {
|
|
322
|
+
typecheck = {
|
|
323
|
+
targetName: pluginOptions.typecheck.targetName ?? defaultTypecheckTargetName,
|
|
324
|
+
};
|
|
325
|
+
}
|
|
326
|
+
const defaultBuildTargetName = 'build';
|
|
327
|
+
const defaultBuildConfigName = 'tsconfig.lib.json';
|
|
328
|
+
let build = {
|
|
329
|
+
targetName: defaultBuildTargetName,
|
|
330
|
+
configName: defaultBuildConfigName,
|
|
331
|
+
};
|
|
332
|
+
// Build target is not enabled by default
|
|
333
|
+
if (!pluginOptions.build) {
|
|
334
|
+
build = false;
|
|
335
|
+
}
|
|
336
|
+
else if (pluginOptions.build && typeof pluginOptions.build !== 'boolean') {
|
|
337
|
+
build = {
|
|
338
|
+
targetName: pluginOptions.build.targetName ?? defaultBuildTargetName,
|
|
339
|
+
configName: pluginOptions.build.configName ?? defaultBuildConfigName,
|
|
340
|
+
};
|
|
341
|
+
}
|
|
342
|
+
return {
|
|
343
|
+
typecheck,
|
|
344
|
+
build,
|
|
345
|
+
};
|
|
346
|
+
}
|
package/typescript.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { createDependencies, createNodes, } from './src/plugins/typescript/plugin';
|
package/typescript.js
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createNodes = exports.createDependencies = void 0;
|
|
4
|
+
var plugin_1 = require("./src/plugins/typescript/plugin");
|
|
5
|
+
Object.defineProperty(exports, "createDependencies", { enumerable: true, get: function () { return plugin_1.createDependencies; } });
|
|
6
|
+
Object.defineProperty(exports, "createNodes", { enumerable: true, get: function () { return plugin_1.createNodes; } });
|