@travetto/manifest 8.0.0-alpha.9 → 8.0.0
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 +9 -9
- package/__index__.ts +6 -6
- package/package.json +15 -15
- package/src/context.ts +13 -11
- package/src/delta.ts +17 -11
- package/src/dependencies.ts +36 -28
- package/src/file.ts +2 -2
- package/src/manifest-index.ts +18 -25
- package/src/module.ts +15 -19
- package/src/package.ts +22 -14
- package/src/path.ts +24 -22
- package/src/types/common.ts +14 -5
- package/src/types/context.ts +1 -1
- package/src/types/manifest.ts +2 -2
- package/src/types/package.ts +1 -1
- package/src/util.ts +35 -25
package/README.md
CHANGED
|
@@ -13,7 +13,7 @@ npm install @travetto/manifest
|
|
|
13
13
|
yarn add @travetto/manifest
|
|
14
14
|
```
|
|
15
15
|
|
|
16
|
-
This module aims to be the boundary between the file system and the code.
|
|
16
|
+
This module aims to be the boundary between the file system and the code. The module provides:
|
|
17
17
|
* Project Manifesting
|
|
18
18
|
* Manifest Delta
|
|
19
19
|
* Class and Function Metadata
|
|
@@ -30,7 +30,7 @@ During the compilation process, the compiler needs to know every file that is el
|
|
|
30
30
|
Additionally, once the code has been compiled (or even bundled after that), the executing process needs to know what files are available for loading, and any patterns necessary for knowing which files to load versus which ones to ignore. This allows for dynamic loading of modules/files without knowledge/access to the file system, and in a more performant manner.
|
|
31
31
|
|
|
32
32
|
## Manifest Delta
|
|
33
|
-
During the compilation process, it is helpful to know how the output content differs from the manifest, which is produced from the source input. The [ManifestDeltaUtil](https://github.com/travetto/travetto/tree/main/module/manifest/src/delta.ts#
|
|
33
|
+
During the compilation process, it is helpful to know how the output content differs from the manifest, which is produced from the source input. The [ManifestDeltaUtil](https://github.com/travetto/travetto/tree/main/module/manifest/src/delta.ts#L31) provides the functionality for a given manifest, and will produce a stream of changes grouped by module. This is the primary input into the [Compiler](https://github.com/travetto/travetto/tree/main/module/compiler#readme "The compiler infrastructure for the Travetto framework")'s incremental behavior to know when a file has changed and needs to be recompiled.
|
|
34
34
|
|
|
35
35
|
## Module Indexing
|
|
36
36
|
Once the manifest is created, the application runtime can now read this manifest, which allows for influencing runtime behavior. The most common patterns include:
|
|
@@ -43,7 +43,7 @@ Once the manifest is created, the application runtime can now read this manifest
|
|
|
43
43
|
* Providing contextual information when provided a filename, import name, etc (e.g. logging, testing output)
|
|
44
44
|
|
|
45
45
|
## Path Normalization
|
|
46
|
-
By default, all paths within the framework are assumed to be in a POSIX style, and all input paths are converted to the POSIX style.
|
|
46
|
+
By default, all paths within the framework are assumed to be in a POSIX style, and all input paths are converted to the POSIX style. This works appropriately within a Unix and a Windows environment. This module offers up [path](https://github.com/travetto/travetto/tree/main/module/manifest/src/path.ts#L48) as an equivalent to [Node](https://nodejs.org)'s [path](https://nodejs.org/api/path.html) library. This allows for consistent behavior across all file-interactions.
|
|
47
47
|
|
|
48
48
|
## Anatomy of a Manifest
|
|
49
49
|
|
|
@@ -131,7 +131,7 @@ The context contains:
|
|
|
131
131
|
* The main module to execute. (*This primarily pertains to mono-repo support when there are multiple modules in the project*)
|
|
132
132
|
* The root path of the project/workspace
|
|
133
133
|
* Whether or not the project is a mono-repo. (*This is determined by using the 'workspaces' field in your [Package JSON](https://docs.npmjs.com/cli/v9/configuring-npm/package-json)*)
|
|
134
|
-
* The location where all compiled code will be stored.
|
|
134
|
+
* The location where all compiled code will be stored. Defaults to: `.trv_output`. (*Can be overridden in your [Package JSON](https://docs.npmjs.com/cli/v9/configuring-npm/package-json) in 'travetto.outputFolder'*)
|
|
135
135
|
* The location where the intermediate compiler will be created. Defaults to: `.trv_compiler`
|
|
136
136
|
* The location where tooling will be able to write to. Defaults to: `.trv_output`
|
|
137
137
|
* Which package manager is in use [Npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm)/[Yarn](https://yarnpkg.com)
|
|
@@ -140,7 +140,7 @@ The context contains:
|
|
|
140
140
|
* The framework version (based on @travetto/manifest)
|
|
141
141
|
|
|
142
142
|
### Modules
|
|
143
|
-
The modules represent all of the [Travetto](https://travetto.dev)-aware dependencies (including dev dependencies) used for compiling, testing and executing.
|
|
143
|
+
The modules represent all of the [Travetto](https://travetto.dev)-aware dependencies (including dev dependencies) used for compiling, testing and executing. A production-only version is produced when packaging the final output. Each module contains:
|
|
144
144
|
* The dependency npm name
|
|
145
145
|
* The dependency version
|
|
146
146
|
* A flag to determine if its a local module
|
|
@@ -148,7 +148,7 @@ The modules represent all of the [Travetto](https://travetto.dev)-aware dependen
|
|
|
148
148
|
* The path to the source folder, relative to the workspace root
|
|
149
149
|
* The path to the output folder, relative to the workspace output root
|
|
150
150
|
* The list of all files
|
|
151
|
-
* The profiles a module applies to.
|
|
151
|
+
* The profiles a module applies to. Values are std, test, compile, doc. Any empty value implies std
|
|
152
152
|
* Parent modules that imported this module
|
|
153
153
|
|
|
154
154
|
### Module Files
|
|
@@ -162,10 +162,10 @@ The module files are a simple categorization of files into a predetermined set o
|
|
|
162
162
|
* `resources` - Packaged resource, meant to pertain to the main module only. Files, under `resources/`
|
|
163
163
|
* `support` - All .ts files under the `support/` folder
|
|
164
164
|
* `support/resources` - Packaged resource files, meant to be included by other modules, under `support/resources/`
|
|
165
|
-
* `support/fixtures` - Test resources meant to shared across modules.
|
|
165
|
+
* `support/fixtures` - Test resources meant to shared across modules. Under `support/fixtures/`
|
|
166
166
|
* `doc` - Documentation files. `DOC.tsx` and All .ts/.tsx files under the `doc/` folder
|
|
167
|
-
* `$transformer` - All .ts files under the pattern `support/transform*`.
|
|
168
|
-
* `bin` - Entry point .js files.
|
|
167
|
+
* `$transformer` - All .ts files under the pattern `support/transform*`. These are used during compilation and never at runtime
|
|
168
|
+
* `bin` - Entry point .js files. All .js files under the `bin/` folder
|
|
169
169
|
|
|
170
170
|
Within each file there is a pattern of either a 3 or 4 element array:
|
|
171
171
|
|
package/__index__.ts
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
export * from './src/context.ts';
|
|
2
|
-
export * from './src/module.ts';
|
|
3
2
|
export * from './src/delta.ts';
|
|
3
|
+
export * from './src/file.ts';
|
|
4
4
|
export * from './src/manifest-index.ts';
|
|
5
|
+
export * from './src/module.ts';
|
|
5
6
|
export * from './src/package.ts';
|
|
6
|
-
export
|
|
7
|
-
export * from './src/
|
|
7
|
+
export { default as path } from './src/path.ts';
|
|
8
|
+
export * from './src/types/common.ts';
|
|
8
9
|
export * from './src/types/context.ts';
|
|
9
|
-
export * from './src/types/package.ts';
|
|
10
10
|
export * from './src/types/manifest.ts';
|
|
11
|
-
export * from './src/types/
|
|
12
|
-
export
|
|
11
|
+
export * from './src/types/package.ts';
|
|
12
|
+
export * from './src/util.ts';
|
package/package.json
CHANGED
|
@@ -1,43 +1,43 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@travetto/manifest",
|
|
3
|
-
"version": "8.0.0
|
|
4
|
-
"type": "module",
|
|
3
|
+
"version": "8.0.0",
|
|
5
4
|
"description": "Support for project indexing, manifesting, along with file watching",
|
|
6
5
|
"keywords": [
|
|
7
|
-
"path",
|
|
8
|
-
"package",
|
|
9
6
|
"manifest",
|
|
7
|
+
"package",
|
|
8
|
+
"path",
|
|
10
9
|
"travetto",
|
|
11
10
|
"typescript"
|
|
12
11
|
],
|
|
13
12
|
"homepage": "https://travetto.io",
|
|
14
13
|
"license": "MIT",
|
|
15
14
|
"author": {
|
|
16
|
-
"
|
|
17
|
-
"
|
|
15
|
+
"name": "Travetto Framework",
|
|
16
|
+
"email": "travetto.framework@gmail.com"
|
|
17
|
+
},
|
|
18
|
+
"repository": {
|
|
19
|
+
"url": "git+https://github.com/travetto/travetto.git",
|
|
20
|
+
"directory": "module/manifest"
|
|
18
21
|
},
|
|
19
22
|
"files": [
|
|
20
23
|
"__index__.ts",
|
|
21
24
|
"src"
|
|
22
25
|
],
|
|
26
|
+
"type": "module",
|
|
23
27
|
"main": "__index__.ts",
|
|
24
|
-
"
|
|
25
|
-
"
|
|
28
|
+
"publishConfig": {
|
|
29
|
+
"access": "public"
|
|
26
30
|
},
|
|
27
31
|
"dependencies": {
|
|
28
|
-
"@types/node": "^
|
|
32
|
+
"@types/node": "^26.2.0"
|
|
29
33
|
},
|
|
30
|
-
"
|
|
31
|
-
"
|
|
32
|
-
"directory": "module/manifest"
|
|
34
|
+
"engines": {
|
|
35
|
+
"node": ">=25.7.0"
|
|
33
36
|
},
|
|
34
37
|
"travetto": {
|
|
35
38
|
"displayName": "Manifest",
|
|
36
39
|
"doc": {
|
|
37
40
|
"baseUrl": "https://github.com/travetto/travetto/tree/main"
|
|
38
41
|
}
|
|
39
|
-
},
|
|
40
|
-
"publishConfig": {
|
|
41
|
-
"access": "public"
|
|
42
42
|
}
|
|
43
43
|
}
|
package/src/context.ts
CHANGED
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
import { existsSync, readFileSync } from 'node:fs';
|
|
2
|
-
import path from 'node:path';
|
|
3
2
|
import { createRequire } from 'node:module';
|
|
3
|
+
import path from 'node:path';
|
|
4
4
|
|
|
5
|
-
import { type Package, PACKAGE_MANAGERS } from './types/package.ts';
|
|
6
5
|
import type { ManifestContext } from './types/context.ts';
|
|
6
|
+
import { PACKAGE_MANAGERS, type Package } from './types/package.ts';
|
|
7
7
|
|
|
8
8
|
type Pkg = Package & { path: string };
|
|
9
9
|
|
|
10
|
-
// eslint-disable-next-line no-bitwise
|
|
11
10
|
const toPort = (location: string): number => (Math.abs([...location].reduce((a, b) => (a * 33) ^ b.charCodeAt(0), 5381)) % 29000) + 20000;
|
|
12
11
|
const toPosix = (location: string): string => location.replaceAll('\\', '/');
|
|
13
12
|
const readPackage = (file: string): Pkg => ({ ...JSON.parse(readFileSync(file, 'utf8')), path: toPosix(path.dirname(file)) });
|
|
@@ -47,10 +46,12 @@ const WORKSPACE_FILES = PACKAGE_MANAGERS.map(x => x.workspaceFile!).filter(Boole
|
|
|
47
46
|
* Gets build context
|
|
48
47
|
*/
|
|
49
48
|
export function getManifestContext(root: string = process.cwd()): ManifestContext {
|
|
50
|
-
const workspace = findPackage(
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
49
|
+
const workspace = findPackage(
|
|
50
|
+
root,
|
|
51
|
+
pkg =>
|
|
52
|
+
!!pkg?.workspaces ||
|
|
53
|
+
!!pkg?.travetto?.build?.isolated ||
|
|
54
|
+
(!!pkg && WORKSPACE_FILES.some(file => existsSync(path.resolve(pkg.path, file))))
|
|
54
55
|
);
|
|
55
56
|
if (workspace.type !== 'module') {
|
|
56
57
|
throw new Error('Only ESM modules are supported, package.json must be of type module');
|
|
@@ -60,9 +61,10 @@ export function getManifestContext(root: string = process.cwd()): ManifestContex
|
|
|
60
61
|
const resolve = createRequire(path.resolve(workspace.path, 'node_modules')).resolve.bind(null);
|
|
61
62
|
const wsPrefix = `${workspace.path}/`;
|
|
62
63
|
const moduleName = process.env.TRV_MODULE === workspace.name ? workspace.path : process.env.TRV_MODULE;
|
|
63
|
-
const modulePkg =
|
|
64
|
-
|
|
65
|
-
|
|
64
|
+
const modulePkg =
|
|
65
|
+
workspace.workspaces && moduleName
|
|
66
|
+
? readPackage(resolve(`${moduleName}/package.json`))
|
|
67
|
+
: (findPackage(root, pkg => !!pkg) ?? workspace);
|
|
66
68
|
|
|
67
69
|
return {
|
|
68
70
|
workspace: {
|
|
@@ -84,4 +86,4 @@ export function getManifestContext(root: string = process.cwd()): ManifestContex
|
|
|
84
86
|
description: modulePkg.description
|
|
85
87
|
}
|
|
86
88
|
};
|
|
87
|
-
}
|
|
89
|
+
}
|
package/src/delta.ts
CHANGED
|
@@ -2,16 +2,24 @@ import fs from 'node:fs/promises';
|
|
|
2
2
|
|
|
3
3
|
import { ManifestModuleUtil } from './module.ts';
|
|
4
4
|
import path from './path.ts';
|
|
5
|
-
|
|
6
|
-
import type { ManifestModule, ManifestModuleCore, ManifestModuleFile, ManifestRoot } from './types/manifest.ts';
|
|
7
5
|
import type { ChangeEventType, ManifestModuleFileType, ManifestModuleFolderType } from './types/common.ts';
|
|
8
6
|
import type { ManifestContext } from './types/context.ts';
|
|
7
|
+
import type { ManifestModule, ManifestModuleCore, ManifestModuleFile, ManifestRoot } from './types/manifest.ts';
|
|
9
8
|
|
|
10
9
|
type DeltaEventType = ChangeEventType | 'missing' | 'dirty';
|
|
11
10
|
type DeltaModule = ManifestModuleCore & { files: Record<string, ManifestModuleFile> };
|
|
12
|
-
export type DeltaEvent = { file: string
|
|
13
|
-
|
|
14
|
-
const VALID_SOURCE_FOLDERS = new Set<ManifestModuleFolderType>([
|
|
11
|
+
export type DeltaEvent = { file: string; type: DeltaEventType; module: string; sourceFile: string };
|
|
12
|
+
|
|
13
|
+
const VALID_SOURCE_FOLDERS = new Set<ManifestModuleFolderType>([
|
|
14
|
+
'bin',
|
|
15
|
+
'src',
|
|
16
|
+
'test',
|
|
17
|
+
'support',
|
|
18
|
+
'$index',
|
|
19
|
+
'$transformer',
|
|
20
|
+
'$package',
|
|
21
|
+
'doc'
|
|
22
|
+
]);
|
|
15
23
|
const VALID_SOURCE_TYPE = new Set<ManifestModuleFileType>(['js', 'ts', 'package-json']);
|
|
16
24
|
const VALID_OUTPUT_TYPE = new Set<ManifestModuleFileType>([...VALID_SOURCE_TYPE, 'typings']);
|
|
17
25
|
|
|
@@ -21,8 +29,7 @@ const TypedObject: { keys<T = unknown, K extends keyof T = keyof T>(item: T): K[
|
|
|
21
29
|
* Produce delta for the manifest
|
|
22
30
|
*/
|
|
23
31
|
export class ManifestDeltaUtil {
|
|
24
|
-
|
|
25
|
-
static #getNewest(stat: { mtimeMs: number, ctimeMs: number }): number {
|
|
32
|
+
static #getNewest(stat: { mtimeMs: number; ctimeMs: number }): number {
|
|
26
33
|
return Math.max(stat.mtimeMs, stat.ctimeMs);
|
|
27
34
|
}
|
|
28
35
|
|
|
@@ -92,17 +99,16 @@ export class ManifestDeltaUtil {
|
|
|
92
99
|
*/
|
|
93
100
|
static async produceDelta(manifest: ManifestRoot): Promise<DeltaEvent[]> {
|
|
94
101
|
const deltaLeft = Object.fromEntries(
|
|
95
|
-
Object.values(manifest.modules)
|
|
96
|
-
.map(module => [module.name, { ...module, files: this.#flattenModuleFiles(module) }])
|
|
102
|
+
Object.values(manifest.modules).map(module => [module.name, { ...module, files: this.#flattenModuleFiles(module) }])
|
|
97
103
|
);
|
|
98
104
|
|
|
99
105
|
const out: DeltaEvent[] = [];
|
|
100
106
|
const outputFolder = path.resolve(manifest.workspace.path, manifest.build.outputFolder);
|
|
101
107
|
|
|
102
108
|
for (const leftModule of Object.values(deltaLeft)) {
|
|
103
|
-
out.push(...await this.#deltaModules(manifest, outputFolder, leftModule));
|
|
109
|
+
out.push(...(await this.#deltaModules(manifest, outputFolder, leftModule)));
|
|
104
110
|
}
|
|
105
111
|
|
|
106
112
|
return out;
|
|
107
113
|
}
|
|
108
|
-
}
|
|
114
|
+
}
|
package/src/dependencies.ts
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
import { PackageUtil } from './package.ts';
|
|
2
2
|
import path from './path.ts';
|
|
3
|
-
|
|
4
|
-
import type { Package, PackageDependencyType } from './types/package.ts';
|
|
5
3
|
import type { ManifestContext } from './types/context.ts';
|
|
6
4
|
import type { PackageModule } from './types/manifest.ts';
|
|
5
|
+
import type { Package, PackageDependencyType } from './types/package.ts';
|
|
7
6
|
|
|
8
|
-
type CreateOpts = Partial<Pick<PackageModule, 'main' | 'workspace' | 'production'>> & { roleRoot?: boolean
|
|
7
|
+
type CreateOpts = Partial<Pick<PackageModule, 'main' | 'workspace' | 'production'>> & { roleRoot?: boolean; parent?: PackageModule };
|
|
9
8
|
|
|
10
9
|
type VisitableNode = {
|
|
11
10
|
/** Request package */
|
|
@@ -22,10 +21,11 @@ type VisitableNode = {
|
|
|
22
21
|
* Used for walking dependencies for collecting modules for the manifest
|
|
23
22
|
*/
|
|
24
23
|
export class PackageModuleVisitor {
|
|
25
|
-
|
|
26
24
|
static async visit(ctx: ManifestContext): Promise<Iterable<PackageModule>> {
|
|
27
|
-
const visitor = new PackageModuleVisitor(
|
|
28
|
-
|
|
25
|
+
const visitor = new PackageModuleVisitor(
|
|
26
|
+
ctx,
|
|
27
|
+
Object.fromEntries((await PackageUtil.resolveWorkspaces(ctx)).map(workspace => [workspace.name, workspace.path]))
|
|
28
|
+
);
|
|
29
29
|
return visitor.visit();
|
|
30
30
|
}
|
|
31
31
|
|
|
@@ -45,22 +45,26 @@ export class PackageModuleVisitor {
|
|
|
45
45
|
*/
|
|
46
46
|
#create(sourcePath: string, { main, workspace, production = false, roleRoot = false, parent }: CreateOpts = {}): VisitableNode {
|
|
47
47
|
const pkg = PackageUtil.readPackage(sourcePath);
|
|
48
|
-
const value = this.#cache[sourcePath] ??= {
|
|
48
|
+
const value = (this.#cache[sourcePath] ??= {
|
|
49
49
|
main,
|
|
50
50
|
production,
|
|
51
51
|
name: pkg.name,
|
|
52
52
|
version: pkg.version,
|
|
53
|
-
workspace: workspace ??
|
|
53
|
+
workspace: workspace ?? pkg.name in this.#workspaceModules,
|
|
54
54
|
internal: pkg.private === true,
|
|
55
55
|
sourceFolder: sourcePath === this.#ctx.workspace.path ? '' : sourcePath.replace(`${this.#ctx.workspace.path}/`, ''),
|
|
56
56
|
outputFolder: `node_modules/${pkg.name}`,
|
|
57
57
|
state: {
|
|
58
|
-
childSet: new Set(),
|
|
59
|
-
|
|
58
|
+
childSet: new Set(),
|
|
59
|
+
parentSet: new Set(),
|
|
60
|
+
roleSet: new Set(),
|
|
61
|
+
roleRoot,
|
|
62
|
+
travetto: pkg.travetto,
|
|
63
|
+
dependencies: new Set(Object.keys(pkg.dependencies ?? {}))
|
|
60
64
|
}
|
|
61
|
-
};
|
|
65
|
+
});
|
|
62
66
|
|
|
63
|
-
const dependencies: PackageDependencyType[] = ['dependencies', ...(value.main ? ['devDependencies'] as const : [])];
|
|
67
|
+
const dependencies: PackageDependencyType[] = ['dependencies', ...(value.main ? (['devDependencies'] as const) : [])];
|
|
64
68
|
const children = Object.fromEntries(dependencies.flatMap(dependency => Object.entries(pkg[dependency] ?? {})));
|
|
65
69
|
return { pkg, value, children, parent };
|
|
66
70
|
}
|
|
@@ -69,19 +73,22 @@ export class PackageModuleVisitor {
|
|
|
69
73
|
* Get monorepo root includes
|
|
70
74
|
*/
|
|
71
75
|
#getMonoRootIncludes(parent: VisitableNode): VisitableNode[] {
|
|
72
|
-
if (!(this.#ctx.workspace.mono && !this.#ctx.main.folder)) {
|
|
76
|
+
if (!(this.#ctx.workspace.mono && !this.#ctx.main.folder)) {
|
|
77
|
+
// If not mono root, bail
|
|
73
78
|
return [];
|
|
74
79
|
}
|
|
75
80
|
|
|
76
|
-
return Object.values(this.#workspaceModules)
|
|
77
|
-
|
|
81
|
+
return Object.values(this.#workspaceModules).map(folder =>
|
|
82
|
+
this.#create(folder, { main: true, workspace: true, roleRoot: true, parent: parent.value })
|
|
83
|
+
);
|
|
78
84
|
}
|
|
79
85
|
|
|
80
86
|
/**
|
|
81
87
|
* Determine default includes
|
|
82
88
|
*/
|
|
83
89
|
#getIncludes(parent: VisitableNode): VisitableNode[] {
|
|
84
|
-
if (this.#ctx.workspace.mono && !this.#ctx.main.folder) {
|
|
90
|
+
if (this.#ctx.workspace.mono && !this.#ctx.main.folder) {
|
|
91
|
+
// If mono and not at mono root, bail
|
|
85
92
|
return [];
|
|
86
93
|
}
|
|
87
94
|
|
|
@@ -92,7 +99,7 @@ export class PackageModuleVisitor {
|
|
|
92
99
|
);
|
|
93
100
|
} else {
|
|
94
101
|
return Object.values(this.#workspaceModules)
|
|
95
|
-
.filter(
|
|
102
|
+
.filter(folder => PackageUtil.readPackage(folder).travetto?.workspaceInclude)
|
|
96
103
|
.map(folder => this.#create(folder, { workspace: true, parent: parent.value }));
|
|
97
104
|
}
|
|
98
105
|
}
|
|
@@ -106,9 +113,12 @@ export class PackageModuleVisitor {
|
|
|
106
113
|
// All first-level dependencies should have role filled in (for propagation)
|
|
107
114
|
for (const dependency of [...modules].filter(module => module.state.roleRoot)) {
|
|
108
115
|
dependency.state.roleSet.clear(); // Ensure the roleRoot is empty
|
|
109
|
-
for (const child of dependency.state.childSet) {
|
|
116
|
+
for (const child of dependency.state.childSet) {
|
|
117
|
+
// Visit children
|
|
110
118
|
const childDependency = mapping.get(child)!.item;
|
|
111
|
-
if (childDependency.state.roleRoot) {
|
|
119
|
+
if (childDependency.state.roleRoot) {
|
|
120
|
+
continue;
|
|
121
|
+
}
|
|
112
122
|
// Set roles for all top level modules
|
|
113
123
|
childDependency.state.roleSet = new Set(childDependency.state.travetto?.roles ?? ['std']);
|
|
114
124
|
}
|
|
@@ -124,7 +134,9 @@ export class PackageModuleVisitor {
|
|
|
124
134
|
for (const { item } of toProcess) {
|
|
125
135
|
for (const childName of item.state.childSet) {
|
|
126
136
|
const child = mapping.get(childName);
|
|
127
|
-
if (!child) {
|
|
137
|
+
if (!child) {
|
|
138
|
+
continue;
|
|
139
|
+
}
|
|
128
140
|
child.parent.delete(item.name);
|
|
129
141
|
// Propagate roles from parent to child
|
|
130
142
|
if (!child.item.state.roleRoot) {
|
|
@@ -133,7 +145,7 @@ export class PackageModuleVisitor {
|
|
|
133
145
|
}
|
|
134
146
|
}
|
|
135
147
|
// Allow production to trickle down as needed
|
|
136
|
-
child.item.production ||=
|
|
148
|
+
child.item.production ||= item.production && item.state.dependencies.has(childName);
|
|
137
149
|
}
|
|
138
150
|
}
|
|
139
151
|
// Remove from mapping
|
|
@@ -144,7 +156,7 @@ export class PackageModuleVisitor {
|
|
|
144
156
|
|
|
145
157
|
// Mark as standard at the end
|
|
146
158
|
for (const dependency of [...modules].filter(module => module.state.roleRoot)) {
|
|
147
|
-
dependency.state.roleSet = new Set(['std', ...dependency.state.travetto?.roles ?? []]);
|
|
159
|
+
dependency.state.roleSet = new Set(['std', ...(dependency.state.travetto?.roles ?? [])]);
|
|
148
160
|
}
|
|
149
161
|
|
|
150
162
|
return [...modules].toSorted((a, b) => a.name.localeCompare(b.name));
|
|
@@ -157,11 +169,7 @@ export class PackageModuleVisitor {
|
|
|
157
169
|
const seen = new Set<PackageModule>();
|
|
158
170
|
const mainRequire = this.#create(this.#mainSourcePath, { main: true, workspace: true, roleRoot: true, production: true });
|
|
159
171
|
|
|
160
|
-
const queue = [
|
|
161
|
-
mainRequire,
|
|
162
|
-
...this.#getMonoRootIncludes(mainRequire),
|
|
163
|
-
...this.#getIncludes(mainRequire)
|
|
164
|
-
];
|
|
172
|
+
const queue = [mainRequire, ...this.#getMonoRootIncludes(mainRequire), ...this.#getIncludes(mainRequire)];
|
|
165
173
|
|
|
166
174
|
while (queue.length) {
|
|
167
175
|
const { value: node, parent, children, pkg } = queue.shift()!; // Visit initial set first
|
|
@@ -190,4 +198,4 @@ export class PackageModuleVisitor {
|
|
|
190
198
|
|
|
191
199
|
return await this.#complete(seen);
|
|
192
200
|
}
|
|
193
|
-
}
|
|
201
|
+
}
|
package/src/file.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import fs from 'node:fs/promises';
|
|
2
1
|
import { readFileSync } from 'node:fs';
|
|
2
|
+
import fs from 'node:fs/promises';
|
|
3
3
|
import os from 'node:os';
|
|
4
4
|
|
|
5
5
|
import path from './path.ts';
|
|
@@ -25,4 +25,4 @@ export class ManifestFileUtil {
|
|
|
25
25
|
static readAsJsonSync<T = unknown>(file: string): T {
|
|
26
26
|
return JSON.parse(readFileSync(file, 'utf8'));
|
|
27
27
|
}
|
|
28
|
-
}
|
|
28
|
+
}
|
package/src/manifest-index.ts
CHANGED
|
@@ -2,10 +2,9 @@ import { existsSync } from 'node:fs';
|
|
|
2
2
|
|
|
3
3
|
import { ManifestModuleUtil } from './module.ts';
|
|
4
4
|
import path from './path.ts';
|
|
5
|
+
import type { FindConfig, IndexedFile, IndexedModule, ManifestModule, ManifestModuleFile, ManifestRoot } from './types/manifest.ts';
|
|
5
6
|
import { ManifestUtil } from './util.ts';
|
|
6
7
|
|
|
7
|
-
import type { ManifestModule, ManifestRoot, ManifestModuleFile, IndexedModule, IndexedFile, FindConfig } from './types/manifest.ts';
|
|
8
|
-
|
|
9
8
|
const TypedObject: {
|
|
10
9
|
keys<T = unknown, K extends keyof T = keyof T>(item: T): K[];
|
|
11
10
|
fromEntries<K extends string | symbol, V>(items: ([K, V] | readonly [K, V])[]): Record<K, V>;
|
|
@@ -16,7 +15,6 @@ const TypedObject: {
|
|
|
16
15
|
* Manifest index
|
|
17
16
|
*/
|
|
18
17
|
export class ManifestIndex {
|
|
19
|
-
|
|
20
18
|
#arbitraryLookup?: (parts: string[]) => ManifestModule | undefined;
|
|
21
19
|
#manifest: ManifestRoot;
|
|
22
20
|
#modules: IndexedModule[];
|
|
@@ -81,16 +79,15 @@ export class ManifestIndex {
|
|
|
81
79
|
this.#sourceToEntry.clear();
|
|
82
80
|
this.#arbitraryLookup = undefined;
|
|
83
81
|
|
|
84
|
-
this.#modules = Object.values(this.#manifest.modules)
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
}));
|
|
82
|
+
this.#modules = Object.values(this.#manifest.modules).map(module => ({
|
|
83
|
+
...module,
|
|
84
|
+
outputPath: this.#resolveOutput(module.outputFolder),
|
|
85
|
+
sourcePath: path.resolve(this.#manifest.workspace.path, module.sourceFolder),
|
|
86
|
+
children: new Set(),
|
|
87
|
+
files: TypedObject.fromEntries(
|
|
88
|
+
TypedObject.entries(module.files).map(([folder, files]) => [folder, this.#moduleFiles(module, files ?? [])])
|
|
89
|
+
)
|
|
90
|
+
}));
|
|
94
91
|
|
|
95
92
|
for (const module of this.#modules) {
|
|
96
93
|
for (const files of Object.values(module.files ?? {})) {
|
|
@@ -139,10 +136,7 @@ export class ManifestIndex {
|
|
|
139
136
|
for (const [folder, files] of TypedObject.entries(module.files)) {
|
|
140
137
|
if (config.folder?.(folder) ?? true) {
|
|
141
138
|
for (const file of files) {
|
|
142
|
-
if (
|
|
143
|
-
(config.file?.(file) ?? true) &&
|
|
144
|
-
(config.sourceOnly === false || file.type === 'ts')
|
|
145
|
-
) {
|
|
139
|
+
if ((config.file?.(file) ?? true) && (config.sourceOnly === false || file.type === 'ts')) {
|
|
146
140
|
searchSpace.push(file);
|
|
147
141
|
}
|
|
148
142
|
}
|
|
@@ -241,7 +235,8 @@ export class ManifestIndex {
|
|
|
241
235
|
seen.add(next);
|
|
242
236
|
const module = this.getModule(next)!;
|
|
243
237
|
toProcess.push(...module[field]);
|
|
244
|
-
if (next !== this.#manifest.main.name) {
|
|
238
|
+
if (next !== this.#manifest.main.name) {
|
|
239
|
+
// Do not include self
|
|
245
240
|
out.push(module);
|
|
246
241
|
}
|
|
247
242
|
}
|
|
@@ -254,13 +249,11 @@ export class ManifestIndex {
|
|
|
254
249
|
*/
|
|
255
250
|
findModuleForArbitraryFile(file: string): ManifestModule | undefined {
|
|
256
251
|
const base = this.#manifest.workspace.path;
|
|
257
|
-
const lookup = this.#arbitraryLookup ??= ManifestUtil.lookupTrie(
|
|
252
|
+
const lookup = (this.#arbitraryLookup ??= ManifestUtil.lookupTrie(
|
|
258
253
|
Object.values(this.#manifest.modules),
|
|
259
254
|
module => module.sourceFolder.split('/'),
|
|
260
|
-
sub =>
|
|
261
|
-
|
|
262
|
-
!existsSync(path.resolve(base, ...sub, '.git'))
|
|
263
|
-
);
|
|
255
|
+
sub => !existsSync(path.resolve(base, ...sub, 'package.json')) && !existsSync(path.resolve(base, ...sub, '.git'))
|
|
256
|
+
));
|
|
264
257
|
return lookup(file.replace(`${base}/`, '').split('/'));
|
|
265
258
|
}
|
|
266
259
|
|
|
@@ -306,7 +299,7 @@ export class ManifestIndex {
|
|
|
306
299
|
/**
|
|
307
300
|
* Group by lineage, data can be duplicated
|
|
308
301
|
*/
|
|
309
|
-
groupByLineage<T extends { action: string }>(items: { item: T
|
|
302
|
+
groupByLineage<T extends { action: string }>(items: { item: T; module: string }[]): Map<string, T[]> {
|
|
310
303
|
const itemsByModule = new Map<string, T[]>();
|
|
311
304
|
for (const event of items) {
|
|
312
305
|
const moduleSet = new Set(this.getDependentModules(event.module, 'parents').map(module => module.name));
|
|
@@ -332,4 +325,4 @@ export class ManifestIndex {
|
|
|
332
325
|
resolvePackageCommand(cmd: string): string {
|
|
333
326
|
return path.resolve(this.manifest.workspace.path, 'node_modules', '.bin', cmd);
|
|
334
327
|
}
|
|
335
|
-
}
|
|
328
|
+
}
|
package/src/module.ts
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
import fs from 'node:fs/promises';
|
|
2
2
|
|
|
3
|
-
import path from './path.ts';
|
|
4
3
|
import { PackageModuleVisitor } from './dependencies.ts';
|
|
5
|
-
|
|
6
|
-
import type { ManifestModuleFileType,
|
|
7
|
-
import type { ManifestModuleFile, ManifestModule, PackageModule } from './types/manifest.ts';
|
|
4
|
+
import path from './path.ts';
|
|
5
|
+
import type { ManifestModuleFileType, ManifestModuleFolderType, ManifestModuleRole } from './types/common.ts';
|
|
8
6
|
import type { ManifestContext } from './types/context.ts';
|
|
7
|
+
import type { ManifestModule, ManifestModuleFile, PackageModule } from './types/manifest.ts';
|
|
9
8
|
|
|
10
9
|
const EXT_MAPPING: Record<string, ManifestModuleFileType> = {
|
|
11
10
|
'.js': 'js',
|
|
@@ -17,11 +16,7 @@ const EXT_MAPPING: Record<string, ManifestModuleFileType> = {
|
|
|
17
16
|
'.md': 'md'
|
|
18
17
|
};
|
|
19
18
|
|
|
20
|
-
const INDEX_FILES = new Set(
|
|
21
|
-
['__index__', '__index', 'index'].flatMap(file =>
|
|
22
|
-
['ts', 'tsx', 'js'].map(ext => `${file}.${ext}`)
|
|
23
|
-
)
|
|
24
|
-
);
|
|
19
|
+
const INDEX_FILES = new Set(['__index__', '__index', 'index'].flatMap(file => ['ts', 'tsx', 'js'].map(ext => `${file}.${ext}`)));
|
|
25
20
|
|
|
26
21
|
const STD_TOP_FOLDERS = new Set(['src', 'bin', 'support']);
|
|
27
22
|
const FULL_TOP_FOLDERS = new Set([...STD_TOP_FOLDERS, 'doc', 'test', 'resources']);
|
|
@@ -40,7 +35,6 @@ const SUPPORT_FILE_MAP: Record<string, ManifestModuleRole> = {
|
|
|
40
35
|
const SUPPORT_FILE_REGEX = new RegExp(`^support[/](?<name>${Object.keys(SUPPORT_FILE_MAP).join('|')})[./]`);
|
|
41
36
|
|
|
42
37
|
export class ManifestModuleUtil {
|
|
43
|
-
|
|
44
38
|
static TYPINGS_EXT = '.d.ts';
|
|
45
39
|
static OUTPUT_EXT = '.js';
|
|
46
40
|
static SOURCE_DEF_EXT = '.ts';
|
|
@@ -50,7 +44,7 @@ export class ManifestModuleUtil {
|
|
|
50
44
|
|
|
51
45
|
static #scanCache: Record<string, string[]> = {};
|
|
52
46
|
|
|
53
|
-
static #getNewest(stat: { mtimeMs: number
|
|
47
|
+
static #getNewest(stat: { mtimeMs: number; ctimeMs: number }): number {
|
|
54
48
|
return Math.max(stat.mtimeMs, stat.ctimeMs);
|
|
55
49
|
}
|
|
56
50
|
|
|
@@ -70,7 +64,7 @@ export class ManifestModuleUtil {
|
|
|
70
64
|
return this.#scanCache[key];
|
|
71
65
|
}
|
|
72
66
|
|
|
73
|
-
if (!await fs.stat(folder, { throwIfNoEntry: false })) {
|
|
67
|
+
if (!(await fs.stat(folder, { throwIfNoEntry: false }))) {
|
|
74
68
|
return [];
|
|
75
69
|
}
|
|
76
70
|
|
|
@@ -78,7 +72,7 @@ export class ManifestModuleUtil {
|
|
|
78
72
|
|
|
79
73
|
const exclude = new Set([
|
|
80
74
|
path.resolve(ctx.workspace.path, ctx.build.outputFolder),
|
|
81
|
-
path.resolve(ctx.workspace.path, ctx.build.toolFolder)
|
|
75
|
+
path.resolve(ctx.workspace.path, ctx.build.toolFolder)
|
|
82
76
|
]);
|
|
83
77
|
|
|
84
78
|
const topFolders = full ? FULL_TOP_FOLDERS : STD_TOP_FOLDERS;
|
|
@@ -94,7 +88,7 @@ export class ManifestModuleUtil {
|
|
|
94
88
|
const [top, depth] = popped;
|
|
95
89
|
|
|
96
90
|
// Don't navigate into sub-folders with package.json's
|
|
97
|
-
if (top !== folder && await fs.stat(`${top}/package.json`, { throwIfNoEntry: false })) {
|
|
91
|
+
if (top !== folder && (await fs.stat(`${top}/package.json`, { throwIfNoEntry: false }))) {
|
|
98
92
|
continue;
|
|
99
93
|
} else if (exclude.has(top)) {
|
|
100
94
|
continue;
|
|
@@ -118,7 +112,7 @@ export class ManifestModuleUtil {
|
|
|
118
112
|
}
|
|
119
113
|
}
|
|
120
114
|
|
|
121
|
-
return this.#scanCache[key] = out;
|
|
115
|
+
return (this.#scanCache[key] = out);
|
|
122
116
|
}
|
|
123
117
|
|
|
124
118
|
/**
|
|
@@ -179,8 +173,10 @@ export class ManifestModuleUtil {
|
|
|
179
173
|
case 'test':
|
|
180
174
|
case 'doc':
|
|
181
175
|
case 'resources':
|
|
182
|
-
case 'support':
|
|
183
|
-
|
|
176
|
+
case 'support':
|
|
177
|
+
return key;
|
|
178
|
+
default:
|
|
179
|
+
throw new Error(`Unknown folder: ${key}`);
|
|
184
180
|
}
|
|
185
181
|
} else if (/^DOC[.]tsx?$/.test(moduleFile)) {
|
|
186
182
|
return 'doc';
|
|
@@ -197,7 +193,7 @@ export class ManifestModuleUtil {
|
|
|
197
193
|
* Convert file (by ext) to a known file type and also retrieve its latest timestamp
|
|
198
194
|
*/
|
|
199
195
|
static async transformFile(moduleFile: string, full: string): Promise<ManifestModuleFile> {
|
|
200
|
-
const updated = this.#getNewest(await fs.stat(full, { throwIfNoEntry: false }) ?? { mtimeMs: 0, ctimeMs: 0 });
|
|
196
|
+
const updated = this.#getNewest((await fs.stat(full, { throwIfNoEntry: false })) ?? { mtimeMs: 0, ctimeMs: 0 });
|
|
201
197
|
const moduleFileTuple: ManifestModuleFile = [moduleFile, this.getFileType(moduleFile), updated];
|
|
202
198
|
const role = this.getFileRole(moduleFile);
|
|
203
199
|
return role ? [...moduleFileTuple, role] : moduleFileTuple;
|
|
@@ -266,4 +262,4 @@ export class ManifestModuleUtil {
|
|
|
266
262
|
}
|
|
267
263
|
return type === 'ts' || type === 'package-json' || type === 'js' || type === 'typings';
|
|
268
264
|
}
|
|
269
|
-
}
|
|
265
|
+
}
|
package/src/package.ts
CHANGED
|
@@ -1,18 +1,16 @@
|
|
|
1
|
-
import { createRequire } from 'node:module';
|
|
2
1
|
import { execSync } from 'node:child_process';
|
|
3
2
|
import { existsSync } from 'node:fs';
|
|
3
|
+
import { createRequire } from 'node:module';
|
|
4
4
|
|
|
5
|
-
import path from './path.ts';
|
|
6
5
|
import { ManifestFileUtil } from './file.ts';
|
|
7
|
-
|
|
8
|
-
import { PackagePathSymbol, type Package, type PackageWorkspaceEntry } from './types/package.ts';
|
|
6
|
+
import path from './path.ts';
|
|
9
7
|
import type { ManifestContext } from './types/context.ts';
|
|
8
|
+
import { type Package, PackagePathSymbol, type PackageWorkspaceEntry } from './types/package.ts';
|
|
10
9
|
|
|
11
10
|
/**
|
|
12
11
|
* Utilities for querying, traversing and reading package.json files.
|
|
13
12
|
*/
|
|
14
13
|
export class PackageUtil {
|
|
15
|
-
|
|
16
14
|
static #resolvers: Record<string, (imp: string) => string> = {};
|
|
17
15
|
static #cache: Record<string, Package> = {};
|
|
18
16
|
static #workspaces: Record<string, PackageWorkspaceEntry[]> = {};
|
|
@@ -46,7 +44,8 @@ export class PackageUtil {
|
|
|
46
44
|
try {
|
|
47
45
|
const resolved = this.resolveImport(name, root);
|
|
48
46
|
return path.join(resolved.split(name)[0], name);
|
|
49
|
-
} catch {
|
|
47
|
+
} catch {
|
|
48
|
+
// When import lookup fails
|
|
50
49
|
let folder = root ?? process.cwd();
|
|
51
50
|
let previous = '';
|
|
52
51
|
while (folder !== previous) {
|
|
@@ -69,9 +68,9 @@ export class PackageUtil {
|
|
|
69
68
|
if (forceRead) {
|
|
70
69
|
delete this.#cache[modulePath];
|
|
71
70
|
}
|
|
72
|
-
const nodePackage = this.#cache[modulePath] ??= ManifestFileUtil.readAsJsonSync(
|
|
73
|
-
modulePath.endsWith('.json') ? modulePath : path.resolve(modulePath, 'package.json')
|
|
74
|
-
);
|
|
71
|
+
const nodePackage = (this.#cache[modulePath] ??= ManifestFileUtil.readAsJsonSync(
|
|
72
|
+
modulePath.endsWith('.json') ? modulePath : path.resolve(modulePath, 'package.json')
|
|
73
|
+
));
|
|
75
74
|
|
|
76
75
|
nodePackage.name ??= 'untitled'; // If a package.json (root-only) is missing a name, allows for execution
|
|
77
76
|
|
|
@@ -93,21 +92,30 @@ export class PackageUtil {
|
|
|
93
92
|
const rootPath = ctx.workspace.path;
|
|
94
93
|
const cache = path.resolve(rootPath, ctx.build.outputFolder, 'workspaces.json');
|
|
95
94
|
try {
|
|
96
|
-
return this.#workspaces[rootPath] ??= ManifestFileUtil.readAsJsonSync(cache);
|
|
95
|
+
return (this.#workspaces[rootPath] ??= ManifestFileUtil.readAsJsonSync(cache));
|
|
97
96
|
} catch {
|
|
98
97
|
let args: string[];
|
|
99
98
|
switch (ctx.workspace.manager) {
|
|
100
99
|
case 'yarn':
|
|
101
|
-
case 'npm':
|
|
102
|
-
|
|
100
|
+
case 'npm':
|
|
101
|
+
args = ['query', '.workspace'];
|
|
102
|
+
break;
|
|
103
|
+
case 'pnpm':
|
|
104
|
+
args = ['ls', '-r', '--depth', '-1', '--json'];
|
|
105
|
+
break;
|
|
103
106
|
}
|
|
104
107
|
|
|
105
108
|
const env = { PATH: process.env.PATH, NODE_PATH: process.env.NODE_PATH };
|
|
106
|
-
const text = execSync(`${ctx.workspace.manager} ${args.join(' ')}`, {
|
|
109
|
+
const text = execSync(`${ctx.workspace.manager} ${args.join(' ')}`, {
|
|
110
|
+
cwd: rootPath,
|
|
111
|
+
encoding: 'utf8',
|
|
112
|
+
env,
|
|
113
|
+
stdio: ['pipe', 'pipe']
|
|
114
|
+
});
|
|
107
115
|
const out: PackageWorkspaceEntry[] = JSON.parse(text.trim());
|
|
108
116
|
const filtered = out.map(item => ({ name: item.name, path: item.path }));
|
|
109
117
|
await ManifestFileUtil.bufferedFileWrite(cache, JSON.stringify(filtered));
|
|
110
118
|
return filtered;
|
|
111
119
|
}
|
|
112
120
|
}
|
|
113
|
-
}
|
|
121
|
+
}
|
package/src/path.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
+
import native from 'node:path';
|
|
1
2
|
import posix from 'node:path/posix';
|
|
2
3
|
import win32 from 'node:path/win32';
|
|
3
|
-
import native from 'node:path';
|
|
4
4
|
|
|
5
5
|
const toPosix = (file: string): string => file.replaceAll('\\', '/');
|
|
6
|
-
const toNative = (file: string): string => file.replace(/[
|
|
6
|
+
const toNative = (file: string): string => file.replace(/[/\\]/g, native.sep);
|
|
7
7
|
const cwd = (): string => toPosix(process.cwd());
|
|
8
8
|
|
|
9
9
|
const path: typeof posix & {
|
|
@@ -22,25 +22,27 @@ const path: typeof posix & {
|
|
|
22
22
|
toNative,
|
|
23
23
|
toPosix,
|
|
24
24
|
matchesGlob: (file, pattern) => posix.matchesGlob(toPosix(file), toPosix(pattern)),
|
|
25
|
-
...process.platform === 'win32'
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
25
|
+
...(process.platform === 'win32'
|
|
26
|
+
? {
|
|
27
|
+
resolve: (...args) => toPosix(native.resolve(cwd(), ...args.map(toPosix))),
|
|
28
|
+
join: (root, ...args) => toPosix(native.join(toPosix(root), ...args.map(toPosix))),
|
|
29
|
+
relative: (from, to) => toPosix(native.relative(toPosix(from), toPosix(to))),
|
|
30
|
+
isAbsolute: file => native.isAbsolute(toPosix(file)),
|
|
31
|
+
normalize: file => toPosix(native.normalize(toPosix(file))),
|
|
32
|
+
parse: file => native.parse(toPosix(file)),
|
|
33
|
+
format: value => toPosix(native.format(value)),
|
|
34
|
+
toNamespacedPath: file => toPosix(native.toNamespacedPath(toPosix(file)))
|
|
35
|
+
}
|
|
36
|
+
: {
|
|
37
|
+
relative: (from, to) => posix.relative(toPosix(from), toPosix(to)),
|
|
38
|
+
resolve: (...args) => posix.resolve(cwd(), ...args.map(toPosix)),
|
|
39
|
+
join: (...args) => posix.join(...args.map(toPosix)),
|
|
40
|
+
isAbsolute: file => posix.isAbsolute(toPosix(file)),
|
|
41
|
+
normalize: file => posix.normalize(toPosix(file)),
|
|
42
|
+
parse: file => posix.parse(toPosix(file)),
|
|
43
|
+
format: value => posix.format(value),
|
|
44
|
+
toNamespacedPath: file => toPosix(file)
|
|
45
|
+
})
|
|
44
46
|
};
|
|
45
47
|
|
|
46
|
-
export default path;
|
|
48
|
+
export default path;
|
package/src/types/common.ts
CHANGED
|
@@ -1,10 +1,19 @@
|
|
|
1
1
|
export type ManifestModuleFileType = 'typings' | 'ts' | 'js' | 'json' | 'package-json' | 'unknown' | 'fixture' | 'md';
|
|
2
2
|
export type ManifestModuleFolderType =
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
'
|
|
3
|
+
| '$root'
|
|
4
|
+
| '$index'
|
|
5
|
+
| '$package'
|
|
6
|
+
| 'src'
|
|
7
|
+
| 'bin'
|
|
8
|
+
| 'support'
|
|
9
|
+
| 'resources'
|
|
10
|
+
| 'test'
|
|
11
|
+
| 'doc'
|
|
12
|
+
| 'test/fixtures'
|
|
13
|
+
| 'support/fixtures'
|
|
14
|
+
| 'support/resources'
|
|
15
|
+
| '$transformer';
|
|
7
16
|
|
|
8
17
|
export type ManifestModuleRole = 'std' | 'test' | 'doc' | 'compile' | 'build';
|
|
9
18
|
|
|
10
|
-
export type ChangeEventType = 'create' | 'update' | 'delete';
|
|
19
|
+
export type ChangeEventType = 'create' | 'update' | 'delete';
|
package/src/types/context.ts
CHANGED
package/src/types/manifest.ts
CHANGED
|
@@ -3,8 +3,8 @@ import type { ManifestContext } from './context.ts';
|
|
|
3
3
|
import type { Package } from './package.ts';
|
|
4
4
|
|
|
5
5
|
export type ManifestModuleFile =
|
|
6
|
-
[path: string, type: ManifestModuleFileType, updated: number]
|
|
7
|
-
[path: string, type: ManifestModuleFileType, updated: number, role: ManifestModuleRole];
|
|
6
|
+
| [path: string, type: ManifestModuleFileType, updated: number]
|
|
7
|
+
| [path: string, type: ManifestModuleFileType, updated: number, role: ManifestModuleRole];
|
|
8
8
|
|
|
9
9
|
export type ManifestDepCore = {
|
|
10
10
|
/** Package name */
|
package/src/types/package.ts
CHANGED
|
@@ -66,4 +66,4 @@ export type Package = {
|
|
|
66
66
|
|
|
67
67
|
export type PackageDependencyType = 'dependencies' | 'devDependencies' | 'optionalDependencies' | 'peerDependencies';
|
|
68
68
|
|
|
69
|
-
export type PackageWorkspaceEntry = { name: string
|
|
69
|
+
export type PackageWorkspaceEntry = { name: string; path: string };
|
package/src/util.ts
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
|
-
import path from './path.ts';
|
|
2
|
-
import { ManifestModuleUtil } from './module.ts';
|
|
3
1
|
import { ManifestFileUtil } from './file.ts';
|
|
2
|
+
import { ManifestModuleUtil } from './module.ts';
|
|
4
3
|
import { PackageUtil } from './package.ts';
|
|
5
|
-
|
|
4
|
+
import path from './path.ts';
|
|
5
|
+
import type { ChangeEventType } from './types/common.ts';
|
|
6
6
|
import type { ManifestContext } from './types/context.ts';
|
|
7
7
|
import type { ManifestRoot } from './types/manifest.ts';
|
|
8
|
-
import type { ChangeEventType } from './types/common.ts';
|
|
9
8
|
|
|
10
9
|
const MANIFEST_FILE = 'manifest.json';
|
|
11
10
|
|
|
@@ -22,7 +21,7 @@ export class ManifestUtil {
|
|
|
22
21
|
workspace: ctx.workspace,
|
|
23
22
|
build: ctx.build,
|
|
24
23
|
main: ctx.main,
|
|
25
|
-
modules: await ManifestModuleUtil.produceModules(ctx)
|
|
24
|
+
modules: await ManifestModuleUtil.produceModules(ctx)
|
|
26
25
|
};
|
|
27
26
|
}
|
|
28
27
|
|
|
@@ -45,14 +44,17 @@ export class ManifestUtil {
|
|
|
45
44
|
build: {
|
|
46
45
|
...manifest.build,
|
|
47
46
|
// Mark output folder/workspace path as portable
|
|
48
|
-
outputFolder: '$$PRODUCTION$$'
|
|
47
|
+
outputFolder: '$$PRODUCTION$$'
|
|
49
48
|
},
|
|
50
49
|
main: manifest.main,
|
|
51
50
|
modules: Object.fromEntries(
|
|
52
|
-
modules.map(module => [
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
51
|
+
modules.map(module => [
|
|
52
|
+
module.name,
|
|
53
|
+
Object.assign(module, {
|
|
54
|
+
parents: module.parents.filter(parent => moduleNames.has(parent))
|
|
55
|
+
})
|
|
56
|
+
])
|
|
57
|
+
)
|
|
56
58
|
};
|
|
57
59
|
}
|
|
58
60
|
|
|
@@ -117,15 +119,17 @@ export class ManifestUtil {
|
|
|
117
119
|
* Produce the manifest context for the workspace module
|
|
118
120
|
*/
|
|
119
121
|
static getWorkspaceContext(ctx: ManifestContext): ManifestContext {
|
|
120
|
-
return ctx.workspace.mono
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
122
|
+
return ctx.workspace.mono
|
|
123
|
+
? {
|
|
124
|
+
workspace: ctx.workspace,
|
|
125
|
+
build: ctx.build,
|
|
126
|
+
main: {
|
|
127
|
+
name: ctx.workspace.name,
|
|
128
|
+
folder: '',
|
|
129
|
+
version: '0.0.0'
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
: ctx;
|
|
129
133
|
}
|
|
130
134
|
|
|
131
135
|
/**
|
|
@@ -151,9 +155,11 @@ export class ManifestUtil {
|
|
|
151
155
|
* Efficient lookup for path-based graphs
|
|
152
156
|
*/
|
|
153
157
|
static lookupTrie<T>(
|
|
154
|
-
inputs: T[],
|
|
158
|
+
inputs: T[],
|
|
159
|
+
getPath: (value: T) => string[],
|
|
160
|
+
validateUnknown?: (inputPath: string[]) => boolean
|
|
155
161
|
): (inputPath: string[]) => T | undefined {
|
|
156
|
-
type TrieNode = { value?: T
|
|
162
|
+
type TrieNode = { value?: T; subPaths: Record<string, TrieNode> };
|
|
157
163
|
const root: TrieNode = { subPaths: {} };
|
|
158
164
|
for (const item of inputs) {
|
|
159
165
|
const inputPath = getPath(item);
|
|
@@ -197,13 +203,17 @@ export class ManifestUtil {
|
|
|
197
203
|
const fileType = ManifestModuleUtil.getFileType(relativeFile);
|
|
198
204
|
const roleType = ManifestModuleUtil.getFileRole(relativeFile)!;
|
|
199
205
|
|
|
200
|
-
const manifestModuleFiles = manifest.modules[moduleName].files[folderKey] ??= [];
|
|
206
|
+
const manifestModuleFiles = (manifest.modules[moduleName].files[folderKey] ??= []);
|
|
201
207
|
const idx = manifestModuleFiles.findIndex(indexedFile => indexedFile[0] === relativeFile);
|
|
202
208
|
const wrappedIdx = idx < 0 ? manifestModuleFiles.length : idx;
|
|
203
209
|
|
|
204
210
|
switch (action) {
|
|
205
|
-
case 'create':
|
|
206
|
-
|
|
211
|
+
case 'create':
|
|
212
|
+
manifestModuleFiles[wrappedIdx] = [relativeFile, fileType, Date.now(), roleType];
|
|
213
|
+
break;
|
|
214
|
+
case 'delete':
|
|
215
|
+
idx >= 0 && manifestModuleFiles.splice(idx, 1);
|
|
216
|
+
break;
|
|
207
217
|
}
|
|
208
218
|
}
|
|
209
|
-
}
|
|
219
|
+
}
|