@travetto/manifest 3.0.2 → 3.0.3

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
@@ -1,6 +1,7 @@
1
1
  <!-- This file was generated by @travetto/doc and should not be modified directly -->
2
- <!-- Please modify https://github.com/travetto/travetto/tree/main/module/manifest/DOC.ts and execute "npx trv doc" to rebuild -->
2
+ <!-- Please modify https://github.com/travetto/travetto/tree/main/module/manifest/DOC.tsx and execute "npx trv doc" to rebuild -->
3
3
  # Manifest
4
+
4
5
  ## Support for project indexing, manifesting, along with file watching
5
6
 
6
7
  **Install: @travetto/manifest**
@@ -13,8 +14,6 @@ yarn add @travetto/manifest
13
14
  ```
14
15
 
15
16
  This module aims to be the boundary between the file system and the code. The module provides:
16
-
17
-
18
17
  * Project Manifesting
19
18
  * Manifest Delta
20
19
  * Class and Function Metadata
@@ -26,7 +25,7 @@ This module aims to be the boundary between the file system and the code. The m
26
25
  The project manifest fulfills two main goals: Compile-time Support, and Runtime Knowledge of the project.
27
26
 
28
27
  ### Compile-time Support
29
- During the compilation process, the compiler needs to know every file that is eligible for compilation, when the file was last created/modified, and any specific patterns for interacting with a given file (e.g. transformers vs. testing code vs. support files that happen to share a common extension with code).
28
+ During the compilation process, the compiler needs to know every file that is eligible for compilation, when the file was last created/modified, and any specific patterns for interacting with a given file (e.g. transformers vs. testing code vs. support files that happen to share a common extension with code).
30
29
 
31
30
  ### Runtime Knowledge
32
31
  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.
@@ -35,10 +34,9 @@ Additionally, once the code has been compiled (or even bundled after that), the
35
34
  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#L21) 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.
36
35
 
37
36
  ## Class and Function Metadata
37
+ For the framework to work properly, metadata needs to be collected about files, classes and functions to uniquely identify them, with support for detecting changes during live reloads. To achieve this, every `class` is decorated with an additional field of `Ⲑid`. `Ⲑid` represents a computed id that is tied to the file/class combination.
38
38
 
39
- For the framework to work properly, metadata needs to be collected about files, classes and functions to uniquely identify them, with support for detecting changes during live reloads. To achieve this, every `class` is decorated with an additional field of `Ⲑid`. `Ⲑid` represents a computed id that is tied to the file/class combination.
40
-
41
- `Ⲑid` is used heavily throughout the framework for determining which classes are owned by the framework, and being able to lookup the needed data from the [RootIndex](https://github.com/travetto/travetto/tree/main/module/manifest/src/root-index.ts) using the `getFunctionMetadata` method.
39
+ `Ⲑid` is used heavily throughout the framework for determining which classes are owned by the framework, and being able to lookup the needed data from the [RootIndex](https://github.com/travetto/travetto/tree/main/module/manifest/src/root-index.ts#L12) using the `getFunctionMetadata` method.
42
40
 
43
41
  **Code: Test Class**
44
42
  ```typescript
@@ -78,7 +76,6 @@ $ trv main ./doc/lookup.ts
78
76
 
79
77
  ## Module Indexing
80
78
  Once the manifest is created, the application runtime can now read this manifest, which allows for influencing runtime behavior. The most common patterns include:
81
-
82
79
  * Loading all source files
83
80
  * Iterating over every test file
84
81
  * Finding all source folders for watching
@@ -168,7 +165,7 @@ This method allows for watching one or more folders, and registering a callback
168
165
  [ "README.md", "md", 1868155200000 ]
169
166
  ],
170
167
  "doc": [
171
- [ "DOC.ts", "ts", 1868155200000, "doc" ],
168
+ [ "DOC.tsx", "ts", 1868155200000, "doc" ],
172
169
  [ "doc/lookup.ts", "ts", 1868155200000, "doc" ],
173
170
  [ "doc/test-class.ts", "ts", 1868155200000, "doc" ]
174
171
  ],
