@plugjs/tsgo 0.0.6 → 0.1.1

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/src/utils.ts ADDED
@@ -0,0 +1,64 @@
1
+ import { assert } from '@plugjs/plug/asserts'
2
+ import { resolveFile } from '@plugjs/plug/paths'
3
+ import { EmitOnly } from 'typescript/async'
4
+
5
+ import type { TypeScriptOptions } from './index.ts'
6
+ import type { AbsolutePath } from '@plugjs/plug/paths'
7
+
8
+ /**
9
+ * Find the TypeScript project configuration file for a given path.
10
+ *
11
+ * The path specified can be a `tsconfig.json` file name or a directory
12
+ * containing a `tsconfig.json` file.
13
+ *
14
+ * The returned path is the absolute path of the actual `tsconfig.json` file.
15
+ */
16
+ export function findProjectConfig(path: AbsolutePath): AbsolutePath {
17
+ // The specified path can be either a file or a directory containing a
18
+ // "tsconfig.json" file: resolve as a file, then assume it's a directory
19
+ let file = resolveFile(path)
20
+ if (!file) file = resolveFile(path, 'tsconfig.json')
21
+ assert(file, `TypeScript configuration file not found in "${path}"`)
22
+ return file
23
+ }
24
+
25
+ /** Convert a diagnostic level option for deprecations into a consistent value. */
26
+ export function diagnosticDeprecationLevel(
27
+ deprecations?: TypeScriptOptions['reportDeprecations'],
28
+ ): 'warn' | 'notice' | 'off' {
29
+ switch (deprecations) {
30
+ // If *warn* we report deprecations as warnings
31
+ case 'warn':
32
+ return 'warn'
33
+ // If *off* or *false* we don't report deprecations at all
34
+ case 'off':
35
+ case false:
36
+ return 'off'
37
+ // If *notice* or *true* (default) we report deprecations as notices
38
+ /* coverage ignore next */ case 'notice':
39
+ /* coverage ignore next */ case true:
40
+ default:
41
+ return 'notice'
42
+ }
43
+ }
44
+
45
+ /** Convert a emit only option into its corresponding enum value. */
46
+ export function emitOnlyOption(emitOnly?: TypeScriptOptions['emitOnly']): EmitOnly | null {
47
+ switch (emitOnly) {
48
+ // If *none* or *false* we don't emit anything
49
+ case 'none':
50
+ case false:
51
+ return null // This is "none"
52
+ // If *js* we only emit JavaScript files
53
+ case 'js':
54
+ return EmitOnly.OnlyJs
55
+ // If *dts* we only emit declaration files
56
+ case 'dts':
57
+ return EmitOnly.OnlyDts
58
+ // In all other cases we emit all files
59
+ /* coverage ignore next */ case 'all':
60
+ /* coverage ignore next */ case true:
61
+ default:
62
+ return EmitOnly.All
63
+ }
64
+ }
@@ -1,72 +0,0 @@
1
- import type { ReportRecord } from '@plugjs/plug/logging';
2
- import type { AbsolutePath } from '@plugjs/plug/paths';
3
- import type { API, ParsedCommandLine } from 'typescript/unstable/async';
4
- /** Interface describing the actual (resolved) config file and its references */
5
- interface ProjectReferences {
6
- /** The actual path of the configuration file containing the references */
7
- path: AbsolutePath;
8
- /** The actual configuration parsed from the configuration file */
9
- config: ParsedCommandLine;
10
- /** The actual paths of all configuration files referenced by this project */
11
- references: AbsolutePath[];
12
- /** Any errors encountered while reading the configuration file */
13
- errors: ReportRecord[];
14
- }
15
- /** Interface describing a group of cross-referencing projects */
16
- interface Projects {
17
- /** All projects to build, each associated with its referencing projects */
18
- projects: Map<AbsolutePath, Set<AbsolutePath>>;
19
- /** Any errors encountered while reading the configuration files */
20
- errors: ReportRecord[];
21
- }
22
- /** Interface describing the order of projects, including any cycles and unresolved projects */
23
- interface ProjectOrder {
24
- /** The order in which projects should be built */
25
- order: AbsolutePath[];
26
- /** Array of project reference cycles */
27
- cycles: AbsolutePath[][];
28
- /** Array containing all projects that could not be ordered because of cyclical dependencies */
29
- unresolved: AbsolutePath[];
30
- /** Any errors encountered while resolving the project order */
31
- errors: ReportRecord[];
32
- }
33
- /**
34
- * Find the TypeScript project configuration file for a given path.
35
- *
36
- * The path specified can be a `tsconfig.json` file name or a directory
37
- * containing a `tsconfig.json` file.
38
- *
39
- * The returned path is the absolute path of the actual `tsconfig.json` file.
40
- */
41
- export declare function findProjectConfig(path: AbsolutePath): AbsolutePath;
42
- /**
43
- * Read the TypeScript project configuration file for a given path.
44
- *
45
- * The path specified can be a `tsconfig.json` file name or a directory
46
- * containing a `tsconfig.json` file.
47
- *
48
- * The returned object contains the resolved configuration file name (in `path`)
49
- * and the array of resolved project references (the actual resolved files on
50
- * disk in `references`).
51
- *
52
- * Any errors encountered while reading the configuration file or resolving its
53
- * references are returned in the `errors` array.
54
- */
55
- export declare function readProjectConfig(api: API, path: AbsolutePath): Promise<ProjectReferences>;
56
- /**
57
- * Find _all_ project references given a set of initial project paths.
58
- *
59
- * The returned map contains all the projects (resolved configuration file
60
- * names) and their referring projects as values.
61
- */
62
- export declare function findProjectReferences(api: API, ...paths: AbsolutePath[]): Promise<Projects>;
63
- /**
64
- * Use Kahn's topological-sort algorithm on a map of projects and their
65
- * references to determine the order in which they should be built.
66
- *
67
- * @param projects A map of projects and their referring projects
68
- * @returns The order of projects, any unresolved projects, and cycles found
69
- */
70
- export declare function resolveProjectOrder(projects: ReadonlyMap<AbsolutePath, Set<AbsolutePath>>): ProjectOrder;
71
- export {};
72
- //# sourceMappingURL=projects.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"projects.d.ts","sourceRoot":"","sources":["../src/projects.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAA;AACxD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AACtD,OAAO,KAAK,EAAE,GAAG,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAA;AAEvE,gFAAgF;AAChF,UAAU,iBAAiB;IACzB,0EAA0E;IAC1E,IAAI,EAAE,YAAY,CAAA;IAClB,kEAAkE;IAClE,MAAM,EAAE,iBAAiB,CAAA;IACzB,6EAA6E;IAC7E,UAAU,EAAE,YAAY,EAAE,CAAA;IAC1B,kEAAkE;IAClE,MAAM,EAAE,YAAY,EAAE,CAAA;CACvB;AAED,iEAAiE;AACjE,UAAU,QAAQ;IAChB,2EAA2E;IAC3E,QAAQ,EAAE,GAAG,CAAC,YAAY,EAAE,GAAG,CAAC,YAAY,CAAC,CAAC,CAAA;IAC9C,mEAAmE;IACnE,MAAM,EAAE,YAAY,EAAE,CAAA;CACvB;AAED,+FAA+F;AAC/F,UAAU,YAAY;IACpB,kDAAkD;IAClD,KAAK,EAAE,YAAY,EAAE,CAAA;IACrB,wCAAwC;IACxC,MAAM,EAAE,YAAY,EAAE,EAAE,CAAA;IACxB,+FAA+F;IAC/F,UAAU,EAAE,YAAY,EAAE,CAAA;IAC1B,+DAA+D;IAC/D,MAAM,EAAE,YAAY,EAAE,CAAA;CACvB;AAID;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,YAAY,GAAG,YAAY,CAOlE;AAED;;;;;;;;;;;;GAYG;AACH,wBAAsB,iBAAiB,CAAC,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,YAAY,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAqChG;AAED;;;;;GAKG;AACH,wBAAsB,qBAAqB,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,KAAK,EAAE,YAAY,EAAE,GAAG,OAAO,CAAC,QAAQ,CAAC,CAkDjG;AAED;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,WAAW,CAAC,YAAY,EAAE,GAAG,CAAC,YAAY,CAAC,CAAC,GAAG,YAAY,CA4FxG"}
package/dist/projects.js DELETED
@@ -1,209 +0,0 @@
1
- import { assert } from '@plugjs/plug/asserts';
2
- import { $gry, $p, $ylw, ERROR } from '@plugjs/plug/logging';
3
- import { assertAbsolutePath, getAbsoluteParent, resolveFile } from '@plugjs/plug/paths';
4
- import { convertProjectDiagnostics } from './diagnostics.js';
5
- /* ========================================================================== */
6
- /**
7
- * Find the TypeScript project configuration file for a given path.
8
- *
9
- * The path specified can be a `tsconfig.json` file name or a directory
10
- * containing a `tsconfig.json` file.
11
- *
12
- * The returned path is the absolute path of the actual `tsconfig.json` file.
13
- */
14
- export function findProjectConfig(path) {
15
- // The specified path can be either a file or a directory containing a
16
- // "tsconfig.json" file: resolve as a file, then assume it's a directory
17
- let file = resolveFile(path);
18
- if (!file)
19
- file = resolveFile(path, 'tsconfig.json');
20
- assert(file, `TypeScript configuration file not found in "${path}"`);
21
- return file;
22
- }
23
- /**
24
- * Read the TypeScript project configuration file for a given path.
25
- *
26
- * The path specified can be a `tsconfig.json` file name or a directory
27
- * containing a `tsconfig.json` file.
28
- *
29
- * The returned object contains the resolved configuration file name (in `path`)
30
- * and the array of resolved project references (the actual resolved files on
31
- * disk in `references`).
32
- *
33
- * Any errors encountered while reading the configuration file or resolving its
34
- * references are returned in the `errors` array.
35
- */
36
- export async function readProjectConfig(api, path) {
37
- const file = findProjectConfig(path);
38
- // Use the TypeScript API to load up this project... We already update the
39
- // snapshot here, so we don't need to do it again once we end up compiling
40
- // the whole project...
41
- const snapshot = await api.updateSnapshot({ openProjects: [file] });
42
- const project = snapshot.getProject(file);
43
- assert(project, `Failed to open TypeScript project from "${file}"`);
44
- assertAbsolutePath(project.configFileName);
45
- path = project.configFileName; // rewrite the path to the actual
46
- // Get any diagnostics encountered while parsing the configuration file
47
- // and any "global" diagnostics (not associated with a specific file)...
48
- const diagnostics = await Promise.all([
49
- project.program.getGlobalDiagnostics(),
50
- project.program.getProgramDiagnostics(),
51
- project.program.getConfigFileParsingDiagnostics(),
52
- ]).then((results) => results.flat());
53
- // Convert the diagnostics to our simplified format
54
- const errors = await convertProjectDiagnostics(diagnostics, project.program, path);
55
- // Prepare our simplified result object
56
- const config = project.parsedCommandLine;
57
- const result = { path, errors, config, references: [] };
58
- // Resolve the references to absolute paths
59
- const directory = getAbsoluteParent(path);
60
- for (const reference of config.projectReferences ?? []) {
61
- let resolved = resolveFile(directory, reference.path);
62
- if (!resolved)
63
- resolved = resolveFile(directory, reference.path, 'tsconfig.json');
64
- if (resolved)
65
- result.references.push(resolved);
66
- }
67
- // All done
68
- return result;
69
- }
70
- /**
71
- * Find _all_ project references given a set of initial project paths.
72
- *
73
- * The returned map contains all the projects (resolved configuration file
74
- * names) and their referring projects as values.
75
- */
76
- export async function findProjectReferences(api, ...paths) {
77
- // The set of *all* projects, whether we have resolved them yet or not.
78
- const remainingProjects = new Set(paths);
79
- // The set of all *resolved* projects (that is, opened and parsed)
80
- const resolvedProjects = new Set();
81
- // The map of all our projects, keyed by their resolved configuration file
82
- // name and having the set of projects that refer to it as a value
83
- const projects = new Map();
84
- // An array of all errors encountered while reading the configuration files
85
- const errors = [];
86
- // Add a referring project to the set of referring projects for a referred project
87
- function addProject(referredProject, referringProject) {
88
- let referringProjects = projects.get(referredProject);
89
- if (!referringProjects) {
90
- referringProjects = new Set();
91
- projects.set(referredProject, referringProjects);
92
- }
93
- if (referringProject)
94
- referringProjects.add(referringProject);
95
- }
96
- while (remainingProjects.size > 0) {
97
- // Take and remove the next project from the remaining set
98
- const project = remainingProjects.values().next().value;
99
- remainingProjects.delete(project);
100
- // Read the project configuration file and its references
101
- const { path, references, errors: e } = await readProjectConfig(api, project);
102
- // If we already resolved this project, skip it
103
- if (resolvedProjects.has(path))
104
- continue;
105
- // Push any errors encountered while reading the configuration file
106
- errors.push(...e);
107
- // Add the project (resolved filename) to the resolved set
108
- resolvedProjects.add(path);
109
- // Record the project and its references in our map of projects
110
- addProject(path);
111
- // Look at all the project references
112
- for (const reference of references) {
113
- // If we haven't resolved this reference yet, add it to the remaining
114
- if (!resolvedProjects.has(reference))
115
- remainingProjects.add(reference);
116
- // Then make sure that we record the referring project for this reference
117
- addProject(reference, path);
118
- }
119
- }
120
- // Return our projects map and all errors
121
- return { projects, errors };
122
- }
123
- /**
124
- * Use Kahn's topological-sort algorithm on a map of projects and their
125
- * references to determine the order in which they should be built.
126
- *
127
- * @param projects A map of projects and their referring projects
128
- * @returns The order of projects, any unresolved projects, and cycles found
129
- */
130
- export function resolveProjectOrder(projects) {
131
- // The number of unresolved dependencies for each project
132
- const counts = Object.create(null);
133
- // Iterate through all the projects (and their referring projects), counting
134
- // the number of unresolved dependencies for each project.
135
- for (const [referred, referring] of projects.entries()) {
136
- // Ensure the referred project has a dependencies count (even if it is zero)
137
- counts[referred] = counts[referred] ?? 0;
138
- // For each referring project, increment its count of unresolved dependencies
139
- for (const ref of referring)
140
- counts[ref] = (counts[ref] ?? 0) + 1;
141
- }
142
- // The unique set of all known projects (referred and referring)
143
- const uniques = Object.keys(counts);
144
- // Projects are "ready" when all dependencies have been resolved (zero count)
145
- const ready = uniques.filter((project) => counts[project] === 0);
146
- // The final order of projects (in dependency order)
147
- const order = [];
148
- // While there are still projects ready to be processed, take the first one
149
- for (let project = ready.shift(); project; project = ready.shift()) {
150
- // Add the project to the final order
151
- order.push(project);
152
- // For each project that depends on this project, decrement its unresolved
153
- // dependency count. If it reaches zero, add it to the ready queue.
154
- for (const dependent of projects.get(project) ?? /* coverage ignore next */ []) {
155
- const remaining = (counts[dependent] = counts[dependent] - 1);
156
- if (remaining === 0)
157
- ready.push(dependent);
158
- }
159
- }
160
- // When no more projects are "ready", the remaining projects are unresolved
161
- const unresolved = uniques.filter((project) => counts[project]);
162
- // If we have no unresolved projects, we can return the order (no cycles)
163
- if (unresolved.length === 0)
164
- return { order, unresolved, cycles: [], errors: [] };
165
- // ===== FIND CYCLES =========================================================
166
- // Projects we _already_ visited (and thus don't need to visit again)
167
- const visited = new Set();
168
- // The list of cycles we have found (each cycle is a list of projects)
169
- const cycles = [];
170
- // Recursively visit a project's dependents, looking for cycles
171
- function visit(project, stack = []) {
172
- // If this project is already in the current path, we found a cycle
173
- const index = stack.indexOf(project);
174
- if (index >= 0) {
175
- cycles.push([...stack.slice(index), project]);
176
- return;
177
- }
178
- // Don't revisit projects whose dependents have all been processed
179
- if (visited.has(project))
180
- return;
181
- // Add this project to the current path and visit its dependents
182
- const next = [...stack, project];
183
- for (const dependent of projects.get(project) ?? /* coverage ignore next */ []) {
184
- if (unresolved.includes(dependent))
185
- visit(dependent, next);
186
- }
187
- // Mark the project as visited after all its dependents have been processed
188
- visited.add(project);
189
- }
190
- // Visit all the unresolved projects, looking for cycles
191
- for (const project of unresolved)
192
- visit(project);
193
- // Prep our errors
194
- const errors = [];
195
- errors.push({
196
- level: ERROR,
197
- message: `Found ${$ylw(unresolved.length)} unresolved projects (${$ylw(cycles.length)} cycles)` +
198
- `\n${$gry('-')} ${unresolved.map($p).join(`\n${$gry('-')} `)}`,
199
- });
200
- for (const cycle of cycles) {
201
- errors.push({
202
- level: ERROR,
203
- message: `Project reference cycle:\n${$gry('-')} ${cycle.map($p).join(`\n${$gry('-')} `)}`,
204
- });
205
- }
206
- // Return the final order, unresolved projects, and cycles found
207
- return { order, unresolved, cycles, errors };
208
- }
209
- //# sourceMappingURL=projects.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"projects.js","sourceRoot":"","sources":["../src/projects.ts"],"names":[],"mappings":"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"}
package/src/projects.ts DELETED
@@ -1,271 +0,0 @@
1
- import { assert } from '@plugjs/plug/asserts'
2
- import { $gry, $p, $ylw, ERROR } from '@plugjs/plug/logging'
3
- import { assertAbsolutePath, getAbsoluteParent, resolveFile } from '@plugjs/plug/paths'
4
-
5
- import { convertProjectDiagnostics } from './diagnostics.ts'
6
-
7
- import type { ReportRecord } from '@plugjs/plug/logging'
8
- import type { AbsolutePath } from '@plugjs/plug/paths'
9
- import type { API, ParsedCommandLine } from 'typescript/unstable/async'
10
-
11
- /** Interface describing the actual (resolved) config file and its references */
12
- interface ProjectReferences {
13
- /** The actual path of the configuration file containing the references */
14
- path: AbsolutePath
15
- /** The actual configuration parsed from the configuration file */
16
- config: ParsedCommandLine
17
- /** The actual paths of all configuration files referenced by this project */
18
- references: AbsolutePath[]
19
- /** Any errors encountered while reading the configuration file */
20
- errors: ReportRecord[]
21
- }
22
-
23
- /** Interface describing a group of cross-referencing projects */
24
- interface Projects {
25
- /** All projects to build, each associated with its referencing projects */
26
- projects: Map<AbsolutePath, Set<AbsolutePath>>
27
- /** Any errors encountered while reading the configuration files */
28
- errors: ReportRecord[]
29
- }
30
-
31
- /** Interface describing the order of projects, including any cycles and unresolved projects */
32
- interface ProjectOrder {
33
- /** The order in which projects should be built */
34
- order: AbsolutePath[]
35
- /** Array of project reference cycles */
36
- cycles: AbsolutePath[][]
37
- /** Array containing all projects that could not be ordered because of cyclical dependencies */
38
- unresolved: AbsolutePath[]
39
- /** Any errors encountered while resolving the project order */
40
- errors: ReportRecord[]
41
- }
42
-
43
- /* ========================================================================== */
44
-
45
- /**
46
- * Find the TypeScript project configuration file for a given path.
47
- *
48
- * The path specified can be a `tsconfig.json` file name or a directory
49
- * containing a `tsconfig.json` file.
50
- *
51
- * The returned path is the absolute path of the actual `tsconfig.json` file.
52
- */
53
- export function findProjectConfig(path: AbsolutePath): AbsolutePath {
54
- // The specified path can be either a file or a directory containing a
55
- // "tsconfig.json" file: resolve as a file, then assume it's a directory
56
- let file = resolveFile(path)
57
- if (!file) file = resolveFile(path, 'tsconfig.json')
58
- assert(file, `TypeScript configuration file not found in "${path}"`)
59
- return file
60
- }
61
-
62
- /**
63
- * Read the TypeScript project configuration file for a given path.
64
- *
65
- * The path specified can be a `tsconfig.json` file name or a directory
66
- * containing a `tsconfig.json` file.
67
- *
68
- * The returned object contains the resolved configuration file name (in `path`)
69
- * and the array of resolved project references (the actual resolved files on
70
- * disk in `references`).
71
- *
72
- * Any errors encountered while reading the configuration file or resolving its
73
- * references are returned in the `errors` array.
74
- */
75
- export async function readProjectConfig(api: API, path: AbsolutePath): Promise<ProjectReferences> {
76
- const file = findProjectConfig(path)
77
-
78
- // Use the TypeScript API to load up this project... We already update the
79
- // snapshot here, so we don't need to do it again once we end up compiling
80
- // the whole project...
81
- const snapshot = await api.updateSnapshot({ openProjects: [file] })
82
- const project = snapshot.getProject(file)
83
- assert(project, `Failed to open TypeScript project from "${file}"`)
84
- assertAbsolutePath(project.configFileName)
85
- path = project.configFileName // rewrite the path to the actual
86
-
87
- // Get any diagnostics encountered while parsing the configuration file
88
- // and any "global" diagnostics (not associated with a specific file)...
89
- const diagnostics = await Promise.all([
90
- project.program.getGlobalDiagnostics(),
91
- project.program.getProgramDiagnostics(),
92
- project.program.getConfigFileParsingDiagnostics(),
93
- ]).then((results) => results.flat())
94
-
95
- // Convert the diagnostics to our simplified format
96
- const errors = await convertProjectDiagnostics(diagnostics, project.program, path)
97
-
98
- // Prepare our simplified result object
99
- const config = project.parsedCommandLine
100
- const result: ProjectReferences = { path, errors, config, references: [] }
101
-
102
- // Resolve the references to absolute paths
103
- const directory = getAbsoluteParent(path)
104
- for (const reference of config.projectReferences ?? []) {
105
- let resolved = resolveFile(directory, reference.path)
106
- if (!resolved) resolved = resolveFile(directory, reference.path, 'tsconfig.json')
107
- if (resolved) result.references.push(resolved)
108
- }
109
-
110
- // All done
111
- return result
112
- }
113
-
114
- /**
115
- * Find _all_ project references given a set of initial project paths.
116
- *
117
- * The returned map contains all the projects (resolved configuration file
118
- * names) and their referring projects as values.
119
- */
120
- export async function findProjectReferences(api: API, ...paths: AbsolutePath[]): Promise<Projects> {
121
- // The set of *all* projects, whether we have resolved them yet or not.
122
- const remainingProjects = new Set<AbsolutePath>(paths)
123
- // The set of all *resolved* projects (that is, opened and parsed)
124
- const resolvedProjects = new Set<AbsolutePath>()
125
-
126
- // The map of all our projects, keyed by their resolved configuration file
127
- // name and having the set of projects that refer to it as a value
128
- const projects = new Map<AbsolutePath, Set<AbsolutePath>>()
129
-
130
- // An array of all errors encountered while reading the configuration files
131
- const errors: ReportRecord[] = []
132
-
133
- // Add a referring project to the set of referring projects for a referred project
134
- function addProject(referredProject: AbsolutePath, referringProject?: AbsolutePath): void {
135
- let referringProjects = projects.get(referredProject)
136
- if (!referringProjects) {
137
- referringProjects = new Set()
138
- projects.set(referredProject, referringProjects)
139
- }
140
- if (referringProject) referringProjects.add(referringProject)
141
- }
142
-
143
- while (remainingProjects.size > 0) {
144
- // Take and remove the next project from the remaining set
145
- const project = remainingProjects.values().next().value!
146
- remainingProjects.delete(project)
147
-
148
- // Read the project configuration file and its references
149
- const { path, references, errors: e } = await readProjectConfig(api, project)
150
- // If we already resolved this project, skip it
151
- if (resolvedProjects.has(path)) continue
152
- // Push any errors encountered while reading the configuration file
153
- errors.push(...e)
154
- // Add the project (resolved filename) to the resolved set
155
- resolvedProjects.add(path)
156
- // Record the project and its references in our map of projects
157
- addProject(path)
158
-
159
- // Look at all the project references
160
- for (const reference of references) {
161
- // If we haven't resolved this reference yet, add it to the remaining
162
- if (!resolvedProjects.has(reference)) remainingProjects.add(reference)
163
- // Then make sure that we record the referring project for this reference
164
- addProject(reference, path)
165
- }
166
- }
167
-
168
- // Return our projects map and all errors
169
- return { projects, errors }
170
- }
171
-
172
- /**
173
- * Use Kahn's topological-sort algorithm on a map of projects and their
174
- * references to determine the order in which they should be built.
175
- *
176
- * @param projects A map of projects and their referring projects
177
- * @returns The order of projects, any unresolved projects, and cycles found
178
- */
179
- export function resolveProjectOrder(projects: ReadonlyMap<AbsolutePath, Set<AbsolutePath>>): ProjectOrder {
180
- // The number of unresolved dependencies for each project
181
- const counts: Record<AbsolutePath, number> = Object.create(null)
182
-
183
- // Iterate through all the projects (and their referring projects), counting
184
- // the number of unresolved dependencies for each project.
185
- for (const [referred, referring] of projects.entries()) {
186
- // Ensure the referred project has a dependencies count (even if it is zero)
187
- counts[referred] = counts[referred] ?? 0
188
- // For each referring project, increment its count of unresolved dependencies
189
- for (const ref of referring) counts[ref] = (counts[ref] ?? 0) + 1
190
- }
191
-
192
- // The unique set of all known projects (referred and referring)
193
- const uniques = Object.keys(counts) as AbsolutePath[]
194
-
195
- // Projects are "ready" when all dependencies have been resolved (zero count)
196
- const ready = uniques.filter((project) => counts[project] === 0)
197
-
198
- // The final order of projects (in dependency order)
199
- const order: AbsolutePath[] = []
200
-
201
- // While there are still projects ready to be processed, take the first one
202
- for (let project = ready.shift(); project; project = ready.shift()) {
203
- // Add the project to the final order
204
- order.push(project)
205
-
206
- // For each project that depends on this project, decrement its unresolved
207
- // dependency count. If it reaches zero, add it to the ready queue.
208
- for (const dependent of projects.get(project) ?? /* coverage ignore next */ []) {
209
- const remaining = (counts[dependent] = counts[dependent]! - 1)
210
- if (remaining === 0) ready.push(dependent)
211
- }
212
- }
213
-
214
- // When no more projects are "ready", the remaining projects are unresolved
215
- const unresolved = uniques.filter((project) => counts[project])
216
-
217
- // If we have no unresolved projects, we can return the order (no cycles)
218
- if (unresolved.length === 0) return { order, unresolved, cycles: [], errors: [] }
219
-
220
- // ===== FIND CYCLES =========================================================
221
-
222
- // Projects we _already_ visited (and thus don't need to visit again)
223
- const visited = new Set<AbsolutePath>()
224
-
225
- // The list of cycles we have found (each cycle is a list of projects)
226
- const cycles: AbsolutePath[][] = []
227
-
228
- // Recursively visit a project's dependents, looking for cycles
229
- function visit(project: AbsolutePath, stack: AbsolutePath[] = []): void {
230
- // If this project is already in the current path, we found a cycle
231
- const index = stack.indexOf(project)
232
- if (index >= 0) {
233
- cycles.push([...stack.slice(index), project])
234
- return
235
- }
236
-
237
- // Don't revisit projects whose dependents have all been processed
238
- if (visited.has(project)) return
239
-
240
- // Add this project to the current path and visit its dependents
241
- const next = [...stack, project]
242
- for (const dependent of projects.get(project) ?? /* coverage ignore next */ []) {
243
- if (unresolved.includes(dependent)) visit(dependent, next)
244
- }
245
-
246
- // Mark the project as visited after all its dependents have been processed
247
- visited.add(project)
248
- }
249
-
250
- // Visit all the unresolved projects, looking for cycles
251
- for (const project of unresolved) visit(project)
252
-
253
- // Prep our errors
254
- const errors: ReportRecord[] = []
255
- errors.push({
256
- level: ERROR,
257
- message:
258
- `Found ${$ylw(unresolved.length)} unresolved projects (${$ylw(cycles.length)} cycles)` +
259
- `\n${$gry('-')} ${unresolved.map($p).join(`\n${$gry('-')} `)}`,
260
- })
261
-
262
- for (const cycle of cycles) {
263
- errors.push({
264
- level: ERROR,
265
- message: `Project reference cycle:\n${$gry('-')} ${cycle.map($p).join(`\n${$gry('-')} `)}`,
266
- })
267
- }
268
-
269
- // Return the final order, unresolved projects, and cycles found
270
- return { order, unresolved, cycles, errors }
271
- }