@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.
Files changed (72) hide show
  1. package/README.md +2 -2
  2. package/dist/cjs/building/builder.d.ts.map +1 -1
  3. package/dist/cjs/building/builder.js.map +1 -1
  4. package/dist/cjs/building/cli.d.ts.map +1 -1
  5. package/dist/cjs/building/cli.js +27 -5
  6. package/dist/cjs/building/cli.js.map +1 -1
  7. package/dist/cjs/building/docs.d.ts +18 -0
  8. package/dist/cjs/building/docs.d.ts.map +1 -0
  9. package/dist/cjs/building/docs.js +249 -0
  10. package/dist/cjs/building/docs.js.map +6 -0
  11. package/dist/cjs/index.d.ts +1 -1
  12. package/dist/cjs/index.d.ts.map +1 -1
  13. package/dist/cjs/index.js +1 -1
  14. package/dist/cjs/index.js.map +1 -1
  15. package/dist/cjs/util/{files.d.ts → file.d.ts} +3 -1
  16. package/dist/cjs/util/file.d.ts.map +1 -0
  17. package/dist/cjs/util/{files.js → file.js} +21 -7
  18. package/dist/cjs/util/file.js.map +6 -0
  19. package/dist/cjs/util/index.d.ts +1 -1
  20. package/dist/cjs/util/index.d.ts.map +1 -1
  21. package/dist/cjs/util/index.js +1 -1
  22. package/dist/cjs/util/index.js.map +1 -1
  23. package/dist/cjs/util/package.d.ts +11 -0
  24. package/dist/cjs/util/package.d.ts.map +1 -1
  25. package/dist/cjs/util/package.js +104 -4
  26. package/dist/cjs/util/package.js.map +1 -1
  27. package/dist/cjs/util/progress.d.ts +1 -0
  28. package/dist/cjs/util/progress.d.ts.map +1 -1
  29. package/dist/cjs/util/progress.js +5 -3
  30. package/dist/cjs/util/progress.js.map +1 -1
  31. package/dist/esm/building/builder.d.ts.map +1 -1
  32. package/dist/esm/building/builder.js +1 -1
  33. package/dist/esm/building/builder.js.map +1 -1
  34. package/dist/esm/building/cli.d.ts.map +1 -1
  35. package/dist/esm/building/cli.js +28 -6
  36. package/dist/esm/building/cli.js.map +1 -1
  37. package/dist/esm/building/docs.d.ts +18 -0
  38. package/dist/esm/building/docs.d.ts.map +1 -0
  39. package/dist/esm/building/docs.js +237 -0
  40. package/dist/esm/building/docs.js.map +6 -0
  41. package/dist/esm/index.d.ts +1 -1
  42. package/dist/esm/index.d.ts.map +1 -1
  43. package/dist/esm/index.js +2 -2
  44. package/dist/esm/util/{files.d.ts → file.d.ts} +3 -1
  45. package/dist/esm/util/file.d.ts.map +1 -0
  46. package/dist/esm/util/file.js +140 -0
  47. package/dist/esm/util/file.js.map +6 -0
  48. package/dist/esm/util/index.d.ts +1 -1
  49. package/dist/esm/util/index.d.ts.map +1 -1
  50. package/dist/esm/util/index.js +2 -2
  51. package/dist/esm/util/package.d.ts +11 -0
  52. package/dist/esm/util/package.d.ts.map +1 -1
  53. package/dist/esm/util/package.js +102 -2
  54. package/dist/esm/util/package.js.map +1 -1
  55. package/dist/esm/util/progress.d.ts +1 -0
  56. package/dist/esm/util/progress.d.ts.map +1 -1
  57. package/dist/esm/util/progress.js +6 -4
  58. package/dist/esm/util/progress.js.map +1 -1
  59. package/package.json +6 -2
  60. package/src/building/builder.ts +5 -0
  61. package/src/building/cli.ts +28 -2
  62. package/src/building/docs.ts +348 -0
  63. package/src/index.ts +1 -1
  64. package/src/util/{files.ts → file.ts} +17 -3
  65. package/src/util/index.ts +1 -1
  66. package/src/util/package.ts +134 -1
  67. package/src/util/progress.ts +5 -5
  68. package/dist/cjs/util/files.d.ts.map +0 -1
  69. package/dist/cjs/util/files.js.map +0 -6
  70. package/dist/esm/util/files.d.ts.map +0 -1
  71. package/dist/esm/util/files.js +0 -126
  72. 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/files.js";
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
- if (mm.set.length > 1) {
70
- throw new GlobError("Unsupported braces in glob pattern");
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
@@ -6,5 +6,5 @@
6
6
 
7
7
  export * from "./commander.js";
8
8
  export * from "./errors.js";
9
- export * from "./files.js";
9
+ export * from "./file.js";
10
10
  export * from "./package.js";
@@ -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 "./files.js";
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
+ }
@@ -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"}