@travetto/manifest 4.0.0-rc.0 → 4.0.0-rc.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/README.md +13 -8
- package/__index__.ts +4 -1
- package/bin/context.d.ts +1 -1
- package/bin/context.js +39 -30
- package/package.json +1 -1
- package/src/delta.ts +10 -9
- package/src/dependencies.ts +87 -89
- package/src/file.ts +1 -21
- package/src/manifest-index.ts +46 -54
- package/src/module.ts +22 -36
- package/src/package.ts +37 -76
- package/src/runtime.ts +19 -2
- package/src/types/common.ts +20 -0
- package/src/types/context.ts +40 -0
- package/src/types/manifest.ts +79 -0
- package/src/types/package.ts +75 -0
- package/src/util.ts +70 -15
- package/src/types.ts +0 -140
package/src/manifest-index.ts
CHANGED
|
@@ -1,36 +1,11 @@
|
|
|
1
|
+
import { existsSync } from 'node:fs';
|
|
2
|
+
|
|
1
3
|
import { ManifestModuleUtil } from './module';
|
|
2
4
|
import { path } from './path';
|
|
3
|
-
|
|
4
|
-
import {
|
|
5
|
-
ManifestModule, ManifestModuleCore, ManifestModuleFile,
|
|
6
|
-
ManifestModuleFileType, ManifestModuleFolderType, ManifestModuleRole, ManifestRoot
|
|
7
|
-
} from './types';
|
|
8
|
-
|
|
9
5
|
import { ManifestUtil } from './util';
|
|
10
6
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
module?: (module: IndexedModule) => boolean;
|
|
14
|
-
file?: (file: IndexedFile) => boolean;
|
|
15
|
-
sourceOnly?: boolean;
|
|
16
|
-
};
|
|
17
|
-
|
|
18
|
-
export type IndexedFile = {
|
|
19
|
-
id: string;
|
|
20
|
-
import: string;
|
|
21
|
-
module: string;
|
|
22
|
-
sourceFile: string;
|
|
23
|
-
outputFile: string;
|
|
24
|
-
relativeFile: string;
|
|
25
|
-
role: ManifestModuleRole;
|
|
26
|
-
type: ManifestModuleFileType;
|
|
27
|
-
};
|
|
28
|
-
|
|
29
|
-
export type IndexedModule = ManifestModuleCore & {
|
|
30
|
-
sourcePath: string;
|
|
31
|
-
outputPath: string;
|
|
32
|
-
files: Record<ManifestModuleFolderType, IndexedFile[]>;
|
|
33
|
-
};
|
|
7
|
+
import type { ManifestModuleFolderType } from './types/common';
|
|
8
|
+
import type { ManifestModule, ManifestRoot, ManifestModuleFile, IndexedModule, IndexedFile, FindConfig } from './types/manifest';
|
|
34
9
|
|
|
35
10
|
const TypedObject: {
|
|
36
11
|
keys<T = unknown, K extends keyof T = keyof T>(o: T): K[];
|
|
@@ -43,7 +18,7 @@ const TypedObject: {
|
|
|
43
18
|
*/
|
|
44
19
|
export class ManifestIndex {
|
|
45
20
|
|
|
46
|
-
#
|
|
21
|
+
#arbitraryLookup?: (parts: string[]) => ManifestModule | undefined;
|
|
47
22
|
#manifest: ManifestRoot;
|
|
48
23
|
#modules: IndexedModule[];
|
|
49
24
|
#modulesByName: Record<string, IndexedModule> = {};
|
|
@@ -69,14 +44,8 @@ export class ManifestIndex {
|
|
|
69
44
|
return this.#outputRoot;
|
|
70
45
|
}
|
|
71
46
|
|
|
72
|
-
get manifestFile(): string {
|
|
73
|
-
return this.#manifestFile;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
47
|
init(manifestInput: string): void {
|
|
77
|
-
|
|
78
|
-
this.#manifest = manifest;
|
|
79
|
-
this.#manifestFile = file;
|
|
48
|
+
this.#manifest = ManifestUtil.readManifestSync(manifestInput);
|
|
80
49
|
this.#outputRoot = path.resolve(this.#manifest.workspace.path, this.#manifest.build.outputFolder);
|
|
81
50
|
this.#index();
|
|
82
51
|
}
|
|
@@ -104,12 +73,14 @@ export class ManifestIndex {
|
|
|
104
73
|
this.#outputToEntry.clear();
|
|
105
74
|
this.#importToEntry.clear();
|
|
106
75
|
this.#sourceToEntry.clear();
|
|
76
|
+
this.#arbitraryLookup = undefined;
|
|
107
77
|
|
|
108
78
|
this.#modules = Object.values(this.#manifest.modules)
|
|
109
79
|
.map(m => ({
|
|
110
80
|
...m,
|
|
111
81
|
outputPath: this.#resolveOutput(m.outputFolder),
|
|
112
82
|
sourcePath: path.resolve(this.#manifest.workspace.path, m.sourceFolder),
|
|
83
|
+
children: new Set(),
|
|
113
84
|
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
114
85
|
files: Object.fromEntries(
|
|
115
86
|
Object.entries(m.files).map(([folder, files]) => [folder, this.#moduleFiles(m, files ?? [])])
|
|
@@ -128,6 +99,13 @@ export class ManifestIndex {
|
|
|
128
99
|
}
|
|
129
100
|
this.#modulesByName = Object.fromEntries(this.#modules.map(x => [x.name, x]));
|
|
130
101
|
this.#modulesByFolder = Object.fromEntries(this.#modules.map(x => [x.sourceFolder, x]));
|
|
102
|
+
|
|
103
|
+
// Store child information
|
|
104
|
+
for (const mod of this.#modules) {
|
|
105
|
+
for (const p of mod.parents) {
|
|
106
|
+
this.#modulesByName[p]?.children.add(mod.name);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
131
109
|
}
|
|
132
110
|
|
|
133
111
|
/**
|
|
@@ -138,11 +116,11 @@ export class ManifestIndex {
|
|
|
138
116
|
}
|
|
139
117
|
|
|
140
118
|
/**
|
|
141
|
-
* Get all
|
|
119
|
+
* Get all workspace modules
|
|
142
120
|
* @returns
|
|
143
121
|
*/
|
|
144
|
-
|
|
145
|
-
return this.#modules.filter(x => x.
|
|
122
|
+
getWorkspaceModules(): IndexedModule[] {
|
|
123
|
+
return this.#modules.filter(x => x.workspace);
|
|
146
124
|
}
|
|
147
125
|
|
|
148
126
|
/**
|
|
@@ -237,12 +215,9 @@ export class ManifestIndex {
|
|
|
237
215
|
/**
|
|
238
216
|
* Build module list from an expression list (e.g. `@travetto/rest,-@travetto/log)
|
|
239
217
|
*/
|
|
240
|
-
getModuleList(mode: '
|
|
218
|
+
getModuleList(mode: 'workspace' | 'all', exprList: string = ''): Set<string> {
|
|
241
219
|
const allMods = Object.keys(this.#manifest.modules);
|
|
242
|
-
const active = new Set<string>(
|
|
243
|
-
mode === 'local' ? this.getLocalModules().map(x => x.name) :
|
|
244
|
-
(mode === 'all' ? allMods : [])
|
|
245
|
-
);
|
|
220
|
+
const active = new Set<string>(mode === 'workspace' ? this.getWorkspaceModules().map(x => x.name) : allMods);
|
|
246
221
|
|
|
247
222
|
for (const expr of exprList.split(/\s*,\s*/g)) {
|
|
248
223
|
const [, neg, mod] = expr.match(/(-|[+])?([^+\- ]+)$/) ?? [];
|
|
@@ -257,21 +232,38 @@ export class ManifestIndex {
|
|
|
257
232
|
}
|
|
258
233
|
|
|
259
234
|
/**
|
|
260
|
-
* Get all modules (transitively)
|
|
235
|
+
* Get all modules, parents or children, (transitively) of the provided root, in a DFS fashion
|
|
261
236
|
*/
|
|
262
|
-
getDependentModules(root: IndexedModule):
|
|
237
|
+
getDependentModules(root: IndexedModule | string, field: 'parents' | 'children'): IndexedModule[] {
|
|
263
238
|
const seen = new Set<string>();
|
|
264
|
-
const out =
|
|
265
|
-
const toProcess = [root.name];
|
|
239
|
+
const out: IndexedModule[] = [];
|
|
240
|
+
const toProcess = [typeof root === 'string' ? root : root.name];
|
|
266
241
|
while (toProcess.length) {
|
|
267
242
|
const next = toProcess.shift()!;
|
|
268
|
-
if (seen.has(next)) {
|
|
269
|
-
|
|
243
|
+
if (!seen.has(next)) {
|
|
244
|
+
seen.add(next);
|
|
245
|
+
const mod = this.getModule(next)!;
|
|
246
|
+
toProcess.push(...mod[field]);
|
|
247
|
+
if (next !== this.#manifest.main.name) { // Do not include self
|
|
248
|
+
out.push(mod);
|
|
249
|
+
}
|
|
270
250
|
}
|
|
271
|
-
const mod = this.getModule(next)!;
|
|
272
|
-
toProcess.push(...mod.parents);
|
|
273
|
-
out.add(mod);
|
|
274
251
|
}
|
|
275
252
|
return out;
|
|
276
253
|
}
|
|
254
|
+
|
|
255
|
+
/**
|
|
256
|
+
* Find the module for an arbitrary source file, if it falls under a given workspace module
|
|
257
|
+
*/
|
|
258
|
+
findModuleForArbitraryFile(file: string): ManifestModule | undefined {
|
|
259
|
+
const base = this.#manifest.workspace.path;
|
|
260
|
+
const lookup = this.#arbitraryLookup ??= ManifestUtil.lookupTrie(
|
|
261
|
+
Object.values(this.#manifest.modules),
|
|
262
|
+
x => x.sourceFolder.split('/'),
|
|
263
|
+
sub =>
|
|
264
|
+
!existsSync(path.resolve(base, ...sub, 'package.json')) &&
|
|
265
|
+
!existsSync(path.resolve(base, ...sub, '.git'))
|
|
266
|
+
);
|
|
267
|
+
return lookup(file.replace(`${base}/`, '').split('/'));
|
|
268
|
+
}
|
|
277
269
|
}
|
package/src/module.ts
CHANGED
|
@@ -1,14 +1,12 @@
|
|
|
1
1
|
import fs from 'node:fs/promises';
|
|
2
2
|
|
|
3
3
|
import { path } from './path';
|
|
4
|
-
import {
|
|
5
|
-
ManifestContext,
|
|
6
|
-
ManifestModule, ManifestModuleFile, ManifestModuleFileType,
|
|
7
|
-
ManifestModuleFolderType,
|
|
8
|
-
ManifestModuleRole
|
|
9
|
-
} from './types';
|
|
10
|
-
import { ModuleDep, ModuleDependencyVisitor } from './dependencies';
|
|
11
4
|
import { PackageUtil } from './package';
|
|
5
|
+
import { PackageModuleVisitor } from './dependencies';
|
|
6
|
+
|
|
7
|
+
import type { ManifestModuleFileType, ManifestModuleRole, ManifestModuleFolderType } from './types/common';
|
|
8
|
+
import type { ManifestModuleFile, ManifestModule, PackageModule } from './types/manifest';
|
|
9
|
+
import type { ManifestContext } from './types/context';
|
|
12
10
|
|
|
13
11
|
const EXT_MAPPING: Record<string, ManifestModuleFileType> = {
|
|
14
12
|
'.js': 'js',
|
|
@@ -47,9 +45,10 @@ export class ManifestModuleUtil {
|
|
|
47
45
|
/**
|
|
48
46
|
* Simple file scanning
|
|
49
47
|
*/
|
|
50
|
-
static async scanFolder(folder: string,
|
|
51
|
-
|
|
52
|
-
|
|
48
|
+
static async scanFolder(folder: string, full = false): Promise<string[]> {
|
|
49
|
+
const key = `${folder}|${full}`;
|
|
50
|
+
if (key in this.#scanCache) {
|
|
51
|
+
return this.#scanCache[key];
|
|
53
52
|
}
|
|
54
53
|
|
|
55
54
|
if (!await fs.stat(folder).catch(() => false)) {
|
|
@@ -73,7 +72,7 @@ export class ManifestModuleUtil {
|
|
|
73
72
|
}
|
|
74
73
|
|
|
75
74
|
for (const sub of await fs.readdir(top)) {
|
|
76
|
-
const valid = !sub.startsWith('.') && (depth > 0 ||
|
|
75
|
+
const valid = !sub.startsWith('.') && (depth > 0 || full);
|
|
77
76
|
const stat = await fs.stat(`${top}/${sub}`);
|
|
78
77
|
if (stat.isFile()) {
|
|
79
78
|
if (valid || STD_TOP_FILES.has(sub)) {
|
|
@@ -87,11 +86,7 @@ export class ManifestModuleUtil {
|
|
|
87
86
|
}
|
|
88
87
|
}
|
|
89
88
|
|
|
90
|
-
|
|
91
|
-
this.#scanCache[folder] = out;
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
return out;
|
|
89
|
+
return this.#scanCache[key] = out;
|
|
95
90
|
}
|
|
96
91
|
|
|
97
92
|
/**
|
|
@@ -177,12 +172,13 @@ export class ManifestModuleUtil {
|
|
|
177
172
|
/**
|
|
178
173
|
* Visit a module and describe files, and metadata
|
|
179
174
|
*/
|
|
180
|
-
static async describeModule(ctx: ManifestContext,
|
|
181
|
-
const {
|
|
175
|
+
static async describeModule(ctx: ManifestContext, mod: PackageModule): Promise<ManifestModule> {
|
|
176
|
+
const { state, ...rest } = mod;
|
|
177
|
+
const sourcePath = path.resolve(ctx.workspace.path, rest.sourceFolder);
|
|
182
178
|
|
|
183
179
|
const files: ManifestModule['files'] = {};
|
|
184
180
|
|
|
185
|
-
for (const file of await this.scanFolder(sourcePath,
|
|
181
|
+
for (const file of await this.scanFolder(sourcePath, rest.main)) {
|
|
186
182
|
// Group by top folder
|
|
187
183
|
const moduleFile = file.replace(`${sourcePath}/`, '');
|
|
188
184
|
const entry = await this.transformFile(moduleFile, file);
|
|
@@ -190,30 +186,20 @@ export class ManifestModuleUtil {
|
|
|
190
186
|
(files[key] ??= []).push(entry);
|
|
191
187
|
}
|
|
192
188
|
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
const roles = [...roleSet ?? []].sort();
|
|
199
|
-
const parents = [...parentSet].sort();
|
|
200
|
-
const outputFolder = `node_modules/${name}`;
|
|
201
|
-
const sourceFolder = sourcePath === ctx.workspace.path ? '' : sourcePath.replace(`${ctx.workspace.path}/`, '');
|
|
202
|
-
|
|
203
|
-
const res: ManifestModule = {
|
|
204
|
-
main, name, version, local, internal, sourceFolder, outputFolder, roles, parents, prod, files
|
|
189
|
+
return {
|
|
190
|
+
...rest,
|
|
191
|
+
roles: [...state.roleSet].sort(),
|
|
192
|
+
parents: [...state.parentSet].sort(),
|
|
193
|
+
files
|
|
205
194
|
};
|
|
206
|
-
return res;
|
|
207
195
|
}
|
|
208
196
|
|
|
209
197
|
/**
|
|
210
198
|
* Produce all modules for a given manifest folder, adding in some given modules when developing framework
|
|
211
199
|
*/
|
|
212
200
|
static async produceModules(ctx: ManifestContext): Promise<Record<string, ManifestModule>> {
|
|
213
|
-
const
|
|
214
|
-
const
|
|
215
|
-
const sorted = [...declared].sort((a, b) => a.name.localeCompare(b.name));
|
|
216
|
-
const modules = await Promise.all(sorted.map(x => this.describeModule(ctx, x)));
|
|
201
|
+
const pkgs = await PackageUtil.visitPackages(new PackageModuleVisitor(ctx));
|
|
202
|
+
const modules = await Promise.all([...pkgs].map(x => this.describeModule(ctx, x)));
|
|
217
203
|
return Object.fromEntries(modules.map(m => [m.name, m]));
|
|
218
204
|
}
|
|
219
205
|
|
package/src/package.ts
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
import { createRequire } from 'node:module';
|
|
2
2
|
import { execSync } from 'node:child_process';
|
|
3
3
|
|
|
4
|
-
import type { ManifestContext, NodePackageManager, Package, PackageVisitor, PackageVisitReq, PackageWorkspaceEntry } from './types';
|
|
5
4
|
import { path } from './path';
|
|
6
5
|
import { ManifestFileUtil } from './file';
|
|
7
6
|
|
|
7
|
+
import { PackagePath, type Package, type PackageVisitor, type PackageWorkspaceEntry } from './types/package';
|
|
8
|
+
import type { ManifestContext } from './types/context';
|
|
9
|
+
import type { NodePackageManager } from './types/common';
|
|
10
|
+
|
|
8
11
|
/**
|
|
9
12
|
* Utilities for querying, traversing and reading package.json files.
|
|
10
13
|
*/
|
|
@@ -31,9 +34,9 @@ export class PackageUtil {
|
|
|
31
34
|
/**
|
|
32
35
|
* Resolve version path, if file: url
|
|
33
36
|
*/
|
|
34
|
-
static resolveVersionPath(
|
|
37
|
+
static resolveVersionPath(root: Package, ver: string): string | undefined {
|
|
35
38
|
if (ver.startsWith('file:')) {
|
|
36
|
-
return path.resolve(
|
|
39
|
+
return path.resolve(this.getPackagePath(root), ver.replace('file:', ''));
|
|
37
40
|
} else {
|
|
38
41
|
return;
|
|
39
42
|
}
|
|
@@ -54,31 +57,6 @@ export class PackageUtil {
|
|
|
54
57
|
throw new Error(`Unable to resolve: ${name}`);
|
|
55
58
|
}
|
|
56
59
|
|
|
57
|
-
/**
|
|
58
|
-
* Build a package visit req
|
|
59
|
-
*/
|
|
60
|
-
static packageReq<T>(sourcePath: string, prod: boolean, topLevel?: boolean): PackageVisitReq<T> {
|
|
61
|
-
return { pkg: this.readPackage(sourcePath), sourcePath, prod, topLevel };
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
/**
|
|
65
|
-
* Extract all dependencies from a package
|
|
66
|
-
*/
|
|
67
|
-
static getAllDependencies<T = unknown>(modulePath: string, local: boolean): PackageVisitReq<T>[] {
|
|
68
|
-
const pkg = this.readPackage(modulePath);
|
|
69
|
-
const children: Record<string, PackageVisitReq<T>> = {};
|
|
70
|
-
for (const [deps, prod] of [
|
|
71
|
-
[pkg.dependencies, true],
|
|
72
|
-
...(local ? [[pkg.devDependencies, false] as const] : []),
|
|
73
|
-
] as const) {
|
|
74
|
-
for (const [name, version] of Object.entries(deps ?? {})) {
|
|
75
|
-
const depPath = this.resolveVersionPath(modulePath, version) ?? this.resolvePackagePath(name);
|
|
76
|
-
children[`${name}#${version}`] = this.packageReq<T>(depPath, prod, false);
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
return Object.values(children).sort((a, b) => a.pkg.name.localeCompare(b.pkg.name));
|
|
80
|
-
}
|
|
81
|
-
|
|
82
60
|
/**
|
|
83
61
|
* Read a package.json from a given folder
|
|
84
62
|
*/
|
|
@@ -92,86 +70,69 @@ export class PackageUtil {
|
|
|
92
70
|
|
|
93
71
|
res.name ??= 'untitled'; // If a package.json (root-only) is missing a name, allows for npx execution
|
|
94
72
|
|
|
73
|
+
res[PackagePath] = modulePath;
|
|
95
74
|
return res;
|
|
96
75
|
}
|
|
97
76
|
|
|
98
77
|
/**
|
|
99
|
-
*
|
|
78
|
+
* Get the package path
|
|
100
79
|
*/
|
|
101
|
-
static
|
|
102
|
-
return
|
|
80
|
+
static getPackagePath(pkg: Package): string {
|
|
81
|
+
return pkg[PackagePath];
|
|
103
82
|
}
|
|
104
83
|
|
|
105
84
|
/**
|
|
106
85
|
* Visit packages with ability to track duplicates
|
|
107
86
|
*/
|
|
108
|
-
static async visitPackages<T>(visitor: PackageVisitor<T>): Promise<
|
|
109
|
-
|
|
110
|
-
const
|
|
111
|
-
|
|
112
|
-
const seen = new Map<string, T>();
|
|
113
|
-
const queue: PackageVisitReq<T>[] = [...await visitor.init?.(root) ?? [], root];
|
|
114
|
-
const out = new Set<T>();
|
|
87
|
+
static async visitPackages<T>(visitor: PackageVisitor<T>): Promise<Iterable<T>> {
|
|
88
|
+
const seen = new Set<T>();
|
|
89
|
+
const queue = [...await visitor.init()];
|
|
115
90
|
|
|
116
91
|
while (queue.length) {
|
|
117
|
-
const
|
|
92
|
+
const node = queue.shift()!; // Visit initial set first
|
|
118
93
|
|
|
119
|
-
if (!
|
|
94
|
+
if (!visitor.valid(node)) {
|
|
120
95
|
continue;
|
|
121
96
|
}
|
|
122
97
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
98
|
+
visitor.visit(node);
|
|
99
|
+
|
|
100
|
+
if (seen.has(node.value)) {
|
|
101
|
+
continue;
|
|
126
102
|
} else {
|
|
127
|
-
|
|
128
|
-
out.add(dep);
|
|
129
|
-
await visitor.visit?.(req, dep);
|
|
130
|
-
seen.set(key, dep);
|
|
131
|
-
const children = this.getAllDependencies<T>(
|
|
132
|
-
req.sourcePath,
|
|
133
|
-
// We consider a module local if its not in the node_modules
|
|
134
|
-
!req.sourcePath.includes('node_modules') && (
|
|
135
|
-
// And its the root or we are in a monorepo
|
|
136
|
-
root.sourcePath === req.sourcePath ||
|
|
137
|
-
!!root.pkg.workspaces
|
|
138
|
-
)
|
|
139
|
-
);
|
|
140
|
-
queue.push(...children.map(x => ({ ...x, parent: dep })));
|
|
103
|
+
seen.add(node.value);
|
|
141
104
|
}
|
|
105
|
+
|
|
106
|
+
const children = Object.entries(node.children)
|
|
107
|
+
.map(([n, v]) => this.readPackage(this.resolveVersionPath(node.pkg, v) ?? this.resolvePackagePath(n)))
|
|
108
|
+
.map(pkg => ({ ...visitor.create(pkg), parent: node.value }));
|
|
109
|
+
|
|
110
|
+
queue.push(...children);
|
|
142
111
|
}
|
|
143
|
-
|
|
112
|
+
|
|
113
|
+
return await visitor.complete(seen);
|
|
144
114
|
}
|
|
145
115
|
|
|
146
116
|
/**
|
|
147
117
|
* Find workspace values from rootPath
|
|
148
118
|
*/
|
|
149
|
-
static async resolveWorkspaces(ctx: ManifestContext
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
} catch (err) {
|
|
119
|
+
static async resolveWorkspaces(ctx: ManifestContext): Promise<PackageWorkspaceEntry[]> {
|
|
120
|
+
const rootPath = ctx.workspace.path;
|
|
121
|
+
const cache = path.resolve(rootPath, ctx.build.outputFolder, 'workspaces.json');
|
|
122
|
+
return this.#workspaces[rootPath] ??= await ManifestFileUtil.readAsJson<PackageWorkspaceEntry[]>(cache)
|
|
123
|
+
.catch(async () => {
|
|
155
124
|
let out: PackageWorkspaceEntry[];
|
|
156
125
|
switch (ctx.workspace.manager) {
|
|
126
|
+
case 'yarn':
|
|
157
127
|
case 'npm': {
|
|
158
128
|
const res = await this.#exec<{ location: string, name: string }[]>(rootPath, 'npm query .workspace');
|
|
159
|
-
out = res.map(d => ({
|
|
160
|
-
break;
|
|
161
|
-
}
|
|
162
|
-
case 'yarn': {
|
|
163
|
-
const res = await this.#exec<Record<string, { location: string }>>(rootPath, 'npm query .workspace');
|
|
164
|
-
out = Object.entries(res).map(([name, { location }]) => ({ sourcePath: location, name }));
|
|
129
|
+
out = res.map(d => ({ path: path.resolve(ctx.workspace.path, d.location), name: d.name }));
|
|
165
130
|
break;
|
|
166
131
|
}
|
|
167
132
|
}
|
|
168
|
-
|
|
169
|
-
this.#workspaces[rootPath] = out;
|
|
170
|
-
|
|
171
133
|
await ManifestFileUtil.bufferedFileWrite(cache, out);
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
return this.#workspaces[rootPath];
|
|
134
|
+
return out;
|
|
135
|
+
});
|
|
175
136
|
}
|
|
176
137
|
|
|
177
138
|
/**
|
package/src/runtime.ts
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import { path } from './path';
|
|
2
|
-
import {
|
|
3
|
-
|
|
2
|
+
import { ManifestIndex } from './manifest-index';
|
|
3
|
+
|
|
4
|
+
import type { FunctionMetadata } from './types/common';
|
|
5
|
+
import type { IndexedModule, ManifestModule } from './types/manifest';
|
|
6
|
+
import type { ManifestContext } from './types/context';
|
|
4
7
|
|
|
5
8
|
const METADATA = Symbol.for('@travetto/manifest:metadata');
|
|
6
9
|
type Metadated = { [METADATA]: FunctionMetadata };
|
|
@@ -122,5 +125,19 @@ export const RuntimeContext = build({
|
|
|
122
125
|
*/
|
|
123
126
|
workspaceRelative(...rel: string[]): string {
|
|
124
127
|
return path.resolve(RuntimeIndex.manifest.workspace.path, ...rel);
|
|
128
|
+
},
|
|
129
|
+
/**
|
|
130
|
+
* Produce a workspace path for tooling, with '@' being replaced by node_module/name folder
|
|
131
|
+
* @param rel The relative path
|
|
132
|
+
*/
|
|
133
|
+
toolPath(...rel: string[]): string {
|
|
134
|
+
rel = rel.flatMap(x => x === '@' ? ['node_modules', RuntimeIndex.manifest.main.name] : [x]);
|
|
135
|
+
return path.resolve(RuntimeIndex.manifest.workspace.path, RuntimeIndex.manifest.build.toolFolder, ...rel);
|
|
136
|
+
},
|
|
137
|
+
/**
|
|
138
|
+
* Are we running from a mono-root?
|
|
139
|
+
*/
|
|
140
|
+
get monoRoot(): boolean {
|
|
141
|
+
return !!RuntimeIndex.manifest.workspace.mono && !RuntimeIndex.manifest.main.folder;
|
|
125
142
|
}
|
|
126
143
|
}, ['main', 'workspace']);
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export type NodeModuleType = 'module' | 'commonjs';
|
|
2
|
+
export type NodePackageManager = 'yarn' | 'npm';
|
|
3
|
+
|
|
4
|
+
export type ManifestModuleFileType = 'typings' | 'ts' | 'js' | 'json' | 'package-json' | 'unknown' | 'fixture' | 'md';
|
|
5
|
+
export type ManifestModuleFolderType =
|
|
6
|
+
'$root' | '$index' | '$package' |
|
|
7
|
+
'src' | 'bin' | 'support' | 'resources' | 'test' | 'doc' |
|
|
8
|
+
'test/fixtures' | 'support/fixtures' | 'support/resources' |
|
|
9
|
+
'$other' | '$transformer';
|
|
10
|
+
|
|
11
|
+
export type ManifestModuleRole = 'std' | 'test' | 'doc' | 'compile' | 'build';
|
|
12
|
+
|
|
13
|
+
export type FunctionMetadata = {
|
|
14
|
+
id: string;
|
|
15
|
+
source: string;
|
|
16
|
+
hash?: number;
|
|
17
|
+
methods?: Record<string, { hash: number }>;
|
|
18
|
+
synthetic?: boolean;
|
|
19
|
+
abstract?: boolean;
|
|
20
|
+
};
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { NodeModuleType, NodePackageManager } from './common';
|
|
2
|
+
|
|
3
|
+
export type ManifestContext = {
|
|
4
|
+
workspace: {
|
|
5
|
+
/** Workspace path for module */
|
|
6
|
+
path: string;
|
|
7
|
+
/** The module name for the workspace root */
|
|
8
|
+
name: string;
|
|
9
|
+
/** Is the workspace a monorepo? */
|
|
10
|
+
mono?: boolean;
|
|
11
|
+
/** The module type of the workspace */
|
|
12
|
+
type: NodeModuleType;
|
|
13
|
+
/** The package manager of the workspace */
|
|
14
|
+
manager: NodePackageManager;
|
|
15
|
+
/** The default env name */
|
|
16
|
+
defaultEnv: string;
|
|
17
|
+
};
|
|
18
|
+
build: {
|
|
19
|
+
/** Compiler folder, relative to workspace */
|
|
20
|
+
compilerFolder: string;
|
|
21
|
+
/** Compiler module folder */
|
|
22
|
+
compilerModuleFolder: string;
|
|
23
|
+
/** URL for the compiler server */
|
|
24
|
+
compilerUrl: string;
|
|
25
|
+
/** Code output folder, relative to workspace */
|
|
26
|
+
outputFolder: string;
|
|
27
|
+
/** Location of development-time tool output */
|
|
28
|
+
toolFolder: string;
|
|
29
|
+
};
|
|
30
|
+
main: {
|
|
31
|
+
/** Main module for manifest */
|
|
32
|
+
name: string;
|
|
33
|
+
/** Folder, relative to workspace for main module */
|
|
34
|
+
folder: string;
|
|
35
|
+
/** Description of the main module */
|
|
36
|
+
description?: string;
|
|
37
|
+
/** Version of the main module */
|
|
38
|
+
version: string;
|
|
39
|
+
};
|
|
40
|
+
};
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import type { ManifestModuleFileType, ManifestModuleFolderType, ManifestModuleRole } from './common';
|
|
2
|
+
import type { ManifestContext } from './context';
|
|
3
|
+
import { Package } from './package';
|
|
4
|
+
|
|
5
|
+
export type ManifestModuleFile = [string, ManifestModuleFileType, number] | [string, ManifestModuleFileType, number, ManifestModuleRole];
|
|
6
|
+
|
|
7
|
+
export type ManifestDepCore = {
|
|
8
|
+
/** Package name */
|
|
9
|
+
name: string;
|
|
10
|
+
/** Package version */
|
|
11
|
+
version: string;
|
|
12
|
+
/** Is this the main module */
|
|
13
|
+
main?: boolean;
|
|
14
|
+
/** Is this a module that is part of the workspace */
|
|
15
|
+
workspace?: boolean;
|
|
16
|
+
/** Should this module be deployed to prod? */
|
|
17
|
+
prod: boolean;
|
|
18
|
+
/** Is the module intended to be published? */
|
|
19
|
+
internal?: boolean;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export type ManifestModuleCore = ManifestDepCore & {
|
|
23
|
+
sourceFolder: string;
|
|
24
|
+
outputFolder: string;
|
|
25
|
+
roles: ManifestModuleRole[];
|
|
26
|
+
parents: string[];
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
export type ManifestModule = ManifestModuleCore & {
|
|
30
|
+
files: Partial<Record<ManifestModuleFolderType, ManifestModuleFile[]>>;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
export type ManifestRoot = ManifestContext & {
|
|
34
|
+
generated: number;
|
|
35
|
+
modules: Record<string, ManifestModule>;
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
export type FindConfig = {
|
|
39
|
+
folder?: (folder: ManifestModuleFolderType) => boolean;
|
|
40
|
+
module?: (module: IndexedModule) => boolean;
|
|
41
|
+
file?: (file: IndexedFile) => boolean;
|
|
42
|
+
sourceOnly?: boolean;
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
export type IndexedFile = {
|
|
46
|
+
id: string;
|
|
47
|
+
import: string;
|
|
48
|
+
module: string;
|
|
49
|
+
sourceFile: string;
|
|
50
|
+
outputFile: string;
|
|
51
|
+
relativeFile: string;
|
|
52
|
+
role: ManifestModuleRole;
|
|
53
|
+
type: ManifestModuleFileType;
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
export type IndexedModule = ManifestModuleCore & {
|
|
57
|
+
sourcePath: string;
|
|
58
|
+
outputPath: string;
|
|
59
|
+
files: Record<ManifestModuleFolderType, IndexedFile[]>;
|
|
60
|
+
children: Set<string>;
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
/** Module dependency, used in dependency visiting */
|
|
64
|
+
export type PackageModule = Omit<ManifestModule, 'files' | 'parents' | 'roles'> & {
|
|
65
|
+
state: {
|
|
66
|
+
/** Role root? */
|
|
67
|
+
roleRoot?: boolean;
|
|
68
|
+
/** Travetto package info */
|
|
69
|
+
travetto?: Package['travetto'];
|
|
70
|
+
/** Prod dependencies */
|
|
71
|
+
prodDeps: Set<string>;
|
|
72
|
+
/** Set of parent package names */
|
|
73
|
+
parentSet: Set<string>;
|
|
74
|
+
/** Set of child package names */
|
|
75
|
+
childSet: Set<string>;
|
|
76
|
+
/** Defined roles for a given module */
|
|
77
|
+
roleSet: Set<ManifestModuleRole>;
|
|
78
|
+
};
|
|
79
|
+
};
|