@matter/tools 0.11.1 → 0.11.2-alpha.0-20241102-aa282dab8
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/README.md +2 -2
- package/dist/cjs/building/builder.d.ts.map +1 -1
- package/dist/cjs/building/builder.js.map +1 -1
- package/dist/cjs/building/cli.d.ts.map +1 -1
- package/dist/cjs/building/cli.js +27 -5
- package/dist/cjs/building/cli.js.map +1 -1
- package/dist/cjs/building/docs.d.ts +18 -0
- package/dist/cjs/building/docs.d.ts.map +1 -0
- package/dist/cjs/building/docs.js +249 -0
- package/dist/cjs/building/docs.js.map +6 -0
- package/dist/cjs/index.d.ts +1 -1
- package/dist/cjs/index.d.ts.map +1 -1
- package/dist/cjs/index.js +1 -1
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/util/{files.d.ts → file.d.ts} +3 -1
- package/dist/cjs/util/file.d.ts.map +1 -0
- package/dist/cjs/util/{files.js → file.js} +21 -7
- package/dist/cjs/util/file.js.map +6 -0
- package/dist/cjs/util/index.d.ts +1 -1
- package/dist/cjs/util/index.d.ts.map +1 -1
- package/dist/cjs/util/index.js +1 -1
- package/dist/cjs/util/index.js.map +1 -1
- package/dist/cjs/util/package.d.ts +11 -0
- package/dist/cjs/util/package.d.ts.map +1 -1
- package/dist/cjs/util/package.js +104 -4
- package/dist/cjs/util/package.js.map +1 -1
- package/dist/cjs/util/progress.d.ts +1 -0
- package/dist/cjs/util/progress.d.ts.map +1 -1
- package/dist/cjs/util/progress.js +5 -3
- package/dist/cjs/util/progress.js.map +1 -1
- package/dist/esm/building/builder.d.ts.map +1 -1
- package/dist/esm/building/builder.js +1 -1
- package/dist/esm/building/builder.js.map +1 -1
- package/dist/esm/building/cli.d.ts.map +1 -1
- package/dist/esm/building/cli.js +28 -6
- package/dist/esm/building/cli.js.map +1 -1
- package/dist/esm/building/docs.d.ts +18 -0
- package/dist/esm/building/docs.d.ts.map +1 -0
- package/dist/esm/building/docs.js +237 -0
- package/dist/esm/building/docs.js.map +6 -0
- package/dist/esm/index.d.ts +1 -1
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js +2 -2
- package/dist/esm/util/{files.d.ts → file.d.ts} +3 -1
- package/dist/esm/util/file.d.ts.map +1 -0
- package/dist/esm/util/file.js +140 -0
- package/dist/esm/util/file.js.map +6 -0
- package/dist/esm/util/index.d.ts +1 -1
- package/dist/esm/util/index.d.ts.map +1 -1
- package/dist/esm/util/index.js +2 -2
- package/dist/esm/util/package.d.ts +11 -0
- package/dist/esm/util/package.d.ts.map +1 -1
- package/dist/esm/util/package.js +102 -2
- package/dist/esm/util/package.js.map +1 -1
- package/dist/esm/util/progress.d.ts +1 -0
- package/dist/esm/util/progress.d.ts.map +1 -1
- package/dist/esm/util/progress.js +6 -4
- package/dist/esm/util/progress.js.map +1 -1
- package/package.json +6 -2
- package/src/building/builder.ts +5 -0
- package/src/building/cli.ts +28 -2
- package/src/building/docs.ts +348 -0
- package/src/index.ts +1 -1
- package/src/util/{files.ts → file.ts} +17 -3
- package/src/util/index.ts +1 -1
- package/src/util/package.ts +134 -1
- package/src/util/progress.ts +5 -5
- package/dist/cjs/util/files.d.ts.map +0 -1
- package/dist/cjs/util/files.js.map +0 -6
- package/dist/esm/util/files.d.ts.map +0 -1
- package/dist/esm/util/files.js +0 -126
- package/dist/esm/util/files.js.map +0 -6
|
@@ -0,0 +1,348 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2022-2024 Matter.js Authors
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { relative } from "path";
|
|
8
|
+
import {
|
|
9
|
+
Application,
|
|
10
|
+
ContainerReflection,
|
|
11
|
+
Converter,
|
|
12
|
+
DeclarationReflection,
|
|
13
|
+
LogLevel,
|
|
14
|
+
Reflection,
|
|
15
|
+
ReflectionFlag,
|
|
16
|
+
ReflectionKind,
|
|
17
|
+
TypeDocOptions,
|
|
18
|
+
} from "typedoc";
|
|
19
|
+
import { isFile } from "../util/file.js";
|
|
20
|
+
import { Package } from "../util/package.js";
|
|
21
|
+
import { Progress } from "../util/progress.js";
|
|
22
|
+
import { Graph } from "./graph.js";
|
|
23
|
+
|
|
24
|
+
// NOTE - this is a "best attempt" at doc generation via typescript. The result is not all that great; typedoc is too
|
|
25
|
+
// limited for our complex API so we're going to need something custom to do it right
|
|
26
|
+
|
|
27
|
+
const PLUGINS = ["typedoc-material-theme"] as string[];
|
|
28
|
+
|
|
29
|
+
// Double "docs" directories so top-level directory can be a GH repository with pages configured under "docs"
|
|
30
|
+
const OUTPUT_PATH = "build/docs/docs";
|
|
31
|
+
|
|
32
|
+
const THEME_OPTIONS = {
|
|
33
|
+
themeColor: "#cb9820",
|
|
34
|
+
|
|
35
|
+
// TODO - add service links
|
|
36
|
+
// GitHub: "https://github.com/project-chip/matter.js",
|
|
37
|
+
// Discord: "https://discord.gg/ujmRNrhDuW",
|
|
38
|
+
// NPM: "https://www.npmjs.com/package/@project-chip/matter.js",
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Generate build/docs.json for a single project.
|
|
43
|
+
*/
|
|
44
|
+
export async function buildDocs(pkg: Package, progress: Progress) {
|
|
45
|
+
const modules = pkg.sourceModules;
|
|
46
|
+
|
|
47
|
+
// We point typedoc at each of our public exports
|
|
48
|
+
const entryPoints = Array<string>();
|
|
49
|
+
|
|
50
|
+
// In a workspace typedoc requires files to be relative to the workspace for merge
|
|
51
|
+
const basePath = pkg.root.path;
|
|
52
|
+
|
|
53
|
+
for (const name in modules) {
|
|
54
|
+
const path = modules[name];
|
|
55
|
+
if (path.endsWith(".json")) {
|
|
56
|
+
continue;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
if (isFile(path)) {
|
|
60
|
+
if (!entryPoints.includes(path)) {
|
|
61
|
+
entryPoints.push(path);
|
|
62
|
+
}
|
|
63
|
+
} else {
|
|
64
|
+
throw new Error(`No source found for module ${name} path ${modules[name]}`);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const app = await createApplication({
|
|
69
|
+
excludeExternals: true,
|
|
70
|
+
entryPoints,
|
|
71
|
+
tsconfig: pkg.resolve("tsconfig.json"),
|
|
72
|
+
basePath,
|
|
73
|
+
skipErrorChecking: true,
|
|
74
|
+
|
|
75
|
+
// Removes a couple hundred MB of tabs so worth uncommenting at some point
|
|
76
|
+
//pretty: false,
|
|
77
|
+
|
|
78
|
+
readme: "none",
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
instrumentForEntrypointRepair(app, pkg);
|
|
82
|
+
|
|
83
|
+
const analysis = new ReflectionAnalysis();
|
|
84
|
+
|
|
85
|
+
app.converter.on(Converter.EVENT_CREATE_DECLARATION, (/*_context, reflection: DeclarationReflection*/) => {
|
|
86
|
+
progress.refresh();
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
app.converter.on(Converter.EVENT_RESOLVE, () => {
|
|
90
|
+
progress.refresh();
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
const reflection = await loadReflections(app, pkg);
|
|
94
|
+
|
|
95
|
+
analyzeReflections(reflection, analysis);
|
|
96
|
+
repairReflections(analysis);
|
|
97
|
+
|
|
98
|
+
await app.generateJson(reflection, pkg.resolve("build/docs.json"));
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function reflectionsPath(pkg: Package) {
|
|
102
|
+
const path = pkg.resolve("build/docs.json");
|
|
103
|
+
if (isFile(path)) {
|
|
104
|
+
return path;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Typedoc is insufficiently configurable to correctly name modules. The official direction is to rename modules using
|
|
110
|
+
* the "module" annotation but seems dumb to have to do that when we can compute the correct name. We'd have to edit
|
|
111
|
+
* and maintain many files including codegen.
|
|
112
|
+
*
|
|
113
|
+
* Instead we create a map of typedoc's naive module name to the correct name so we can update names as reflections
|
|
114
|
+
* load.
|
|
115
|
+
*/
|
|
116
|
+
function instrumentForEntrypointRepair(app: Application, pkg: Package) {
|
|
117
|
+
const baseGetEntryPoints = app.getEntryPoints.bind(app);
|
|
118
|
+
const mapping = naiveToRealNamesFor(pkg);
|
|
119
|
+
app.getEntryPoints = () => {
|
|
120
|
+
const list = baseGetEntryPoints();
|
|
121
|
+
if (list === undefined) {
|
|
122
|
+
return list;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
for (const ep of list) {
|
|
126
|
+
const realName = mapping[ep.displayName];
|
|
127
|
+
if (realName === undefined) {
|
|
128
|
+
throw new Error(`Typedoc naive module name "${ep.displayName}" is unmapped`);
|
|
129
|
+
}
|
|
130
|
+
ep.displayName = realName;
|
|
131
|
+
}
|
|
132
|
+
return list;
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Build the map of typedoc's naive name -> real name.
|
|
138
|
+
*/
|
|
139
|
+
function naiveToRealNamesFor(pkg: Package) {
|
|
140
|
+
const modules = pkg.sourceModules;
|
|
141
|
+
|
|
142
|
+
// Map of stupid names that typedoc chooses to actual export names
|
|
143
|
+
const mapping = {} as Record<string, string>;
|
|
144
|
+
|
|
145
|
+
const packagePrefix = `${pkg.name}/`;
|
|
146
|
+
|
|
147
|
+
// In a workspace typedoc requires files to be relative to the workspace for merge
|
|
148
|
+
const basePath = pkg.root.path;
|
|
149
|
+
|
|
150
|
+
for (const name in modules) {
|
|
151
|
+
const path = modules[name];
|
|
152
|
+
if (path.endsWith(".json")) {
|
|
153
|
+
continue;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
const naiveName = relative(basePath, path)
|
|
157
|
+
.replace(/.(?:ts|js|mjs|cjs)$/, "")
|
|
158
|
+
|
|
159
|
+
// typedoc strips "/index"; this is hard-coded and doesn't respect exports
|
|
160
|
+
.replace(/\/index$/, "");
|
|
161
|
+
|
|
162
|
+
if (name.startsWith(packagePrefix)) {
|
|
163
|
+
mapping[naiveName] = name.substring(packagePrefix.length);
|
|
164
|
+
} else if (name === pkg.name) {
|
|
165
|
+
// Flags for merge with parent
|
|
166
|
+
mapping[naiveName] = ".";
|
|
167
|
+
} else {
|
|
168
|
+
mapping[naiveName] = name;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
return mapping;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* Generate static documentation website.
|
|
177
|
+
*
|
|
178
|
+
* Supports individual projects or workspaces but not individual projects within workspaces.
|
|
179
|
+
*/
|
|
180
|
+
export async function mergeDocs(pkg: Package) {
|
|
181
|
+
const entryPoints = Array<string>();
|
|
182
|
+
|
|
183
|
+
const root = pkg.root;
|
|
184
|
+
|
|
185
|
+
if (root.isWorkspace) {
|
|
186
|
+
// Workspace
|
|
187
|
+
const graph = await Graph.load(root);
|
|
188
|
+
if (graph === undefined) {
|
|
189
|
+
// Shouldn't happen
|
|
190
|
+
throw new Error(`Internal: ${pkg.name} has workspaces but no graph`);
|
|
191
|
+
}
|
|
192
|
+
for (const node of graph.nodes) {
|
|
193
|
+
const path = reflectionsPath(node.pkg);
|
|
194
|
+
if (path) {
|
|
195
|
+
entryPoints.push(path);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
if (!entryPoints.length) {
|
|
199
|
+
throw new Error(`No reflections detected in workspace ${pkg.name}`);
|
|
200
|
+
}
|
|
201
|
+
} else {
|
|
202
|
+
// Standalone package
|
|
203
|
+
const path = reflectionsPath(pkg);
|
|
204
|
+
if (path === undefined) {
|
|
205
|
+
throw new Error(`No reflections present for ${pkg.name}`);
|
|
206
|
+
}
|
|
207
|
+
entryPoints.push(path);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
const app = await createApplication({
|
|
211
|
+
entryPoints,
|
|
212
|
+
entryPointStrategy: "merge",
|
|
213
|
+
...THEME_OPTIONS,
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
const reflection = await loadReflections(app, pkg);
|
|
217
|
+
|
|
218
|
+
await app.generateDocs(reflection, pkg.resolve(OUTPUT_PATH));
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
/**
|
|
222
|
+
* Create a typedoc "application" which is the interface for extracting types and generating docs.
|
|
223
|
+
*/
|
|
224
|
+
async function createApplication(options: Partial<TypeDocOptions>) {
|
|
225
|
+
return await Application.bootstrapWithPlugins({
|
|
226
|
+
plugin: PLUGINS,
|
|
227
|
+
logLevel: LogLevel.Warn,
|
|
228
|
+
...options,
|
|
229
|
+
});
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* Perform "conversion" which is typedoc terminology for executing the operation defined by the application.
|
|
234
|
+
*/
|
|
235
|
+
async function loadReflections(app: Application, pkg: Package) {
|
|
236
|
+
const reflection = await app.convert();
|
|
237
|
+
if (reflection === undefined) {
|
|
238
|
+
throw new Error(`Project ${pkg.path} produced no documentation`);
|
|
239
|
+
}
|
|
240
|
+
return reflection;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
class ReflectionAnalysis {
|
|
244
|
+
// TODO - need to populate this during analysis so we can warn; will replace typedoc-plugin-missing-exports
|
|
245
|
+
unexportedReference = new Set<Reflection>();
|
|
246
|
+
|
|
247
|
+
mergeWithParent = new Set<DeclarationReflection>();
|
|
248
|
+
mergeInto = new Map<DeclarationReflection, DeclarationReflection>();
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
/**
|
|
252
|
+
* Transform reflections to improve final output.
|
|
253
|
+
*/
|
|
254
|
+
function analyzeReflections(node: Reflection, analysis: ReflectionAnalysis) {
|
|
255
|
+
visit(node, subject => {
|
|
256
|
+
// TODO - populate analysis.unexporedReference (or perhaps just print warning)
|
|
257
|
+
|
|
258
|
+
const children = childrenOf(subject);
|
|
259
|
+
const mergeable = {} as Record<string, DeclarationReflection>;
|
|
260
|
+
const namespaces = new Set<DeclarationReflection>();
|
|
261
|
+
for (const child of children) {
|
|
262
|
+
if (child.kindOf(ReflectionKind.ClassOrInterface | ReflectionKind.Function)) {
|
|
263
|
+
mergeable[child.name] = child;
|
|
264
|
+
} else if (child.kindOf(ReflectionKind.Namespace)) {
|
|
265
|
+
namespaces.add(child);
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
for (const ns of namespaces) {
|
|
270
|
+
const mergeInto = mergeable[ns.name];
|
|
271
|
+
if (mergeInto) {
|
|
272
|
+
analysis.mergeInto.set(ns, mergeInto);
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
});
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
function repairReflections(analysis: ReflectionAnalysis) {
|
|
279
|
+
for (const toMerge of analysis.mergeWithParent) {
|
|
280
|
+
if (toMerge.parent instanceof DeclarationReflection) {
|
|
281
|
+
mergeInto(toMerge, toMerge.parent);
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
for (const [toMerge, into] of analysis.mergeInto.entries()) {
|
|
285
|
+
mergeInto(toMerge, into);
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
function moveNode(subject: DeclarationReflection, into: ContainerReflection) {
|
|
290
|
+
const from = subject.parent as ContainerReflection;
|
|
291
|
+
|
|
292
|
+
// No actual movement
|
|
293
|
+
if (from === into) {
|
|
294
|
+
return;
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
// Remove from old parent
|
|
298
|
+
if (from) {
|
|
299
|
+
from.removeChild(subject);
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
// Add to new parent
|
|
303
|
+
into.addChild(subject);
|
|
304
|
+
subject.parent = into;
|
|
305
|
+
|
|
306
|
+
// When merging a namespace into a type tweak modifier and kind appropriately (a bit of guessing here; might need
|
|
307
|
+
// tweaking)
|
|
308
|
+
if (
|
|
309
|
+
from.kindOf(ReflectionKind.Namespace) &&
|
|
310
|
+
into.kindOf(ReflectionKind.ClassOrInterface) &&
|
|
311
|
+
subject.kindOf(ReflectionKind.SomeValue)
|
|
312
|
+
) {
|
|
313
|
+
subject.flags.setFlag(ReflectionFlag.Static, true);
|
|
314
|
+
if (subject.kindOf(ReflectionKind.Variable)) {
|
|
315
|
+
subject.kind = ReflectionKind.Property;
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
function mergeInto(from: DeclarationReflection, into: ContainerReflection) {
|
|
321
|
+
const children = childrenOf(from);
|
|
322
|
+
while (children.length) {
|
|
323
|
+
moveNode(children[0], into);
|
|
324
|
+
}
|
|
325
|
+
(from.parent as ContainerReflection)?.removeChild(from);
|
|
326
|
+
// TODO - remap name
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
function childrenOf(node: Reflection) {
|
|
330
|
+
if (node instanceof ContainerReflection) {
|
|
331
|
+
if (node.children === undefined) {
|
|
332
|
+
node.children = [];
|
|
333
|
+
}
|
|
334
|
+
return node.children;
|
|
335
|
+
}
|
|
336
|
+
return [];
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
/**
|
|
340
|
+
* Visit all nodes in a reflection tree. Reflection has a "visit" method but it's just a branch on type.
|
|
341
|
+
*/
|
|
342
|
+
function visit(node: Reflection, visitor: (node: Reflection) => void) {
|
|
343
|
+
visitor(node);
|
|
344
|
+
|
|
345
|
+
for (const child of childrenOf(node)) {
|
|
346
|
+
visit(child, visitor);
|
|
347
|
+
}
|
|
348
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -8,6 +8,6 @@ export * from "./building/builder.js";
|
|
|
8
8
|
export * from "./building/graph.js";
|
|
9
9
|
export * from "./building/project.js";
|
|
10
10
|
export * from "./util/commander.js";
|
|
11
|
-
export * from "./util/
|
|
11
|
+
export * from "./util/file.js";
|
|
12
12
|
export * from "./util/package.js";
|
|
13
13
|
export * from "./util/progress.js";
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
import { readdirSync, readFileSync, statSync } from "fs";
|
|
8
8
|
import { GLOBSTAR, Minimatch, ParseReturnFiltered } from "minimatch";
|
|
9
9
|
import { resolve } from "path";
|
|
10
|
+
import { ignoreErrorSync } from "./errors.js";
|
|
10
11
|
|
|
11
12
|
function isNotFoundError(e: unknown) {
|
|
12
13
|
return typeof e === "object" && e !== null && "code" in e && (e.code === "ENOENT" || e.code === "ENOTDIR");
|
|
@@ -66,12 +67,17 @@ export function globSync(pattern: string | string[]) {
|
|
|
66
67
|
function globOneSync(pattern: string) {
|
|
67
68
|
// Parse the glob
|
|
68
69
|
const mm = new Minimatch(pattern.replace(/\\/g, "/"), {});
|
|
69
|
-
|
|
70
|
-
|
|
70
|
+
const results = new Set<string>();
|
|
71
|
+
for (const part of mm.set) {
|
|
72
|
+
for (const path of globOnePartSync(mm, part)) {
|
|
73
|
+
results.add(path);
|
|
74
|
+
}
|
|
71
75
|
}
|
|
76
|
+
return results;
|
|
77
|
+
}
|
|
72
78
|
|
|
79
|
+
function globOnePartSync(mm: Minimatch, segments: ParseReturnFiltered[]) {
|
|
73
80
|
// Find the starting path
|
|
74
|
-
const segments = mm.set[0];
|
|
75
81
|
let rootPath = "";
|
|
76
82
|
let didOne = false;
|
|
77
83
|
while (typeof segments[0] === "string") {
|
|
@@ -152,3 +158,11 @@ function globOneSync(pattern: string) {
|
|
|
152
158
|
|
|
153
159
|
return results;
|
|
154
160
|
}
|
|
161
|
+
|
|
162
|
+
export function isDirectory(path: string) {
|
|
163
|
+
return !!ignoreErrorSync("ENOENT", () => statSync(path).isDirectory());
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
export function isFile(path: string) {
|
|
167
|
+
return !!ignoreErrorSync("ENOENT", () => statSync(path).isFile());
|
|
168
|
+
}
|
package/src/util/index.ts
CHANGED
package/src/util/package.ts
CHANGED
|
@@ -8,7 +8,7 @@ import { existsSync, readFileSync, statSync } from "fs";
|
|
|
8
8
|
import { readdir, readFile, stat, writeFile } from "fs/promises";
|
|
9
9
|
import { dirname, join, relative, resolve } from "path";
|
|
10
10
|
import { ignoreError, ignoreErrorSync } from "./errors.js";
|
|
11
|
-
import { globSync, maybeReadJsonSync, maybeStatSync } from "./
|
|
11
|
+
import { globSync, isFile, maybeReadJsonSync, maybeStatSync } from "./file.js";
|
|
12
12
|
import { Progress } from "./progress.js";
|
|
13
13
|
import { toolsPath } from "./tools-path.cjs";
|
|
14
14
|
|
|
@@ -90,6 +90,10 @@ export class Package {
|
|
|
90
90
|
return this.json.name;
|
|
91
91
|
}
|
|
92
92
|
|
|
93
|
+
get version() {
|
|
94
|
+
return this.json.version;
|
|
95
|
+
}
|
|
96
|
+
|
|
93
97
|
get exports() {
|
|
94
98
|
return this.json.exports;
|
|
95
99
|
}
|
|
@@ -166,6 +170,21 @@ export class Package {
|
|
|
166
170
|
return Package.workspaceFor(this.path);
|
|
167
171
|
}
|
|
168
172
|
|
|
173
|
+
get isWorkspace() {
|
|
174
|
+
return Array.isArray(this.json.workspaces);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
get root(): Package {
|
|
178
|
+
try {
|
|
179
|
+
return this.workspace;
|
|
180
|
+
} catch (e) {
|
|
181
|
+
if (!(e instanceof JsonNotFoundError)) {
|
|
182
|
+
throw e;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
return this;
|
|
186
|
+
}
|
|
187
|
+
|
|
169
188
|
static set workingDir(wd: string) {
|
|
170
189
|
workingDir = wd;
|
|
171
190
|
}
|
|
@@ -326,6 +345,34 @@ export class Package {
|
|
|
326
345
|
return this.#aliases;
|
|
327
346
|
}
|
|
328
347
|
|
|
348
|
+
get modules() {
|
|
349
|
+
return this.listModules(false);
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
get sourceModules() {
|
|
353
|
+
return this.listModules(true);
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
/**
|
|
357
|
+
* Create a map of module name -> implementation file. If "source" is true, searches source files rather than
|
|
358
|
+
* transpiled files. We do this rather than finding transpilation files then mapping to source files so this works
|
|
359
|
+
* even if there isn't a build.
|
|
360
|
+
*/
|
|
361
|
+
listModules(source: boolean, ...conditions: string[]) {
|
|
362
|
+
if (!conditions.length) {
|
|
363
|
+
conditions = [this.supportsEsm ? "import" : "require", "default"];
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
const modules = {} as Record<string, string>;
|
|
367
|
+
|
|
368
|
+
const exports = this.exports;
|
|
369
|
+
if (typeof exports === "object" && exports !== null) {
|
|
370
|
+
findModules(source, new Set(conditions), modules, this.name, this.path, exports);
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
return modules;
|
|
374
|
+
}
|
|
375
|
+
|
|
329
376
|
#maybeStat(path: string) {
|
|
330
377
|
return maybeStatSync(this.resolve(path));
|
|
331
378
|
}
|
|
@@ -386,3 +433,89 @@ function findExportCondition(detail: Record<string, any>, type: "esm" | "cjs"):
|
|
|
386
433
|
return exp;
|
|
387
434
|
}
|
|
388
435
|
}
|
|
436
|
+
|
|
437
|
+
type Conditions = { [name: string]: Exports };
|
|
438
|
+
|
|
439
|
+
type Exports = string | Conditions | Record<string, Conditions>;
|
|
440
|
+
|
|
441
|
+
function findModules(
|
|
442
|
+
source: boolean,
|
|
443
|
+
conditions: Set<string>,
|
|
444
|
+
target: Record<string, string>,
|
|
445
|
+
prefix: string,
|
|
446
|
+
path: string,
|
|
447
|
+
exports: Exports,
|
|
448
|
+
) {
|
|
449
|
+
if (typeof exports === "string") {
|
|
450
|
+
addModuleGlobs(source, target, prefix, path, exports);
|
|
451
|
+
} else if (Array.isArray(exports)) {
|
|
452
|
+
for (const entry of exports) {
|
|
453
|
+
findModules(source, conditions, target, prefix, path, entry);
|
|
454
|
+
}
|
|
455
|
+
} else if (typeof exports === "object" && exports !== null) {
|
|
456
|
+
let selectedCondition = false;
|
|
457
|
+
for (const key in exports) {
|
|
458
|
+
if (key.startsWith(".")) {
|
|
459
|
+
findModules(source, conditions, target, join(prefix, key), path, exports[key]);
|
|
460
|
+
} else if (!selectedCondition && conditions.has(key)) {
|
|
461
|
+
findModules(source, conditions, target, prefix, path, exports[key]);
|
|
462
|
+
selectedCondition = true;
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
} else {
|
|
466
|
+
throw new Error("Malformed exports field in package.json");
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
function addModuleGlobs(source: boolean, target: Record<string, string>, name: string, base: string, pattern: string) {
|
|
471
|
+
let path = join(base, pattern);
|
|
472
|
+
if (source) {
|
|
473
|
+
path = path.replace(/\/dist\/(?:esm|cjs)\//, "/src/");
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
if (name.includes("*")) {
|
|
477
|
+
// Wildcard
|
|
478
|
+
if (!name.endsWith("/*")) {
|
|
479
|
+
throw new Error(`Wildcard in module ${name} does not appear as final path segment`);
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
name = name.substring(0, name.length - 2);
|
|
483
|
+
const paths = globSync(source ? path.replace(/\.js$/, ".{ts,js,cjs,mjs}") : path);
|
|
484
|
+
if (!paths.length) {
|
|
485
|
+
throw new Error(`No match for module ${name} pattern ${pattern}`);
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
const [prefix, suffix] = path.split(/\*+/);
|
|
489
|
+
const prefixLength = prefix === undefined ? 0 : prefix.length;
|
|
490
|
+
const suffixLength = suffix === undefined ? 0 : suffix.length;
|
|
491
|
+
|
|
492
|
+
for (const thisPath of paths) {
|
|
493
|
+
const qualifier = thisPath.substring(prefixLength, thisPath.length - suffixLength);
|
|
494
|
+
const thisName = join(name, qualifier);
|
|
495
|
+
target[thisName] = thisPath;
|
|
496
|
+
}
|
|
497
|
+
} else if (path.includes("*")) {
|
|
498
|
+
// A wildcard path is only valid with wildcard name
|
|
499
|
+
throw new Error(`Wildcard in module path "${path}" but not in module "${name}"`);
|
|
500
|
+
} else {
|
|
501
|
+
// No wildcard -- remove directory
|
|
502
|
+
name = name.replace(/\/(?:export|index)$/, "");
|
|
503
|
+
|
|
504
|
+
// Look for source if file isn't present
|
|
505
|
+
let found = false;
|
|
506
|
+
if (isFile(path)) {
|
|
507
|
+
found = true;
|
|
508
|
+
} else if (source && path.endsWith(".js")) {
|
|
509
|
+
path = path.replace(/\.js$/, ".ts");
|
|
510
|
+
if (isFile(path)) {
|
|
511
|
+
found = true;
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
if (!found) {
|
|
516
|
+
throw new Error(`Module "${name}" path "${path}" not found`);
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
target[name] = path;
|
|
520
|
+
}
|
|
521
|
+
}
|
package/src/util/progress.ts
CHANGED
|
@@ -40,11 +40,7 @@ const writeStatus = (() => {
|
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
// Require a newline for status updates any time the cursor does not end at the beginning of a line
|
|
43
|
-
needNewline =
|
|
44
|
-
// Update ends in newline
|
|
45
|
-
payload[payload.length - 1] === "\n" &&
|
|
46
|
-
// Update ends in carriage return
|
|
47
|
-
payload[payload.length - 1] !== "\r";
|
|
43
|
+
needNewline = payload[payload.length - 1] !== "\n" && payload[payload.length - 1] !== "\r";
|
|
48
44
|
|
|
49
45
|
return actualWrite.call(stream, payload, ...params);
|
|
50
46
|
};
|
|
@@ -155,6 +151,10 @@ export class Progress {
|
|
|
155
151
|
writeStatus(` ${colors.dim("‣")} ${label}`);
|
|
156
152
|
}
|
|
157
153
|
|
|
154
|
+
warn(text: string) {
|
|
155
|
+
stdout.write(` ${colors.yellow("Warning:")} ${text}\n`);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
158
|
shutdown() {
|
|
159
159
|
if (this.#refreshInterval) {
|
|
160
160
|
clearInterval(this.#refreshInterval);
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"files.d.ts","sourceRoot":"","sources":["../../../src/util/files.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAUH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,kCASzC;AAED,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,OAa7C;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,wBAQ5C;AAED,qBAAa,SAAU,SAAQ,KAAK;CAAG;AAEvC,wBAAgB,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,YAWlD"}
|
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../../../src/util/files.ts"],
|
|
4
|
-
"mappings": "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",
|
|
5
|
-
"names": []
|
|
6
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"files.d.ts","sourceRoot":"","sources":["../../../src/util/files.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAUH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,kCASzC;AAED,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,OAa7C;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,wBAQ5C;AAED,qBAAa,SAAU,SAAQ,KAAK;CAAG;AAEvC,wBAAgB,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,YAWlD"}
|