@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 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. The module provides:
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#L23) 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.
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. 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#L46) 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.
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. Defaults to: `.trv_output`. (*Can be overridden in your [Package JSON](https://docs.npmjs.com/cli/v9/configuring-npm/package-json) in 'travetto.outputFolder'*)
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. A production-only version is produced when packaging the final output. Each module contains:
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. Values are std, test, compile, doc. Any empty value implies std
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. Under `support/fixtures/`
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*`. These are used during compilation and never at runtime
168
- * `bin` - Entry point .js files. All .js files under the `bin/` folder
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 * from './src/util.ts';
7
- export * from './src/file.ts';
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/common.ts';
12
- export { default as path } from './src/path.ts';
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-alpha.9",
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
- "email": "travetto.framework@gmail.com",
17
- "name": "Travetto Framework"
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
- "engines": {
25
- "node": ">=25.7.0"
28
+ "publishConfig": {
29
+ "access": "public"
26
30
  },
27
31
  "dependencies": {
28
- "@types/node": "^25.9.2"
32
+ "@types/node": "^26.2.0"
29
33
  },
30
- "repository": {
31
- "url": "git+https://github.com/travetto/travetto.git",
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(root, pkg =>
51
- !!pkg?.workspaces ||
52
- !!pkg?.travetto?.build?.isolated ||
53
- (!!pkg && WORKSPACE_FILES.some(file => existsSync(path.resolve(pkg.path, file))))
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 = (!!workspace.workspaces && moduleName) ?
64
- readPackage(resolve(`${moduleName}/package.json`)) :
65
- findPackage(root, pkg => !!pkg) ?? workspace;
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, type: DeltaEventType, module: string, sourceFile: string };
13
-
14
- const VALID_SOURCE_FOLDERS = new Set<ManifestModuleFolderType>(['bin', 'src', 'test', 'support', '$index', '$transformer', '$package', 'doc']);
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
+ }
@@ -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, parent?: PackageModule };
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(ctx, Object.fromEntries((await PackageUtil.resolveWorkspaces(ctx))
28
- .map(workspace => [workspace.name, workspace.path])));
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 ?? (pkg.name in this.#workspaceModules),
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(), parentSet: new Set(), roleSet: new Set(), roleRoot,
59
- travetto: pkg.travetto, dependencies: new Set(Object.keys(pkg.dependencies ?? {}))
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)) { // If not mono root, bail
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
- .map(folder => this.#create(folder, { main: true, workspace: true, roleRoot: true, parent: parent.value }));
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) { // If mono and not at mono root, bail
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((folder) => PackageUtil.readPackage(folder).travetto?.workspaceInclude)
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) { // Visit children
116
+ for (const child of dependency.state.childSet) {
117
+ // Visit children
110
118
  const childDependency = mapping.get(child)!.item;
111
- if (childDependency.state.roleRoot) { continue; }
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) { continue; }
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 ||= (item.production && item.state.dependencies.has(childName));
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
+ }
@@ -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
- .map(module => ({
86
- ...module,
87
- outputPath: this.#resolveOutput(module.outputFolder),
88
- sourcePath: path.resolve(this.#manifest.workspace.path, module.sourceFolder),
89
- children: new Set(),
90
- files: TypedObject.fromEntries(
91
- TypedObject.entries(module.files).map(([folder, files]) => [folder, this.#moduleFiles(module, files ?? [])])
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) { // Do not include self
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
- !existsSync(path.resolve(base, ...sub, 'package.json')) &&
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, module: string }[]): Map<string, 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, ManifestModuleRole, ManifestModuleFolderType } from './types/common.ts';
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, ctimeMs: number }): 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': return key;
183
- default: throw new Error(`Unknown folder: ${key}`);
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 { // When import lookup fails
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': args = ['query', '.workspace']; break;
102
- case 'pnpm': args = ['ls', '-r', '--depth', '-1', '--json']; break;
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(' ')}`, { cwd: rootPath, encoding: 'utf8', env, stdio: ['pipe', 'pipe'] });
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(/[\/]/g, native.sep);
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
- resolve: (...args) => toPosix(native.resolve(cwd(), ...args.map(toPosix))),
27
- join: (root, ...args) => toPosix(native.join(toPosix(root), ...args.map(toPosix))),
28
- relative: (from, to) => toPosix(native.relative(toPosix(from), toPosix(to))),
29
- isAbsolute: (file) => native.isAbsolute(toPosix(file)),
30
- normalize: (file) => toPosix(native.normalize(toPosix(file))),
31
- parse: (file) => native.parse(toPosix(file)),
32
- format: (value) => toPosix(native.format(value)),
33
- toNamespacedPath: (file) => toPosix(native.toNamespacedPath(toPosix(file))),
34
- } : {
35
- relative: (from, to) => posix.relative(toPosix(from), toPosix(to)),
36
- resolve: (...args) => posix.resolve(cwd(), ...args.map(toPosix)),
37
- join: (...args) => posix.join(...args.map(toPosix)),
38
- isAbsolute: file => posix.isAbsolute(toPosix(file)),
39
- normalize: file => posix.normalize(toPosix(file)),
40
- parse: file => posix.parse(toPosix(file)),
41
- format: value => posix.format(value),
42
- toNamespacedPath: file => toPosix(file),
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;
@@ -1,10 +1,19 @@
1
1
  export type ManifestModuleFileType = 'typings' | 'ts' | 'js' | 'json' | 'package-json' | 'unknown' | 'fixture' | 'md';
2
2
  export type ManifestModuleFolderType =
3
- '$root' | '$index' | '$package' |
4
- 'src' | 'bin' | 'support' | 'resources' | 'test' | 'doc' |
5
- 'test/fixtures' | 'support/fixtures' | 'support/resources' |
6
- '$transformer';
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';
@@ -31,4 +31,4 @@ export type ManifestContext = {
31
31
  /** Version of the main module */
32
32
  version: string;
33
33
  };
34
- };
34
+ };
@@ -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 */
@@ -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, path: 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 => [module.name, Object.assign(module, {
53
- parents: module.parents.filter(parent => moduleNames.has(parent))
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
- workspace: ctx.workspace,
122
- build: ctx.build,
123
- main: {
124
- name: ctx.workspace.name,
125
- folder: '',
126
- version: '0.0.0',
127
- }
128
- } : ctx;
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[], getPath: (value: T) => string[], validateUnknown?: (inputPath: string[]) => boolean
158
+ inputs: T[],
159
+ getPath: (value: T) => string[],
160
+ validateUnknown?: (inputPath: string[]) => boolean
155
161
  ): (inputPath: string[]) => T | undefined {
156
- type TrieNode = { value?: T, subPaths: Record<string, TrieNode> };
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': manifestModuleFiles[wrappedIdx] = [relativeFile, fileType, Date.now(), roleType]; break;
206
- case 'delete': idx >= 0 && manifestModuleFiles.splice(idx, 1); break;
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
+ }