@@ -214,25 +211,21 @@ This method allows for watching one or more folders, and registering a callback
214
211
  ```
215
212
 
216
213
  ### General Context
217
- The general context describes the project-space and any important information for how to build/execute the code.
214
+ The general context describes the project-space and any important information for how to build/execute the code.
218
215
 
219
216
  The context contains:
220
-
221
217
  * A generated timestamp
222
- * Module Type: [commonjs](https://nodejs.org/api/modules.html) or [module](https://nodejs.org/api/esm.html)
223
- * The main module to execute. **Note**: This primarily pertains to mono-repo support when there are multiple modules in the project
218
+ * Module Type: `commonjs`([CommonJS](https://nodejs.org/api/modules.html)) or `module`([Ecmascript Module](https://nodejs.org/api/esm.html))
219
+ * The main module to execute. (*This primarily pertains to mono-repo support when there are multiple modules in the project*)
224
220
  * The root path of the project/workspace
225
- * Whether or not the project is a mono-repo. **Note**: This is determined by using the 'workspaces' field in your [object Object]
226
- * The location where all compiled code will be stored. Defaults to: `.trv_output`. **Note**: Can be overridden in your [object Object] in 'travetto.outputFolder'
221
+ * 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)*)
222
+ * 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'*)
227
223
  * The location where the intermediate compiler will be created. Defaults to: `.trv_compiler`
228
224
  * The location where tooling will be able to write to. Defaults to: `.trv_output`
229
225
  * Which package manager is in use [Npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm) or [Yarn](https://yarnpg.com)
230
226
 
231
227
  ### Modules
232
- The modules represent all of the [Travetto](https://travetto.dev)-aware dependencies (including dev dependencies) used for compiling, testing and executing. A prod-only version is produced when packaging the final output.
233
-
234
- Each module contains:
235
-
228
+ The modules represent all of the [Travetto](https://travetto.dev)-aware dependencies (including dev dependencies) used for compiling, testing and executing. A prod-only version is produced when packaging the final output. Each module contains:
236
229
  * The dependency npm name
237
230
  * The dependency version
238
231
  * A flag to determine if its a local module
@@ -245,7 +238,6 @@ Each module contains:
245
238
 
246
239
  ### Module Files
247
240
  The module files are a simple categorization of files into a predetermined set of folders:
248
-
249
241
  * $root - All uncategorized files at the module root
250
242
  * $index - __index__.ts, index.ts files at the root of the project
251
243
  * $package - The [Package JSON](https://docs.npmjs.com/cli/v9/configuring-npm/package-json) for the project
@@ -259,7 +251,6 @@ The module files are a simple categorization of files into a predetermined set o
259
251
  * doc - Documentation files. All .ts files under the doc/ folder
260
252
  * $transformer - All .ts files under the pattern support/transform*. These are used during compilation and never at runtime
261
253
  * bin - Entry point .js files. All .js files under the bin/ folder
262
-
263
254
  Within each file there is a pattern of either a 3 or 4 element array:
264
255
 
265
256
  **Code: Sample file**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@travetto/manifest",
3
- "version": "3.0.2",
3
+ "version": "3.0.3",
4
4
  "description": "Support for project indexing, manifesting, along with file watching",
5
5
  "keywords": [
6
6
  "path",
package/src/delta.ts CHANGED
@@ -36,15 +36,18 @@ export class ManifestDeltaUtil {
36
36
  const root = `${ctx.workspacePath}/${ctx.outputFolder}/${left.outputFolder}`;
37
37
  const right = new Set(
38
38
  (await ManifestModuleUtil.scanFolder(root, left.main))
39
- .filter(x => (x.endsWith('.ts') || x.endsWith('.js') || x.endsWith('package.json')))
40
- .map(x => x.replace(`${root}/`, '').replace(/[.][tj]s$/, ''))
39
+ .filter(x => {
40
+ const type = ManifestModuleUtil.getFileType(x);
41
+ return type === 'ts' || type === 'typings' || type === 'js' || type === 'package-json';
42
+ })
43
+ .map(x => ManifestModuleUtil.sourceToBlankExt(x.replace(`${root}/`, '')))
41
44
  );
42
45
 
43
46
  for (const el of Object.keys(left.files)) {
44
- const output = `${outputFolder}/${left.outputFolder}/${el.replace(/[.]ts$/, '.js')}`;
47
+ const output = ManifestModuleUtil.sourceToOutputExt(`${outputFolder}/${left.outputFolder}/${el}`);
45
48
  const [, , leftTs] = left.files[el];
46
49
  const stat = await fs.stat(output).catch(() => { });
47
- right.delete(el.replace(/[.][tj]s$/, ''));
50
+ right.delete(ManifestModuleUtil.sourceToBlankExt(el));
48
51
 
49
52
  if (!stat) {
50
53
  add(el, 'added');
@@ -1,3 +1,4 @@
1
+ import { ManifestModuleUtil } from './module';
1
2
  import { path } from './path';
2
3
 
3
4
  import {
@@ -78,13 +79,14 @@ export class ManifestIndex {
78
79
 
79
80
  #moduleFiles(m: ManifestModule, files: ManifestModuleFile[]): IndexedFile[] {
80
81
  return files.map(([f, type, ts, profile = 'std']) => {
82
+ const isSource = type === 'ts' || type === 'js';
81
83
  const sourceFile = path.resolve(this.#manifest.workspacePath, m.sourceFolder, f);
82
- const js = (type === 'ts' ? f.replace(/[.]ts$/, '.js') : f);
84
+ const js = isSource ? ManifestModuleUtil.sourceToOutputExt(f) : f;
83
85
  const outputFile = this.#resolveOutput(m.outputFolder, js);
84
86
  const modImport = `${m.name}/${js}`;
85
87
  let id = modImport.replace(`${m.name}/`, _ => _.replace(/[/]$/, ':'));
86
- if (type === 'ts' || type === 'js') {
87
- id = id.replace(/[.]js$/, '');
88
+ if (isSource) {
89
+ id = ManifestModuleUtil.sourceToBlankExt(id);
88
90
  }
89
91
 
90
92
  return { id, type, sourceFile, outputFile, import: modImport, profile, relativeFile: f, module: m.name };
@@ -117,7 +119,6 @@ export class ManifestIndex {
117
119
  this.#sourceToEntry.set(entry.sourceFile, entry);
118
120
  this.#importToEntry.set(entry.import, entry);
119
121
  this.#importToEntry.set(entry.import.replace(/[.]js$/, ''), entry);
120
- this.#importToEntry.set(entry.import.replace(/[.]js$/, '.ts'), entry);
121
122
  }
122
123
  }
123
124
  }
@@ -221,7 +222,7 @@ export class ManifestIndex {
221
222
  * Resolve import
222
223
  */
223
224
  resolveFileImport(name: string): string {
224
- return this.#importToEntry.get(name)?.outputFile ?? name;
225
+ return this.getFromImport(name)?.outputFile ?? name;
225
226
  }
226
227
 
227
228
  /**
@@ -237,6 +238,8 @@ export class ManifestIndex {
237
238
  * @param source
238
239
  */
239
240
  getFromImport(imp: string): IndexedFile | undefined {
241
+ // Strip ext
242
+ imp = ManifestModuleUtil.sourceToBlankExt(imp);
240
243
  return this.#importToEntry.get(imp);
241
244
  }
242
245
 
package/src/module.ts CHANGED
@@ -15,17 +15,15 @@ const EXT_MAPPING: Record<string, ManifestModuleFileType> = {
15
15
  '.cjs': 'js',
16
16
  '.json': 'json',
17
17
  '.ts': 'ts',
18
+ '.tsx': 'ts',
18
19
  '.md': 'md'
19
20
  };
20
21
 
21
- const INDEX_FILES = new Set([
22
- 'index.ts',
23
- 'index.js',
24
- '__index__.ts',
25
- '__index__.js',
26
- '__index.ts',
27
- '__index.js'
28
- ]);
22
+ const INDEX_FILES = new Set(
23
+ ['__index__', '__index', 'index', 'jsx-runtime'].flatMap(f =>
24
+ ['ts', 'tsx', 'js'].map(ext => `${f}.${ext}`)
25
+ )
26
+ );
29
27
 
30
28
  export class ManifestModuleUtil {
31
29
 
@@ -35,6 +33,13 @@ export class ManifestModuleUtil {
35
33
  return Math.max(stat.mtimeMs, stat.ctimeMs);
36
34
  }
37
35
 
36
+ /**
37
+ * Replace a source file's extension with a given value
38
+ */
39
+ static #sourceToExtension(inputFile: string, ext: string): string {
40
+ return inputFile.replace(/[.][tj]sx?$/, ext);
41
+ }
42
+
38
43
  /**
39
44
  * Simple file scanning
40
45
  */
@@ -93,7 +98,7 @@ export class ManifestModuleUtil {
93
98
  * Get file type for a file name
94
99
  */
95
100
  static getFileType(moduleFile: string): ManifestModuleFileType {
96
- if (moduleFile === 'package.json') {
101
+ if (moduleFile.endsWith('package.json')) {
97
102
  return 'package-json';
98
103
  } else if (
99
104
  moduleFile.startsWith('support/fixtures/') ||
@@ -117,7 +122,7 @@ export class ManifestModuleUtil {
117
122
  return 'compile';
118
123
  } else if (moduleFile.startsWith('support/test/') || moduleFile.startsWith('test/')) {
119
124
  return 'test';
120
- } else if (moduleFile.startsWith('doc/') || moduleFile === 'DOC.ts') {
125
+ } else if (moduleFile.startsWith('doc/') || /^DOC[.]tsx?$/.test(moduleFile)) {
121
126
  return 'doc';
122
127
  } else {
123
128
  return;
@@ -149,7 +154,7 @@ export class ManifestModuleUtil {
149
154
  case 'support': return key;
150
155
  default: return '$other';
151
156
  }
152
- } else if (moduleFile === 'DOC.ts') {
157
+ } else if (/^DOC[.]tsx?$/.test(moduleFile)) {
153
158
  return 'doc';
154
159
  } else if (INDEX_FILES.has(moduleFile)) {
155
160
  return '$index';
@@ -210,4 +215,18 @@ export class ManifestModuleUtil {
210
215
  const modules = await Promise.all(sorted.map(x => this.describeModule(ctx, x)));
211
216
  return Object.fromEntries(modules.map(m => [m.name, m]));
212
217
  }
218
+
219
+ /**
220
+ * Get the output file name for a given input
221
+ */
222
+ static sourceToOutputExt(inputFile: string): string {
223
+ return this.#sourceToExtension(inputFile, '.js');
224
+ }
225
+
226
+ /**
227
+ * Get the file without an extension
228
+ */
229
+ static sourceToBlankExt(inputFile: string): string {
230
+ return this.#sourceToExtension(inputFile, '');
231
+ }
213
232
  }