depflow 3.0.0-dev.10 → 3.0.0-dev.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (175) hide show
  1. package/README.md +513 -117
  2. package/dist/builder/Builder.d.ts +279 -0
  3. package/dist/builder/Builder.js +391 -0
  4. package/dist/builder/Builder.js.map +1 -0
  5. package/dist/cli/Actions.d.ts +187 -0
  6. package/dist/cli/Actions.js +793 -0
  7. package/dist/cli/Actions.js.map +1 -0
  8. package/dist/cli/CLI.d.ts +170 -0
  9. package/dist/cli/CLI.js +231 -0
  10. package/dist/cli/CLI.js.map +1 -0
  11. package/dist/cli/DepflowCLI.d.ts +62 -0
  12. package/dist/cli/DepflowCLI.js +229 -0
  13. package/dist/cli/DepflowCLI.js.map +1 -0
  14. package/dist/cli/Flags.d.ts +106 -0
  15. package/dist/cli/Flags.js +125 -0
  16. package/dist/cli/Flags.js.map +1 -0
  17. package/dist/cli/bin.js +63 -0
  18. package/dist/cli/bin.js.map +1 -0
  19. package/dist/config/Config.d.ts +690 -0
  20. package/dist/config/Config.js +45 -0
  21. package/dist/config/Config.js.map +1 -0
  22. package/dist/config/ImportMap.d.ts +60 -0
  23. package/dist/config/ImportMap.js +66 -0
  24. package/dist/config/ImportMap.js.map +1 -0
  25. package/dist/config/JsonSchema.d.ts +12 -0
  26. package/dist/config/JsonSchema.js +26 -0
  27. package/dist/config/JsonSchema.js.map +1 -0
  28. package/dist/config/Settings.d.ts +201 -0
  29. package/dist/config/Settings.js +191 -0
  30. package/dist/config/Settings.js.map +1 -0
  31. package/dist/config/TSConfig.d.ts +73 -0
  32. package/dist/config/TSConfig.js +73 -0
  33. package/dist/config/TSConfig.js.map +1 -0
  34. package/dist/config/codecs/JsonCodec.d.ts +30 -0
  35. package/dist/config/codecs/JsonCodec.js +31 -0
  36. package/dist/config/codecs/JsonCodec.js.map +1 -0
  37. package/dist/config/codecs/YamlCodec.d.ts +62 -0
  38. package/dist/config/codecs/YamlCodec.js +89 -0
  39. package/dist/config/codecs/YamlCodec.js.map +1 -0
  40. package/dist/dependency/DepUtils.d.ts +78 -0
  41. package/dist/dependency/DepUtils.js +122 -0
  42. package/dist/dependency/DepUtils.js.map +1 -0
  43. package/dist/dependency/Dependency.d.ts +81 -0
  44. package/dist/dependency/Dependency.js +71 -0
  45. package/dist/dependency/Dependency.js.map +1 -0
  46. package/dist/dependency/Git.d.ts +75 -0
  47. package/dist/dependency/Git.js +97 -0
  48. package/dist/dependency/Git.js.map +1 -0
  49. package/dist/dependency/GitDependency.d.ts +30 -0
  50. package/dist/dependency/GitDependency.js +79 -0
  51. package/dist/dependency/GitDependency.js.map +1 -0
  52. package/dist/dependency/NpmDependency.d.ts +27 -0
  53. package/dist/dependency/NpmDependency.js +91 -0
  54. package/dist/dependency/NpmDependency.js.map +1 -0
  55. package/{build/support/PathResolver → dist/resolve}/AliasCompiler.d.ts +18 -5
  56. package/{build/support/PathResolver → dist/resolve}/AliasCompiler.js +31 -9
  57. package/dist/resolve/AliasCompiler.js.map +1 -0
  58. package/{build/support/PathResolver → dist/resolve}/PathResolver.d.ts +25 -8
  59. package/dist/resolve/PathResolver.js +133 -0
  60. package/dist/resolve/PathResolver.js.map +1 -0
  61. package/dist/resolve/PathRewriter.d.ts +24 -0
  62. package/{build/support/PathResolver → dist/resolve}/PathRewriter.js +21 -11
  63. package/dist/resolve/PathRewriter.js.map +1 -0
  64. package/{build → dist}/schema/Config/Builder.d.ts +114 -49
  65. package/dist/schema/Config/Builder.js +78 -0
  66. package/dist/schema/Config/Builder.js.map +1 -0
  67. package/{build → dist}/schema/Config/Config.d.ts +169 -78
  68. package/dist/schema/Config/Config.js +62 -0
  69. package/dist/schema/Config/Config.js.map +1 -0
  70. package/{build → dist}/schema/Config/Dependency.d.ts +219 -89
  71. package/dist/schema/Config/Dependency.js +80 -0
  72. package/dist/schema/Config/Dependency.js.map +1 -0
  73. package/{build → dist}/schema/Config/Extractor.d.ts +41 -17
  74. package/dist/schema/Config/Extractor.js +43 -0
  75. package/dist/schema/Config/Extractor.js.map +1 -0
  76. package/{build → dist}/schema/Config/Resolver.d.ts +25 -8
  77. package/dist/schema/Config/Resolver.js +43 -0
  78. package/dist/schema/Config/Resolver.js.map +1 -0
  79. package/{build → dist}/schema/Config/Transform.d.ts +22 -5
  80. package/dist/schema/Config/Transform.js +51 -0
  81. package/dist/schema/Config/Transform.js.map +1 -0
  82. package/dist/schema/Defaults.d.ts +20 -0
  83. package/dist/schema/Defaults.js +24 -0
  84. package/dist/schema/Defaults.js.map +1 -0
  85. package/dist/schema/ImportMap.d.ts +30 -0
  86. package/dist/schema/ImportMap.js +28 -0
  87. package/dist/schema/ImportMap.js.map +1 -0
  88. package/{build → dist}/schema/TSConfig.d.ts +23 -9
  89. package/dist/schema/TSConfig.js +39 -0
  90. package/dist/schema/TSConfig.js.map +1 -0
  91. package/{build → dist}/schema/schema.d.ts +11 -2
  92. package/{build → dist}/schema/schema.js +11 -2
  93. package/dist/schema/schema.js.map +1 -0
  94. package/dist/task/Command.d.ts +287 -0
  95. package/dist/task/Command.js +404 -0
  96. package/dist/task/Command.js.map +1 -0
  97. package/dist/task/Group.d.ts +15 -0
  98. package/dist/task/Group.js +29 -0
  99. package/dist/task/Group.js.map +1 -0
  100. package/dist/task/OutputPolicy.d.ts +262 -0
  101. package/dist/task/OutputPolicy.js +364 -0
  102. package/dist/task/OutputPolicy.js.map +1 -0
  103. package/dist/task/Task.d.ts +210 -0
  104. package/dist/task/Task.js +312 -0
  105. package/dist/task/Task.js.map +1 -0
  106. package/package.json +14 -10
  107. package/.gitignore +0 -7
  108. package/build/cli/DepFLowCLI.d.ts +0 -16
  109. package/build/cli/DepFLowCLI.js +0 -254
  110. package/build/cli/DepFLowCLI.js.map +0 -1
  111. package/build/cli/bin.js +0 -38
  112. package/build/cli/bin.js.map +0 -1
  113. package/build/config/Config.d.ts +0 -28
  114. package/build/config/Config.js +0 -46
  115. package/build/config/Config.js.map +0 -1
  116. package/build/config/ImportMap.d.ts +0 -51
  117. package/build/config/ImportMap.js +0 -97
  118. package/build/config/ImportMap.js.map +0 -1
  119. package/build/config/TSConfig.d.ts +0 -54
  120. package/build/config/TSConfig.js +0 -104
  121. package/build/config/TSConfig.js.map +0 -1
  122. package/build/schema/Config/Builder.js +0 -48
  123. package/build/schema/Config/Builder.js.map +0 -1
  124. package/build/schema/Config/Config.js +0 -20
  125. package/build/schema/Config/Config.js.map +0 -1
  126. package/build/schema/Config/Dependency.js +0 -25
  127. package/build/schema/Config/Dependency.js.map +0 -1
  128. package/build/schema/Config/Extractor.js +0 -25
  129. package/build/schema/Config/Extractor.js.map +0 -1
  130. package/build/schema/Config/Resolver.js +0 -25
  131. package/build/schema/Config/Resolver.js.map +0 -1
  132. package/build/schema/Config/Transform.js +0 -27
  133. package/build/schema/Config/Transform.js.map +0 -1
  134. package/build/schema/ImportMap.d.ts +0 -22
  135. package/build/schema/ImportMap.js +0 -12
  136. package/build/schema/ImportMap.js.map +0 -1
  137. package/build/schema/TSConfig.js +0 -19
  138. package/build/schema/TSConfig.js.map +0 -1
  139. package/build/schema/schema.js.map +0 -1
  140. package/build/support/Builder/Builder.d.ts +0 -46
  141. package/build/support/Builder/Builder.js +0 -116
  142. package/build/support/Builder/Builder.js.map +0 -1
  143. package/build/support/Dependency/Dependency.d.ts +0 -38
  144. package/build/support/Dependency/Dependency.js +0 -14
  145. package/build/support/Dependency/Dependency.js.map +0 -1
  146. package/build/support/Dependency/GitDependency.d.ts +0 -20
  147. package/build/support/Dependency/GitDependency.js +0 -67
  148. package/build/support/Dependency/GitDependency.js.map +0 -1
  149. package/build/support/Dependency/NpmDependency.d.ts +0 -18
  150. package/build/support/Dependency/NpmDependency.js +0 -65
  151. package/build/support/Dependency/NpmDependency.js.map +0 -1
  152. package/build/support/Git.d.ts +0 -53
  153. package/build/support/Git.js +0 -86
  154. package/build/support/Git.js.map +0 -1
  155. package/build/support/PathResolver/AliasCompiler.js.map +0 -1
  156. package/build/support/PathResolver/PathResolver.js +0 -105
  157. package/build/support/PathResolver/PathResolver.js.map +0 -1
  158. package/build/support/PathResolver/PathRewriter.d.ts +0 -18
  159. package/build/support/PathResolver/PathRewriter.js.map +0 -1
  160. package/build/support/PathResolver/Utils.d.ts +0 -36
  161. package/build/support/PathResolver/Utils.js +0 -45
  162. package/build/support/PathResolver/Utils.js.map +0 -1
  163. package/build/support/Task/Command.d.ts +0 -49
  164. package/build/support/Task/Command.js +0 -100
  165. package/build/support/Task/Command.js.map +0 -1
  166. package/build/support/Task/Task.d.ts +0 -84
  167. package/build/support/Task/Task.js +0 -145
  168. package/build/support/Task/Task.js.map +0 -1
  169. package/build/support/Utils.d.ts +0 -40
  170. package/build/support/Utils.js +0 -138
  171. package/build/support/Utils.js.map +0 -1
  172. package/build/support/Validator.d.ts +0 -22
  173. package/build/support/Validator.js +0 -28
  174. package/build/support/Validator.js.map +0 -1
  175. /package/{build → dist}/cli/bin.d.ts +0 -0
@@ -1,7 +1,13 @@
1
+ /**
2
+ * @author NetFeez <netfeez.dev@gmail.com>.
3
+ * @description Compiles resolver entries from the configuration into absolute compiled aliases.
4
+ * @license Apache-2.0
5
+ */
1
6
  import path from 'node:path';
2
- import Utils from './Utils.js';
3
7
  export class AliasCompiler {
4
8
  projectRoot;
9
+ /** Matches the optional wildcard suffix of an alias or target (`/*` or `/`). */
10
+ static WILDCARD_SUFFIX_REGEX = /\/\*?$/;
5
11
  constructor(projectRoot) {
6
12
  this.projectRoot = projectRoot;
7
13
  }
@@ -9,7 +15,7 @@ export class AliasCompiler {
9
15
  * Compiles alias configurations from the provided config object into a structured format for path resolution.
10
16
  * It processes both regular and wildcard aliases, resolving local paths to absolute paths based on the project root.
11
17
  * The resulting compiled aliases include information about the alias name, whether it's a wildcard, and its target paths for local and CDN usage.
12
- * @param config The configuration object containing dependencies with resolver entries to compile into aliases.
18
+ * @param config - The configuration object containing dependencies with resolver entries to compile into aliases.
13
19
  * @returns An array of compiled alias objects ready for use in path resolution.
14
20
  */
15
21
  compile(config) {
@@ -31,32 +37,48 @@ export class AliasCompiler {
31
37
  * Resolves an array of resolver entries into compiled alias objects, handling both string and object target formats.
32
38
  * It determines if each alias is a wildcard and resolves local paths to absolute paths based on the project root.
33
39
  * The method also extracts type and CDN targets if provided in the resolver entry.
34
- * @param resolver An array of resolver entries to process into compiled aliases.
40
+ * @param resolver - An array of resolver entries to process into compiled aliases.
35
41
  * @returns An array of compiled alias objects derived from the resolver entries.
36
42
  */
37
43
  resolve(resolver) {
38
44
  const result = [];
39
45
  for (const [crudeAlias, target] of Object.entries(resolver)) {
40
- const isWildcard = Utils.isWildcard(crudeAlias);
41
- const alias = Utils.removeWildcardSuffix(crudeAlias);
46
+ const isWildcard = AliasCompiler.isWildcard(crudeAlias);
47
+ const alias = AliasCompiler.removeWildcardSuffix(crudeAlias);
42
48
  const rawLocal = typeof target === 'string' ? target : target.local;
43
49
  const localTarget = path.isAbsolute(rawLocal)
44
- ? Utils.removeWildcardSuffix(rawLocal)
45
- : path.resolve(this.projectRoot, Utils.removeWildcardSuffix(rawLocal));
50
+ ? AliasCompiler.removeWildcardSuffix(rawLocal)
51
+ : path.resolve(this.projectRoot, AliasCompiler.removeWildcardSuffix(rawLocal));
46
52
  let cdnTarget;
47
53
  let typeTarget;
48
54
  if (typeof target === 'object') {
49
55
  if (target.type) {
50
- typeTarget = Utils.removeWildcardSuffix(target.type);
56
+ typeTarget = AliasCompiler.removeWildcardSuffix(target.type);
51
57
  }
52
58
  if (target.cdn) {
53
- cdnTarget = Utils.removeWildcardSuffix(target.cdn);
59
+ cdnTarget = AliasCompiler.removeWildcardSuffix(target.cdn);
54
60
  }
55
61
  }
56
62
  result.push({ alias, isWildcard, targets: { local: localTarget, type: typeTarget, cdn: cdnTarget } });
57
63
  }
58
64
  return result;
59
65
  }
66
+ /**
67
+ * Checks whether an alias string carries the wildcard suffix (`/*` or `/`) that turns it into a mapping.
68
+ * @param alias - The alias string to check.
69
+ * @returns True if the alias ends with a wildcard suffix, false otherwise.
70
+ */
71
+ static isWildcard(alias) {
72
+ return this.WILDCARD_SUFFIX_REGEX.test(alias);
73
+ }
74
+ /**
75
+ * Strips the wildcard suffix from an alias or target string, leaving its base form.
76
+ * @param pathStr - The string to normalize (e.g., `components/*` or `utils/`).
77
+ * @returns The string without its wildcard suffix (e.g., `components` or `utils`).
78
+ */
79
+ static removeWildcardSuffix(pathStr) {
80
+ return pathStr.replace(this.WILDCARD_SUFFIX_REGEX, '');
81
+ }
60
82
  }
61
83
  export default AliasCompiler;
62
84
  //# sourceMappingURL=AliasCompiler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AliasCompiler.js","sourceRoot":"","sources":["../../src/resolve/AliasCompiler.ts"],"names":[],"mappings":"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"}
@@ -1,40 +1,57 @@
1
1
  import { Logger } from "@netfeez/vterm";
2
2
  import PathRewriter from './PathRewriter.js';
3
3
  import AliasCompiler from './AliasCompiler.js';
4
- import Config from '../../config/Config.js';
4
+ import schema from '../schema/schema.js';
5
5
  export declare class PathResolver {
6
- readonly config: Config.Config;
7
6
  readonly options: PathResolver.Options;
8
- static readonly PROJECT_ROOT: string;
7
+ /** The extensions of the built files the resolver owns, in any mode. */
9
8
  static readonly EXTENSIONS: string[];
10
9
  protected readonly logger: Logger;
11
10
  protected readonly rewriter: PathRewriter;
12
11
  protected readonly outDir: string;
13
12
  readonly aliases: AliasCompiler.CompiledAlias[];
14
- constructor(config: Config.Config, options?: PathResolver.Options);
13
+ constructor(data: schema.Config, projectRoot: string, options?: PathResolver.Options);
14
+ /**
15
+ * The pattern that matches the built files the resolver owns, derived from the extensions it does.
16
+ * @returns The glob pattern of the files to rewrite.
17
+ **/
18
+ private static get filter();
15
19
  /**
16
20
  * Resolves and rewrites paths in built files based on the provided mode (local or CDN).
17
21
  * It processes all files in the output directory, rewriting import paths according to the configured aliases.
18
- * @param mode The resolution mode ('local' or 'cdn') to determine which target paths to use.
22
+ * @param mode - The resolution mode ('local' or 'cdn') to determine which target paths to use.
23
+ * @throws { Error } When any of the files could not be rewritten, reporting all of them.
24
+ *
25
+ * @remarks A file that cannot be rewritten is not a file that was left alone: a build that reports
26
+ * success while some of its files still point at the source tree is a build that cannot be
27
+ * deployed, so the failure travels up to whoever asked for the resolution.
19
28
  */
20
29
  rewritePaths(mode: PathResolver.Mode): Promise<void>;
21
30
  /**
22
31
  * Processes a single file, rewriting import paths based on the configured aliases and the specified mode (local or CDN).
23
32
  * It reads the file content, applies the path rewriting logic, and writes the updated content back to the file system if any changes were made.
24
- * @param file The path of the file to process.
25
- * @param mode The resolution mode ('local' or 'cdn') to determine which target paths to use for rewriting.
33
+ * @param file - The path of the file to process.
34
+ * @param mode - The resolution mode ('local' or 'cdn') to determine which target paths to use for rewriting.
26
35
  * @returns A boolean indicating whether the file was modified (true if rewritten, false if no changes were made).
36
+ * @throws { Error } When the file cannot be read, rewritten or written.
27
37
  */
28
38
  protected processFile(file: string, mode: PathResolver.Mode): Promise<boolean>;
29
39
  /**
30
40
  * Watches the output directory for changes and automatically rewrites paths in modified files based on the configured aliases and specified mode (local or CDN).
31
41
  * It sets up a file system watcher that listens for changes in the output directory, and when a relevant file is modified, it triggers the path rewriting process for that file.
32
42
  * The method includes debouncing to prevent excessive processing during rapid file changes, ensuring efficient handling of updates while maintaining responsiveness.
33
- * @param mode The resolution mode ('local' or 'cdn') to determine which target paths to use for rewriting when changes are detected.
43
+ * @param mode - The resolution mode ('local' or 'cdn') to determine which target paths to use for rewriting when changes are detected.
34
44
  * @returns A promise that resolves when the watcher is set up and running, allowing the application to continue monitoring for changes indefinitely until manually stopped.
35
45
  * @throws Will throw an error if there is an issue setting up the file system watcher or processing files, which can be caught by the caller to handle it appropriately.
36
46
  */
37
47
  watch(mode: PathResolver.Mode): Promise<void>;
48
+ /**
49
+ * Debounces a function so it only executes after the specified delay has passed since the last invocation.
50
+ * @param fn - The function to debounce.
51
+ * @param delay - The number of milliseconds to wait before executing the function.
52
+ * @returns A debounced version of the function that delays its execution.
53
+ */
54
+ private static debounce;
38
55
  }
39
56
  export declare namespace PathResolver {
40
57
  type Mode = 'local' | 'cdn';
@@ -0,0 +1,133 @@
1
+ /**
2
+ * @author NetFeez <netfeez.dev@gmail.com>.
3
+ * @description Path resolution with Local/CDN support and dual path fixing.
4
+ * @license Apache-2.0
5
+ */
6
+ import FS, { promises as FSP } from 'node:fs';
7
+ import { Async, File, Path } from '@netfeez/common-node';
8
+ import { Logger } from "@netfeez/vterm";
9
+ import PathRewriter from './PathRewriter.js';
10
+ import AliasCompiler from './AliasCompiler.js';
11
+ export class PathResolver {
12
+ options;
13
+ /** The extensions of the built files the resolver owns, in any mode. */
14
+ static EXTENSIONS = ['.js', '.ts', '.jsx', '.tsx', '.cjs', '.mjs'];
15
+ logger;
16
+ rewriter;
17
+ outDir;
18
+ aliases;
19
+ constructor(data, projectRoot, options = {}) {
20
+ this.options = options;
21
+ this.logger = options.logger || new Logger({ name: 'PATH-RW' });
22
+ const outDir = data.outDir;
23
+ this.outDir = !Path.isAbsolute(outDir)
24
+ ? Path.resolve(projectRoot, outDir)
25
+ : outDir;
26
+ this.aliases = new AliasCompiler(projectRoot).compile(data);
27
+ this.rewriter = new PathRewriter(this.aliases);
28
+ }
29
+ /**
30
+ * The pattern that matches the built files the resolver owns, derived from the extensions it does.
31
+ * @returns The glob pattern of the files to rewrite.
32
+ **/
33
+ static get filter() {
34
+ return `**/*{${PathResolver.EXTENSIONS.map(extension => extension.slice(1)).join(',')}}`;
35
+ }
36
+ /**
37
+ * Resolves and rewrites paths in built files based on the provided mode (local or CDN).
38
+ * It processes all files in the output directory, rewriting import paths according to the configured aliases.
39
+ * @param mode - The resolution mode ('local' or 'cdn') to determine which target paths to use.
40
+ * @throws { Error } When any of the files could not be rewritten, reporting all of them.
41
+ *
42
+ * @remarks A file that cannot be rewritten is not a file that was left alone: a build that reports
43
+ * success while some of its files still point at the source tree is a build that cannot be
44
+ * deployed, so the failure travels up to whoever asked for the resolution.
45
+ */
46
+ async rewritePaths(mode) {
47
+ this.logger.log(`&C2Starting path resolver in &C3${mode} &C2mode for ${this.outDir}...`);
48
+ if (!await File.exists(this.outDir))
49
+ return void this.logger.warn(`Directory &C4${this.outDir}&R not found.`);
50
+ const files = await File.glob(PathResolver.filter, { cwd: this.outDir, absolute: false });
51
+ let rewrittenCount = 0;
52
+ const failed = [];
53
+ const limiter = Async.currencyLimiter(16);
54
+ await Promise.all(files.map((file) => limiter(async () => {
55
+ try {
56
+ if (await this.processFile(Path.join(this.outDir, file), mode))
57
+ rewrittenCount += 1;
58
+ }
59
+ catch (error) {
60
+ failed.push(`${file}: ${error instanceof Error ? error.message : String(error)}`);
61
+ }
62
+ })));
63
+ if (failed.length > 0)
64
+ throw new Error(`Path resolver failed to rewrite ${failed.length} of ${files.length} file(s):\n${failed.join('\n')}`);
65
+ this.logger.log(`&C2Path aliases resolved in &C3${rewrittenCount} &C2files.`);
66
+ }
67
+ /**
68
+ * Processes a single file, rewriting import paths based on the configured aliases and the specified mode (local or CDN).
69
+ * It reads the file content, applies the path rewriting logic, and writes the updated content back to the file system if any changes were made.
70
+ * @param file - The path of the file to process.
71
+ * @param mode - The resolution mode ('local' or 'cdn') to determine which target paths to use for rewriting.
72
+ * @returns A boolean indicating whether the file was modified (true if rewritten, false if no changes were made).
73
+ * @throws { Error } When the file cannot be read, rewritten or written.
74
+ */
75
+ async processFile(file, mode) {
76
+ const content = await FSP.readFile(file, 'utf8');
77
+ const newContent = this.rewriter.rewrite(content, file, mode);
78
+ if (content === newContent)
79
+ return false;
80
+ await FSP.writeFile(file, newContent, 'utf8');
81
+ return true;
82
+ }
83
+ /**
84
+ * Watches the output directory for changes and automatically rewrites paths in modified files based on the configured aliases and specified mode (local or CDN).
85
+ * It sets up a file system watcher that listens for changes in the output directory, and when a relevant file is modified, it triggers the path rewriting process for that file.
86
+ * The method includes debouncing to prevent excessive processing during rapid file changes, ensuring efficient handling of updates while maintaining responsiveness.
87
+ * @param mode - The resolution mode ('local' or 'cdn') to determine which target paths to use for rewriting when changes are detected.
88
+ * @returns A promise that resolves when the watcher is set up and running, allowing the application to continue monitoring for changes indefinitely until manually stopped.
89
+ * @throws Will throw an error if there is an issue setting up the file system watcher or processing files, which can be caught by the caller to handle it appropriately.
90
+ */
91
+ async watch(mode) {
92
+ await this.rewritePaths(mode);
93
+ this.logger.log(`&C2Watching for changes in &C4${this.outDir}...`);
94
+ const debouncedProcessor = PathResolver.debounce(async (fullPath, filename) => {
95
+ try {
96
+ if (await this.processFile(fullPath, mode)) {
97
+ this.logger.log(`&C2File &C4${filename}&C2 updated.`);
98
+ }
99
+ }
100
+ catch (error) {
101
+ this.logger.error(`Failed to process file &C4${filename}&C7: &C1${error instanceof Error ? error.message : String(error)}`);
102
+ }
103
+ }, 300);
104
+ FS.watch(this.outDir, { recursive: true }, (eventType, filename) => {
105
+ if (!filename)
106
+ return;
107
+ const isTargetExtension = PathResolver.EXTENSIONS.some(ext => filename.endsWith(ext));
108
+ if (!isTargetExtension)
109
+ return;
110
+ const fullPath = Path.join(this.outDir, filename);
111
+ debouncedProcessor(fullPath, filename);
112
+ });
113
+ }
114
+ /**
115
+ * Debounces a function so it only executes after the specified delay has passed since the last invocation.
116
+ * @param fn - The function to debounce.
117
+ * @param delay - The number of milliseconds to wait before executing the function.
118
+ * @returns A debounced version of the function that delays its execution.
119
+ */
120
+ static debounce(fn, delay) {
121
+ let timeoutId = null;
122
+ return function (...args) {
123
+ if (timeoutId)
124
+ clearTimeout(timeoutId);
125
+ timeoutId = setTimeout(() => {
126
+ fn.apply(this, args);
127
+ timeoutId = null;
128
+ }, delay);
129
+ };
130
+ }
131
+ }
132
+ export default PathResolver;
133
+ //# sourceMappingURL=PathResolver.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PathResolver.js","sourceRoot":"","sources":["../../src/resolve/PathResolver.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,24 @@
1
+ import AliasCompiler from "./AliasCompiler.js";
2
+ export declare class PathRewriter {
3
+ private readonly aliases;
4
+ static readonly IMPORT_REGEX: RegExp;
5
+ constructor(aliases: AliasCompiler.CompiledAlias[]);
6
+ /**
7
+ * Rewrites import paths in the given content based on the configured aliases.
8
+ * It detects import statements and replaces alias paths with their resolved targets.
9
+ * @param content - The file content to rewrite.
10
+ * @param filePath - The path of the file being processed (used for relative path calculations).
11
+ * @param mode - The resolution mode ('local' or 'cdn') to determine which target to use.
12
+ * @returns The rewritten content with resolved import paths.
13
+ */
14
+ rewrite(content: string, filePath: string, mode: 'local' | 'cdn'): string;
15
+ /**
16
+ * The specifier of an import, which is never a file system path: the separator it is written with
17
+ * is the one of the module system, not the one of the machine that wrote it.
18
+ * @param target - The target of the import, as the file system spells it.
19
+ * @returns The target written with the separator an import is written with.
20
+ **/
21
+ protected static posix(target: string): string;
22
+ }
23
+ export declare namespace PathRewriter { }
24
+ export default PathRewriter;
@@ -1,19 +1,21 @@
1
+ /**
2
+ * @author NetFeez <netfeez.dev@gmail.com>.
3
+ * @description Rewrites import statements in file content using compiled aliases.
4
+ * @license Apache-2.0
5
+ */
1
6
  import PATH from "node:path";
2
- import { Path } from "@netfeez/common-node";
3
7
  export class PathRewriter {
4
8
  aliases;
5
- projectRoot;
6
9
  static IMPORT_REGEX = /(from\s+['"])([^'"]+)(['"])/g;
7
- constructor(aliases, projectRoot) {
10
+ constructor(aliases) {
8
11
  this.aliases = aliases;
9
- this.projectRoot = projectRoot;
10
12
  }
11
13
  /**
12
14
  * Rewrites import paths in the given content based on the configured aliases.
13
15
  * It detects import statements and replaces alias paths with their resolved targets.
14
- * @param content The file content to rewrite.
15
- * @param filePath The path of the file being processed (used for relative path calculations).
16
- * @param mode The resolution mode ('local' or 'cdn') to determine which target to use.
16
+ * @param content - The file content to rewrite.
17
+ * @param filePath - The path of the file being processed (used for relative path calculations).
18
+ * @param mode - The resolution mode ('local' or 'cdn') to determine which target to use.
17
19
  * @returns The rewritten content with resolved import paths.
18
20
  */
19
21
  rewrite(content, filePath, mode) {
@@ -36,12 +38,20 @@ export class PathRewriter {
36
38
  if (isCDN)
37
39
  return `${prefix}${resolvedPath}${suffix}`;
38
40
  const currentFileDir = PATH.dirname(filePath);
39
- let relativeTarget = PATH.relative(currentFileDir, resolvedPath);
40
- if (!relativeTarget.startsWith('.'))
41
- relativeTarget = `./${relativeTarget}`;
42
- return `${prefix}${Path.normalize(relativeTarget)}${suffix}`;
41
+ const relative = PATH.relative(currentFileDir, resolvedPath);
42
+ const relativeTarget = relative.startsWith('.') ? relative : `./${relative}`;
43
+ return `${prefix}${PathRewriter.posix(relativeTarget)}${suffix}`;
43
44
  });
44
45
  }
46
+ /**
47
+ * The specifier of an import, which is never a file system path: the separator it is written with
48
+ * is the one of the module system, not the one of the machine that wrote it.
49
+ * @param target - The target of the import, as the file system spells it.
50
+ * @returns The target written with the separator an import is written with.
51
+ **/
52
+ static posix(target) {
53
+ return target.split(PATH.sep).join('/');
54
+ }
45
55
  }
46
56
  export default PathRewriter;
47
57
  //# sourceMappingURL=PathRewriter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PathRewriter.js","sourceRoot":"","sources":["../../src/resolve/PathRewriter.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,IAAI,MAAM,WAAW,CAAC;AAI7B,MAAM,OAAO,YAAY;IAGA,OAAO;IAFrB,MAAM,CAAU,YAAY,GAAG,8BAA8B,CAAC;IACrE,YACqB,OAAsC;uBAAtC,OAAO;IACzB,CAAC;IACJ;;;;;;;OAOG;IACI,OAAO,CAAC,OAAe,EAAE,QAAgB,EAAE,IAAqB;QACnE,OAAO,OAAO,CAAC,OAAO,CAAC,YAAY,CAAC,YAAY,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,EAAE;YACpF,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,UAAU,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,UAAU,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC;YAEtH,IAAI,CAAC,QAAQ;gBAAE,OAAO,KAAK,CAAC;YAE5B,MAAM,KAAK,GAAG,IAAI,KAAK,KAAK,IAAI,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC;YACrD,MAAM,UAAU,GAAG,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,KAAK,CAAC;YAE1E,IAAI,YAAoB,CAAC;YACzB,IAAI,QAAQ,CAAC,UAAU,EAAE,CAAC;gBACtB,MAAM,OAAO,GAAG,UAAU,CAAC,SAAS,CAAC,QAAQ,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;gBAChE,YAAY,GAAG,KAAK;oBAChB,CAAC,CAAC,GAAG,UAAU,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,IAAI,OAAO,EAAE;oBAC/C,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;YACzC,CAAC;iBAAM,CAAC;gBACJ,YAAY,GAAG,UAAU,CAAC;YAC9B,CAAC;YAED,IAAI,KAAK;gBAAE,OAAO,GAAG,MAAM,GAAG,YAAY,GAAG,MAAM,EAAE,CAAC;YAEtD,MAAM,cAAc,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;YAC9C,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,cAAc,EAAE,YAAY,CAAC,CAAC;YAC7D,MAAM,cAAc,GAAG,QAAQ,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,QAAQ,EAAE,CAAC;YAE7E,OAAO,GAAG,MAAM,GAAG,YAAY,CAAC,KAAK,CAAC,cAAc,CAAC,GAAG,MAAM,EAAE,CAAC;QACrE,CAAC,CAAC,CAAC;IACP,CAAC;IACD;;;;;QAKI;IACM,MAAM,CAAC,KAAK,CAAC,MAAc;QACjC,OAAO,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC5C,CAAC;CACJ;AAED,eAAe,YAAY,CAAC"}