@oazmi/superbuild 0.1.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.
Files changed (118) hide show
  1. package/esm/_dnt.shims.d.ts +2 -0
  2. package/esm/_dnt.shims.d.ts.map +1 -0
  3. package/esm/_dnt.shims.js +57 -0
  4. package/esm/deps/jsr.io/@oazmi/esbuild-types/0.28.0/src/mod.d.ts +598 -0
  5. package/esm/deps/jsr.io/@oazmi/esbuild-types/0.28.0/src/mod.d.ts.map +1 -0
  6. package/esm/deps/jsr.io/@oazmi/esbuild-types/0.28.0/src/mod.js +1 -0
  7. package/esm/deps/jsr.io/@oazmi/kitchensink/0.10.0/src/alias.d.ts +617 -0
  8. package/esm/deps/jsr.io/@oazmi/kitchensink/0.10.0/src/alias.d.ts.map +1 -0
  9. package/esm/deps/jsr.io/@oazmi/kitchensink/0.10.0/src/alias.js +671 -0
  10. package/esm/deps/jsr.io/@oazmi/kitchensink/0.10.0/src/array1d.d.ts +487 -0
  11. package/esm/deps/jsr.io/@oazmi/kitchensink/0.10.0/src/array1d.d.ts.map +1 -0
  12. package/esm/deps/jsr.io/@oazmi/kitchensink/0.10.0/src/array1d.js +536 -0
  13. package/esm/deps/jsr.io/@oazmi/kitchensink/0.10.0/src/array2d.d.ts +266 -0
  14. package/esm/deps/jsr.io/@oazmi/kitchensink/0.10.0/src/array2d.d.ts.map +1 -0
  15. package/esm/deps/jsr.io/@oazmi/kitchensink/0.10.0/src/array2d.js +318 -0
  16. package/esm/deps/jsr.io/@oazmi/kitchensink/0.10.0/src/binder.d.ts +368 -0
  17. package/esm/deps/jsr.io/@oazmi/kitchensink/0.10.0/src/binder.d.ts.map +1 -0
  18. package/esm/deps/jsr.io/@oazmi/kitchensink/0.10.0/src/binder.js +380 -0
  19. package/esm/deps/jsr.io/@oazmi/kitchensink/0.10.0/src/crossenv.d.ts +711 -0
  20. package/esm/deps/jsr.io/@oazmi/kitchensink/0.10.0/src/crossenv.d.ts.map +1 -0
  21. package/esm/deps/jsr.io/@oazmi/kitchensink/0.10.0/src/crossenv.js +1173 -0
  22. package/esm/deps/jsr.io/@oazmi/kitchensink/0.10.0/src/cryptoman.d.ts +171 -0
  23. package/esm/deps/jsr.io/@oazmi/kitchensink/0.10.0/src/cryptoman.d.ts.map +1 -0
  24. package/esm/deps/jsr.io/@oazmi/kitchensink/0.10.0/src/cryptoman.js +308 -0
  25. package/esm/deps/jsr.io/@oazmi/kitchensink/0.10.0/src/deps.d.ts +10 -0
  26. package/esm/deps/jsr.io/@oazmi/kitchensink/0.10.0/src/deps.d.ts.map +1 -0
  27. package/esm/deps/jsr.io/@oazmi/kitchensink/0.10.0/src/deps.js +10 -0
  28. package/esm/deps/jsr.io/@oazmi/kitchensink/0.10.0/src/eightpack.d.ts +168 -0
  29. package/esm/deps/jsr.io/@oazmi/kitchensink/0.10.0/src/eightpack.d.ts.map +1 -0
  30. package/esm/deps/jsr.io/@oazmi/kitchensink/0.10.0/src/eightpack.js +236 -0
  31. package/esm/deps/jsr.io/@oazmi/kitchensink/0.10.0/src/eightpack_varint.d.ts +90 -0
  32. package/esm/deps/jsr.io/@oazmi/kitchensink/0.10.0/src/eightpack_varint.d.ts.map +1 -0
  33. package/esm/deps/jsr.io/@oazmi/kitchensink/0.10.0/src/eightpack_varint.js +237 -0
  34. package/esm/deps/jsr.io/@oazmi/kitchensink/0.10.0/src/numericarray.d.ts +213 -0
  35. package/esm/deps/jsr.io/@oazmi/kitchensink/0.10.0/src/numericarray.d.ts.map +1 -0
  36. package/esm/deps/jsr.io/@oazmi/kitchensink/0.10.0/src/numericarray.js +363 -0
  37. package/esm/deps/jsr.io/@oazmi/kitchensink/0.10.0/src/numericmethods.d.ts +233 -0
  38. package/esm/deps/jsr.io/@oazmi/kitchensink/0.10.0/src/numericmethods.d.ts.map +1 -0
  39. package/esm/deps/jsr.io/@oazmi/kitchensink/0.10.0/src/numericmethods.js +256 -0
  40. package/esm/deps/jsr.io/@oazmi/kitchensink/0.10.0/src/pathman.d.ts +1436 -0
  41. package/esm/deps/jsr.io/@oazmi/kitchensink/0.10.0/src/pathman.d.ts.map +1 -0
  42. package/esm/deps/jsr.io/@oazmi/kitchensink/0.10.0/src/pathman.js +1730 -0
  43. package/esm/deps/jsr.io/@oazmi/kitchensink/0.10.0/src/promiseman.d.ts +647 -0
  44. package/esm/deps/jsr.io/@oazmi/kitchensink/0.10.0/src/promiseman.d.ts.map +1 -0
  45. package/esm/deps/jsr.io/@oazmi/kitchensink/0.10.0/src/promiseman.js +762 -0
  46. package/esm/deps/jsr.io/@oazmi/kitchensink/0.10.0/src/stringman.d.ts +538 -0
  47. package/esm/deps/jsr.io/@oazmi/kitchensink/0.10.0/src/stringman.d.ts.map +1 -0
  48. package/esm/deps/jsr.io/@oazmi/kitchensink/0.10.0/src/stringman.js +626 -0
  49. package/esm/deps/jsr.io/@oazmi/kitchensink/0.10.0/src/struct.d.ts +734 -0
  50. package/esm/deps/jsr.io/@oazmi/kitchensink/0.10.0/src/struct.d.ts.map +1 -0
  51. package/esm/deps/jsr.io/@oazmi/kitchensink/0.10.0/src/struct.js +764 -0
  52. package/esm/deps/jsr.io/@oazmi/kitchensink/0.10.0/src/typedbuffer.d.ts +137 -0
  53. package/esm/deps/jsr.io/@oazmi/kitchensink/0.10.0/src/typedbuffer.d.ts.map +1 -0
  54. package/esm/deps/jsr.io/@oazmi/kitchensink/0.10.0/src/typedbuffer.js +234 -0
  55. package/esm/deps/jsr.io/@oazmi/kitchensink/0.10.0/src/typedefs.d.ts +391 -0
  56. package/esm/deps/jsr.io/@oazmi/kitchensink/0.10.0/src/typedefs.d.ts.map +1 -0
  57. package/esm/deps/jsr.io/@oazmi/kitchensink/0.10.0/src/typedefs.js +8 -0
  58. package/esm/deps.d.ts +56 -0
  59. package/esm/deps.d.ts.map +1 -0
  60. package/esm/deps.js +37 -0
  61. package/esm/esbuild/metafile.d.ts +90 -0
  62. package/esm/esbuild/metafile.d.ts.map +1 -0
  63. package/esm/esbuild/metafile.js +275 -0
  64. package/esm/esbuild/native.d.ts +95 -0
  65. package/esm/esbuild/native.d.ts.map +1 -0
  66. package/esm/esbuild/native.js +127 -0
  67. package/esm/esbuild/outputfile.d.ts +86 -0
  68. package/esm/esbuild/outputfile.d.ts.map +1 -0
  69. package/esm/esbuild/outputfile.js +221 -0
  70. package/esm/esbuild/strongtypes.d.ts +90 -0
  71. package/esm/esbuild/strongtypes.d.ts.map +1 -0
  72. package/esm/esbuild/strongtypes.js +8 -0
  73. package/esm/esbuild/typedefs.d.ts +121 -0
  74. package/esm/esbuild/typedefs.d.ts.map +1 -0
  75. package/esm/esbuild/typedefs.js +55 -0
  76. package/esm/esbuild/weaktypes.d.ts +46 -0
  77. package/esm/esbuild/weaktypes.d.ts.map +1 -0
  78. package/esm/esbuild/weaktypes.js +8 -0
  79. package/esm/funcdefs.d.ts +89 -0
  80. package/esm/funcdefs.d.ts.map +1 -0
  81. package/esm/funcdefs.js +145 -0
  82. package/esm/mod.d.ts +4 -0
  83. package/esm/mod.d.ts.map +1 -0
  84. package/esm/mod.js +2 -0
  85. package/esm/package.json +3 -0
  86. package/esm/plugins/emissions_driver.d.ts +33 -0
  87. package/esm/plugins/emissions_driver.d.ts.map +1 -0
  88. package/esm/plugins/emissions_driver.js +260 -0
  89. package/esm/plugins/long_build.d.ts +138 -0
  90. package/esm/plugins/long_build.d.ts.map +1 -0
  91. package/esm/plugins/long_build.js +288 -0
  92. package/esm/plugins/native_replica.d.ts +48 -0
  93. package/esm/plugins/native_replica.d.ts.map +1 -0
  94. package/esm/plugins/native_replica.js +122 -0
  95. package/esm/super/build.d.ts +53 -0
  96. package/esm/super/build.d.ts.map +1 -0
  97. package/esm/super/build.js +39 -0
  98. package/esm/super/build_context.d.ts +83 -0
  99. package/esm/super/build_context.d.ts.map +1 -0
  100. package/esm/super/build_context.js +124 -0
  101. package/esm/super/mod.d.ts +12 -0
  102. package/esm/super/mod.d.ts.map +1 -0
  103. package/esm/super/mod.js +9 -0
  104. package/esm/super/plugin.d.ts +23 -0
  105. package/esm/super/plugin.d.ts.map +1 -0
  106. package/esm/super/plugin.js +31 -0
  107. package/esm/super/plugin_build.d.ts +38 -0
  108. package/esm/super/plugin_build.d.ts.map +1 -0
  109. package/esm/super/plugin_build.js +198 -0
  110. package/esm/super/typedefs.d.ts +323 -0
  111. package/esm/super/typedefs.d.ts.map +1 -0
  112. package/esm/super/typedefs.js +10 -0
  113. package/esm/typedefs.d.ts +21 -0
  114. package/esm/typedefs.d.ts.map +1 -0
  115. package/esm/typedefs.js +5 -0
  116. package/license.md +37 -0
  117. package/package.json +88 -0
  118. package/readme.md +181 -0
@@ -0,0 +1,138 @@
1
+ /** an internal super-build plugin that enables the inclusion of additional imports dynamically,
2
+ * as esbuild is transforming the loaded content.
3
+ *
4
+ * the reason why this plugin is called "long build" is because it hangs up at its loader stage and waits for the import requests to come in,
5
+ * until all known entities that had entered the `onResolve` stage have exited through at least one `onLoad` hook.
6
+ *
7
+ * @module
8
+ */
9
+ import type { EsbuildPartialMessage, EsbuildPlugin, EsbuildPluginSetup, OnResolveResult } from "../esbuild/strongtypes.js";
10
+ import type { ImportEntity } from "../super/typedefs.js";
11
+ import type { LoggerFunction } from "../typedefs.js";
12
+ export interface LongBuildControllerConfig {
13
+ /** enable internal logging for the {@link LongBuildController}, when {@link DEBUG.LOG} is enabled.
14
+ *
15
+ * @defaultValue {@link noopLogger}
16
+ */
17
+ debuggingLogs?: LoggerFunction;
18
+ }
19
+ /** the controller used for commanding the state of the "long build" plugin. */
20
+ export declare class LongBuildController {
21
+ /** the unique base filename that will be used by the {@link longBuildPluginSetup} plugin to insert its "long build" js file as an entry-point.
22
+ * the full filename format it will use will be: `${recursion_number}.(${uuid}).js`.
23
+ */
24
+ readonly uuid: string;
25
+ /** the unique filename(s) that will be used for the "long build" js files.
26
+ * it is a computed value that evaluates to `.(${uuid}).js`,
27
+ * and the actual filename that gets inserted/injected will also have a leading number, signifying the "build/recursion number".
28
+ *
29
+ * for instance, the entry-point long build js file will be named: `0.(${uuid}).js`,
30
+ * while the next recursive "long build" import within the `0.(${uuid}).js` file will be named `1.(${uuid}).js`,
31
+ * and so on (until a "long build" js file with zero external imports/includes is discovered, at which point we shall halt).
32
+ */
33
+ readonly baseFilename: string;
34
+ /** the name of the "long build dependency" file, as defined in {@link LONGBUILD.DEPS_FILE}.
35
+ *
36
+ * its value evaluates to `deps.(${uuid}).js`, and it is imported by each "long build step" js file as a dependency,
37
+ * in order to have a shared resource variable where all imports will get registered.
38
+ */
39
+ readonly depsFilename: string;
40
+ /** the namespace used by the {@link longBuildPlugin}.
41
+ * it is a computed value that evaluates to `oazmi-superbuild-long_build-plugin-${uuid}`.
42
+ */
43
+ readonly pluginNamespace: string;
44
+ /** the current build/recursion number. it starts with zero, and it is used for indicating the filename of the current "long build" file. */
45
+ readonly buildNumber: number;
46
+ /** the number of files in the esbuild build process that are currently in circulation.
47
+ *
48
+ * - everytime a new file hits the "long build" plugin's `onResolve` hook, this value gets incremented by one,
49
+ * since a "new file is currently in circulation".
50
+ * - whenever a file gets successfully loaded via some plugin's `onLoad` hook,
51
+ * the {@link SuperPluginBuild.onLoad} overload decrements this shared-state counter,
52
+ * since a "file that was in circulation has exited".
53
+ * - a caveat to look out for is the fact that if any plugin calls {@link SuperPluginBuild.resolve},
54
+ * this counter will get incremented again (double count),
55
+ * since the resolve request will go through our "long build" plugin's `onResolve` hook once again.
56
+ * to combat this double count, the {@link SuperPluginBuild.resolve} function decrements this counter whenever it gets called.
57
+ */
58
+ remainingFilesCounter: number;
59
+ /** esbuild caches the loaded result of an `onLoad` hook, based on the result of the `onResolve` hook's `result.path` and `result.namespace`
60
+ * (I don't know if esbuild also caches with respect to the `with` import attribute).
61
+ * but we don't want to count any cached paths towards {@link remainingFilesCounter}, since they won't be loaded again;
62
+ * which is why we need this hash-set to keep track of what has already been seen once.
63
+ */
64
+ protected encounteredPaths: Set<string>;
65
+ steps: Array<LongBuildStep>;
66
+ /** a logging function for internal debugging. it gets called only when {@link DEBUG.LOG} is enabled. */
67
+ log: LoggerFunction;
68
+ constructor(config?: LongBuildControllerConfig);
69
+ incrementBuild(): EsbuildPartialMessage[];
70
+ incrementFilesCounter(pathname?: string): void;
71
+ decrementFilesCounter(pathname?: string): void;
72
+ cacheResolvedResult(args: OnResolveResult): void;
73
+ /** this function does the inverse of {@link prepareLongBuildFileContent};
74
+ * it parses the js-transpiled contents of the "long build" file and extracts/reconstructs the resource import `Map` from it.
75
+ *
76
+ * since I plan on using a dynamic script `import()` to execute the contents of a modified version of the "long build" file content,
77
+ * this method has to be made asynchronous.
78
+ * I'm certainly not going to be using `eval` or the `Function` constructor, because they are often restricted in some js-environments.
79
+ */
80
+ parseLongBuildFileContent(longbuild_file_contents: string): Promise<Map<string, ImportEntity[]>>;
81
+ }
82
+ export declare class LongBuildStep {
83
+ /** the build number of this build step, starting with zero. */
84
+ readonly buildNumber: number;
85
+ /** the unique filename of this "long build step" js file.
86
+ * it is a computed value that evaluates to `${buildNumber}.(${uuid}).js`.
87
+ */
88
+ readonly filename: string;
89
+ readonly promise: Promise<void>;
90
+ readonly signalresolve: (() => void);
91
+ readonly cancelResolve: (() => void);
92
+ readonly resourceImports: Map<string, ImportEntity[]>;
93
+ protected readonly controller: LongBuildController;
94
+ constructor(parent_controller: LongBuildController, build_number: number);
95
+ /** register imports performed by some resource `importer_key`.
96
+ * the `importer_key` should be formatted as `${namespace}:${resolved_path}` of the resource performing the `imports`.
97
+ */
98
+ pushImports(importer_key: string, imports: ImportEntity[]): void;
99
+ /** prepares the file contents of the "long build" of this "long build step".
100
+ *
101
+ * you would use this once you have deduced that all files that were in circulation during this build step have exited,
102
+ * and therefore your long build plugin must also halt by loading the contents prepared here by this method.
103
+ *
104
+ * > [!caution]
105
+ * > the file's contents are in typescript rather than javascript.
106
+ * > so make sure to use the `"ts"` esbuild loader for it.
107
+ */
108
+ prepareLongBuildFileContent(): string;
109
+ }
110
+ export interface LongBuildPluginSetupConfig {
111
+ controller: LongBuildController;
112
+ }
113
+ /** this plugin that enables the inclusion of additional imports dynamically, as esbuild is transforming the loaded content.
114
+ *
115
+ * the reason why this plugin is called "long build" is because it hangs up at its loader stage and waits for the import requests to come in,
116
+ * until all known entities that had entered the `onResolve` stage have exited through at least one `onLoad` hook.
117
+ *
118
+ * > [!note]
119
+ * > this plugin should be placed at the very beginning, as it needs to inspect all incoming path-resolution requests,
120
+ * > in order to track if any unprocessed files still remain while bundling.
121
+ *
122
+ * > _Mr. Feast_: Hello everyone, it's your host jimmy neutrino,
123
+ * > and today we'll be trafficking 100 foreign slaves to compete against one another in building the longest pyramid.
124
+ * > whichever slave manages to build the tallest pyramid at the 100 hour mark will earn his freedom and a also a free bugatti**!
125
+ * >
126
+ * > _Lapdog #1_: the rules are simple: if a slave falls asleeps, or moves out of the red circle,
127
+ * > they'll get disqualified immediately and be deported back to their original owner.
128
+ * >
129
+ * > _Lapdog #2_: look at this wonderful art piece that I commissioned from epstien himself!
130
+ * > hey! stop criticizing me! I'm doing this for my son! also, I identify as they/them, so you can't criticize me now.
131
+ * >
132
+ * > **no auto insurance will be supplied, and state sales tax will be the responsibility of the winner.
133
+ * > failing to register your prize within 6 hours of winning will indicate that you wish to forfeit from owning it.
134
+ */
135
+ export declare const longBuildPluginSetup: (config: LongBuildPluginSetupConfig) => EsbuildPluginSetup;
136
+ /** {@inheritDoc longBuildPluginSetup} */
137
+ export declare const longBuildPlugin: (config: LongBuildPluginSetupConfig) => EsbuildPlugin;
138
+ //# sourceMappingURL=long_build.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"long_build.d.ts","sourceRoot":"","sources":["../../src/plugins/long_build.ts"],"names":[],"mappings":"AAAA;;;;;;;EAOE;AAGF,OAAO,KAAK,EAAE,qBAAqB,EAAE,aAAa,EAAsB,kBAAkB,EAA6B,eAAe,EAAE,MAAM,2BAA2B,CAAA;AAGzK,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAA;AACxD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAA;AAgDpD,MAAM,WAAW,yBAAyB;IACzC;;;MAGE;IACF,aAAa,CAAC,EAAE,cAAc,CAAA;CAC9B;AAED,+EAA+E;AAC/E,qBAAa,mBAAmB;IAC/B;;MAEE;IACF,SAAgB,IAAI,EAAE,MAAM,CAAA;IAE5B;;;;;;;MAOE;IACF,SAAgB,YAAY,EAAE,MAAM,CAAA;IAEpC;;;;MAIE;IACF,SAAgB,YAAY,EAAE,MAAM,CAAA;IAEpC;;MAEE;IACF,SAAgB,eAAe,EAAE,MAAM,CAAA;IAEvC,4IAA4I;IAC5I,SAAgB,WAAW,EAAE,MAAM,CAAA;IAEnC;;;;;;;;;;;MAWE;IACK,qBAAqB,EAAE,MAAM,CAAA;IAEpC;;;;MAIE;IACF,SAAS,CAAC,gBAAgB,EAAE,GAAG,CAAC,MAAM,CAAC,CAAY;IAE5C,KAAK,EAAE,KAAK,CAAC,aAAa,CAAC,CAAK;IAEvC,wGAAwG;IACjG,GAAG,EAAE,cAAc,CAAA;gBAEd,MAAM,CAAC,EAAE,yBAAyB;IAYvC,cAAc,IAAI,qBAAqB,EAAE;IAgBzC,qBAAqB,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI;IAO9C,qBAAqB,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI;IAU9C,mBAAmB,CAAC,IAAI,EAAE,eAAe;IAwBhD;;;;;;MAME;IACW,yBAAyB,CAAC,uBAAuB,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,YAAY,EAAE,CAAC,CAAC;CAW7G;AAED,qBAAa,aAAa;IACzB,+DAA+D;IAC/D,SAAgB,WAAW,EAAE,MAAM,CAAA;IAEnC;;MAEE;IACF,SAAgB,QAAQ,EAAE,MAAM,CAAA;IAEhC,SAAgB,OAAO,EAAE,OAAO,CAAC,IAAI,CAAC,CAAA;IAEtC,SAAgB,aAAa,EAAE,CAAC,MAAM,IAAI,CAAC,CAAA;IAE3C,SAAgB,aAAa,EAAE,CAAC,MAAM,IAAI,CAAC,CAAA;IAE3C,SAAgB,eAAe,EAAE,GAAG,CAAC,MAAM,EAAE,YAAY,EAAE,CAAC,CAAY;IAExE,SAAS,CAAC,QAAQ,CAAC,UAAU,EAAE,mBAAmB,CAAA;gBAEtC,iBAAiB,EAAE,mBAAmB,EAAE,YAAY,EAAE,MAAM;IASxE;;MAEE;IACK,WAAW,CAAC,YAAY,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,EAAE;IAIhE;;;;;;;;MAQE;IACK,2BAA2B,IAAI,MAAM;CAoC5C;AAED,MAAM,WAAW,0BAA0B;IAC1C,UAAU,EAAE,mBAAmB,CAAA;CAC/B;AAED;;;;;;;;;;;;;;;;;;;;;EAqBE;AACF,eAAO,MAAM,oBAAoB,WAAY,0BAA0B,KAAG,kBAgDzE,CAAA;AAED,yCAAyC;AACzC,eAAO,MAAM,eAAe,WAAY,0BAA0B,KAAG,aAKpE,CAAA"}
@@ -0,0 +1,288 @@
1
+ /** an internal super-build plugin that enables the inclusion of additional imports dynamically,
2
+ * as esbuild is transforming the loaded content.
3
+ *
4
+ * the reason why this plugin is called "long build" is because it hangs up at its loader stage and waits for the import requests to come in,
5
+ * until all known entities that had entered the `onResolve` stage have exited through at least one `onLoad` hook.
6
+ *
7
+ * @module
8
+ */
9
+ import { array_isEmpty, DEBUG, escapeLiteralStringForRegex, json_stringify, parseFilepathInfo, pathToPosixPath, promiseOutside } from "../deps.js";
10
+ import { cancelableDelayedPromiseResolver, generateUuid, noopLogger } from "../funcdefs.js";
11
+ var LONGBUILD;
12
+ (function (LONGBUILD) {
13
+ /** the minimum amount of time (in ms) that the long build will wait before concluding its `contents`,
14
+ * after it has determined that no active files remain in circulation.
15
+ * if a new file is suddenly introduced while the longbuild is waiting for this delay to complete, it will halt the timer,
16
+ * and wait for all new files in the circulation to complete before beginning this countdown again.
17
+ *
18
+ * ideally, this should be set to a safe high value,
19
+ * where you can be certain that esbuild's go-side transpiler/transformer won't take any longer than that to transform a single file in your bundle.
20
+ * i.e. the lower bound of this enum value = `max(...all_bundled_files.map((file) => get_transpilation_time(file))`
21
+ */
22
+ LONGBUILD[LONGBUILD["ONLOAD_MIN_DELAY"] = 500] = "ONLOAD_MIN_DELAY";
23
+ /** the name of the resource-imports storage variable used across the "long build step" js files. */
24
+ LONGBUILD["RESOURCE_VAR_NAME"] = "resourceImports";
25
+ /** this will be common dependency file of each "long build step" js file, so that they all share the same `resourceImports` storage variable.
26
+ *
27
+ * the name of this file will be `deps.(${uuid}).js`, defined in the {@link LongBuildController}.
28
+ */
29
+ LONGBUILD["DEPS_FILE"] = "\nexport interface ImportEntity<K = any> {\n\tkey: K\n\tpath: string\n\twith: Record<string, string>\n\texternal: boolean\n}\n\nexport const resourceImports: Map<\n\tstring, // the importer's key.\n\tImportEntity[] // all of the entities imported by the importer.\n> = new Map()\n\n// esbuild likes to add a \"@__PURE__\" annotation to the variable above.\n// hence, to ensure that it never gets stripped away (because we want to dynamically import it later),\n// we perform an action that has a potential for side-effect, preventing esbuild from ever dropping this variable in the bundle.\nresourceImports.size\n\nexport const console_log = (...args: any[]) => {\n\t// console.log(...args) // for debugging purposes.\n}\n";
30
+ })(LONGBUILD || (LONGBUILD = {}));
31
+ const import_statement_regex = new RegExp("await\\s+import\\s*\\(\\s*(?<quote>[\"'`])(?<importPath>.*?)\\k<quote>\\s*\\)", "g");
32
+ /** the controller used for commanding the state of the "long build" plugin. */
33
+ export class LongBuildController {
34
+ /** the unique base filename that will be used by the {@link longBuildPluginSetup} plugin to insert its "long build" js file as an entry-point.
35
+ * the full filename format it will use will be: `${recursion_number}.(${uuid}).js`.
36
+ */
37
+ uuid;
38
+ /** the unique filename(s) that will be used for the "long build" js files.
39
+ * it is a computed value that evaluates to `.(${uuid}).js`,
40
+ * and the actual filename that gets inserted/injected will also have a leading number, signifying the "build/recursion number".
41
+ *
42
+ * for instance, the entry-point long build js file will be named: `0.(${uuid}).js`,
43
+ * while the next recursive "long build" import within the `0.(${uuid}).js` file will be named `1.(${uuid}).js`,
44
+ * and so on (until a "long build" js file with zero external imports/includes is discovered, at which point we shall halt).
45
+ */
46
+ baseFilename;
47
+ /** the name of the "long build dependency" file, as defined in {@link LONGBUILD.DEPS_FILE}.
48
+ *
49
+ * its value evaluates to `deps.(${uuid}).js`, and it is imported by each "long build step" js file as a dependency,
50
+ * in order to have a shared resource variable where all imports will get registered.
51
+ */
52
+ depsFilename;
53
+ /** the namespace used by the {@link longBuildPlugin}.
54
+ * it is a computed value that evaluates to `oazmi-superbuild-long_build-plugin-${uuid}`.
55
+ */
56
+ pluginNamespace;
57
+ /** the current build/recursion number. it starts with zero, and it is used for indicating the filename of the current "long build" file. */
58
+ buildNumber;
59
+ /** the number of files in the esbuild build process that are currently in circulation.
60
+ *
61
+ * - everytime a new file hits the "long build" plugin's `onResolve` hook, this value gets incremented by one,
62
+ * since a "new file is currently in circulation".
63
+ * - whenever a file gets successfully loaded via some plugin's `onLoad` hook,
64
+ * the {@link SuperPluginBuild.onLoad} overload decrements this shared-state counter,
65
+ * since a "file that was in circulation has exited".
66
+ * - a caveat to look out for is the fact that if any plugin calls {@link SuperPluginBuild.resolve},
67
+ * this counter will get incremented again (double count),
68
+ * since the resolve request will go through our "long build" plugin's `onResolve` hook once again.
69
+ * to combat this double count, the {@link SuperPluginBuild.resolve} function decrements this counter whenever it gets called.
70
+ */
71
+ remainingFilesCounter;
72
+ /** esbuild caches the loaded result of an `onLoad` hook, based on the result of the `onResolve` hook's `result.path` and `result.namespace`
73
+ * (I don't know if esbuild also caches with respect to the `with` import attribute).
74
+ * but we don't want to count any cached paths towards {@link remainingFilesCounter}, since they won't be loaded again;
75
+ * which is why we need this hash-set to keep track of what has already been seen once.
76
+ */
77
+ encounteredPaths = new Set();
78
+ steps = [];
79
+ /** a logging function for internal debugging. it gets called only when {@link DEBUG.LOG} is enabled. */
80
+ log;
81
+ constructor(config) {
82
+ const uuid = generateUuid(2);
83
+ this.log = config?.debuggingLogs ?? noopLogger;
84
+ this.uuid = uuid;
85
+ this.baseFilename = `.(${uuid}).js`;
86
+ this.depsFilename = `deps.(${uuid}).js`;
87
+ this.pluginNamespace = `oazmi-superbuild-long_build-plugin-${uuid}`;
88
+ this.remainingFilesCounter = 0;
89
+ this.buildNumber = -1;
90
+ this.incrementBuild();
91
+ }
92
+ incrementBuild() {
93
+ const warnings = [];
94
+ if (this.remainingFilesCounter !== 0) {
95
+ warnings.push({
96
+ text: `[LongBuildController.incrementBuild]: the number of remaining files (${this.remainingFilesCounter}) in circulation during th current long-build (${this.buildNumber}) did not reach zero before the build was incremented!`
97
+ });
98
+ }
99
+ // hey! incrementing a readonly number is illegal, IN AMERICA! - bandit keith. (unless they pass the citizenship test)
100
+ this.steps.push(new LongBuildStep(this, ++this.buildNumber));
101
+ return warnings;
102
+ }
103
+ incrementFilesCounter(pathname) {
104
+ // cancel any prior resolve that may have been triggered.
105
+ this.steps[this.buildNumber].cancelResolve();
106
+ ++this.remainingFilesCounter;
107
+ if (DEBUG.LOG) {
108
+ this.log(`[LongBuildController]: increment for: "${pathname}". remaining files: ${this.remainingFilesCounter}.`);
109
+ }
110
+ }
111
+ decrementFilesCounter(pathname) {
112
+ // cancel any prior resolve that may have been triggered,
113
+ // so that we always ensure that the desired amount of time has been waited with absolutely no resource processing in between.
114
+ this.steps[this.buildNumber].cancelResolve();
115
+ if ((--this.remainingFilesCounter) <= 0) {
116
+ this.steps[this.buildNumber].signalresolve();
117
+ }
118
+ if (DEBUG.LOG) {
119
+ this.log(`[LongBuildController]: decrement for: "${pathname}". remaining files: ${this.remainingFilesCounter}.`);
120
+ }
121
+ }
122
+ cacheResolvedResult(args) {
123
+ // first we make sure that if the result is `external`, then we decrement the the file counter,
124
+ // as this resource will never go to the loading stage (never gets passed to an `onLoad`).
125
+ if (args.external) {
126
+ this.decrementFilesCounter(args.path);
127
+ return;
128
+ }
129
+ // for all other non-external cases, we expect an `args.path` to exist.
130
+ const path = pathToPosixPath(args.path), namespace = args.namespace ?? "file", key = namespace + ":" + path;
131
+ // if the resolved path has already been encountered once, then esbuild will have it cached, and so, no loader hooks will be called,
132
+ // therefore we must immediately decrement the files counter, since the loader can't do it any longer.
133
+ if (this.encounteredPaths.has(key)) {
134
+ if (DEBUG.LOG) {
135
+ this.log(`[LongBuildController]: already encountered: "${key}"`);
136
+ }
137
+ this.decrementFilesCounter(args.path);
138
+ }
139
+ else {
140
+ if (DEBUG.LOG) {
141
+ this.log(`[LongBuildController]: never encountered : "${key}"`);
142
+ }
143
+ this.encounteredPaths.add(key);
144
+ }
145
+ }
146
+ /** this function does the inverse of {@link prepareLongBuildFileContent};
147
+ * it parses the js-transpiled contents of the "long build" file and extracts/reconstructs the resource import `Map` from it.
148
+ *
149
+ * since I plan on using a dynamic script `import()` to execute the contents of a modified version of the "long build" file content,
150
+ * this method has to be made asynchronous.
151
+ * I'm certainly not going to be using `eval` or the `Function` constructor, because they are often restricted in some js-environments.
152
+ */
153
+ async parseLongBuildFileContent(longbuild_file_contents) {
154
+ const
155
+ // we first strip away all dynamic import statements and replace them with just the import string.
156
+ // for instance: `await import("./hello-world.xyz")` will transform to just "String.raw`./hello-world.xyz`".
157
+ js_content_without_imports = longbuild_file_contents.replaceAll(import_statement_regex, "String.raw`$<importPath>`"), js_blob = new Blob([js_content_without_imports], { type: "text/javascript" }), js_blob_url = URL.createObjectURL(js_blob),
158
+ // now we dynamically load our bundled long-build js file that contains import statements, and then return them.
159
+ { [LONGBUILD.RESOURCE_VAR_NAME]: resourceImports } = await import(js_blob_url);
160
+ return resourceImports;
161
+ }
162
+ }
163
+ export class LongBuildStep {
164
+ /** the build number of this build step, starting with zero. */
165
+ buildNumber;
166
+ /** the unique filename of this "long build step" js file.
167
+ * it is a computed value that evaluates to `${buildNumber}.(${uuid}).js`.
168
+ */
169
+ filename;
170
+ promise;
171
+ signalresolve;
172
+ cancelResolve;
173
+ resourceImports = new Map();
174
+ controller;
175
+ constructor(parent_controller, build_number) {
176
+ this.controller = parent_controller;
177
+ this.buildNumber = build_number;
178
+ this.filename = `${build_number}${parent_controller.baseFilename}`;
179
+ const [promise, resolve, reject] = promiseOutside();
180
+ [this.signalresolve, this.cancelResolve] = cancelableDelayedPromiseResolver(resolve, LONGBUILD.ONLOAD_MIN_DELAY, parent_controller.log);
181
+ this.promise = promise;
182
+ }
183
+ /** register imports performed by some resource `importer_key`.
184
+ * the `importer_key` should be formatted as `${namespace}:${resolved_path}` of the resource performing the `imports`.
185
+ */
186
+ pushImports(importer_key, imports) {
187
+ this.resourceImports.set(importer_key, imports);
188
+ }
189
+ /** prepares the file contents of the "long build" of this "long build step".
190
+ *
191
+ * you would use this once you have deduced that all files that were in circulation during this build step have exited,
192
+ * and therefore your long build plugin must also halt by loading the contents prepared here by this method.
193
+ *
194
+ * > [!caution]
195
+ * > the file's contents are in typescript rather than javascript.
196
+ * > so make sure to use the `"ts"` esbuild loader for it.
197
+ */
198
+ prepareLongBuildFileContent() {
199
+ const all_imports_this_build = [...this.resourceImports];
200
+ const all_imports_js_str = all_imports_this_build.map(([importer_key, imports_arr]) => {
201
+ const imports_str_arr = imports_arr.map((import_entity) => {
202
+ const { key, path, with: with_attr = {}, external = false } = import_entity, key_str = json_stringify(key), path_str = json_stringify(path), with_str = json_stringify(with_attr), external_str = json_stringify(external),
203
+ // to prevent resources marked as `external` from being discovered by esbuild, we don't wrap them around a dynamic `import(...)`.
204
+ import_statement = external ? path_str : `await import(${path_str})`;
205
+ // return `import(${path_str}, { with: { importer: "" } })`
206
+ return `{ key: ${key_str}, path: ${import_statement}, with: ${with_str}, external: ${external_str} }`;
207
+ });
208
+ const imports_str = imports_str_arr.join(",\n\t");
209
+ const importer_key_str = json_stringify(importer_key);
210
+ return `resourceImports.set(${importer_key_str}, [\n\t${imports_str}\n])`;
211
+ });
212
+ const deps_filename = this.controller.depsFilename, next_filename = `${this.buildNumber + 1}${this.controller.baseFilename}`, recursion_import_statement = !array_isEmpty(all_imports_this_build)
213
+ ? `import "${next_filename}" // recursion to the next long-build.`
214
+ : "// no imports were pushed this build-number. hence, this is the final long-build file.";
215
+ return `
216
+ import { ${LONGBUILD.RESOURCE_VAR_NAME}, console_log } from "${deps_filename}"
217
+ export { ${LONGBUILD.RESOURCE_VAR_NAME} } // export the "resourceImports" so that it can be imported by the parser.
218
+ ${recursion_import_statement}
219
+
220
+ console_log("long build: ${this.buildNumber}")
221
+ ${all_imports_js_str}
222
+ `.trim();
223
+ }
224
+ }
225
+ /** this plugin that enables the inclusion of additional imports dynamically, as esbuild is transforming the loaded content.
226
+ *
227
+ * the reason why this plugin is called "long build" is because it hangs up at its loader stage and waits for the import requests to come in,
228
+ * until all known entities that had entered the `onResolve` stage have exited through at least one `onLoad` hook.
229
+ *
230
+ * > [!note]
231
+ * > this plugin should be placed at the very beginning, as it needs to inspect all incoming path-resolution requests,
232
+ * > in order to track if any unprocessed files still remain while bundling.
233
+ *
234
+ * > _Mr. Feast_: Hello everyone, it's your host jimmy neutrino,
235
+ * > and today we'll be trafficking 100 foreign slaves to compete against one another in building the longest pyramid.
236
+ * > whichever slave manages to build the tallest pyramid at the 100 hour mark will earn his freedom and a also a free bugatti**!
237
+ * >
238
+ * > _Lapdog #1_: the rules are simple: if a slave falls asleeps, or moves out of the red circle,
239
+ * > they'll get disqualified immediately and be deported back to their original owner.
240
+ * >
241
+ * > _Lapdog #2_: look at this wonderful art piece that I commissioned from epstien himself!
242
+ * > hey! stop criticizing me! I'm doing this for my son! also, I identify as they/them, so you can't criticize me now.
243
+ * >
244
+ * > **no auto insurance will be supplied, and state sales tax will be the responsibility of the winner.
245
+ * > failing to register your prize within 6 hours of winning will indicate that you wish to forfeit from owning it.
246
+ */
247
+ export const longBuildPluginSetup = (config) => {
248
+ const controller = config.controller, longbuild_base_filename = controller.baseFilename, longbuild_deps_filename = controller.depsFilename, plugin_namespace = controller.pluginNamespace;
249
+ return (build) => {
250
+ const sbuild = build, // I can't think of a better way for annotating `build` as a `SuperPluginBuild` without getting a bunch of type errors.
251
+ filter = RegExp(escapeLiteralStringForRegex(longbuild_base_filename) + "$"), deps_file_filter = RegExp(escapeLiteralStringForRegex(longbuild_deps_filename) + "$");
252
+ build.onResolve({ filter: /.*/ }, (args) => {
253
+ // TODO: I believe `<stdin>` does not go through any `onResolve`, and jumps straight to `onLoad`. so, we must account for not decrementing the counter when it is `<stdin>`.
254
+ controller.incrementFilesCounter(args.path);
255
+ if (!args.path.endsWith(longbuild_base_filename)) {
256
+ return undefined;
257
+ }
258
+ const filename = parseFilepathInfo(args.path).filename; // this is to strip away any directory prefixes.
259
+ return { path: filename, namespace: plugin_namespace }; // TODO: should we set `sideEffects` to true?
260
+ });
261
+ build.onLoad({ filter: deps_file_filter, namespace: plugin_namespace }, (args) => {
262
+ return { contents: LONGBUILD.DEPS_FILE, loader: "ts" };
263
+ });
264
+ build.onLoad({ filter, namespace: plugin_namespace }, async (args) => {
265
+ // the "long build" js files need to temporarily remove themselves from the `remainingFilesCounter` circulation, otherwise it will never drop to zero
266
+ controller.decrementFilesCounter(args.path);
267
+ const filename = args.path, build_number = Number(filename.slice(0, -longbuild_base_filename.length)), build_step = controller.steps[build_number];
268
+ // wait for super-build to externally resolve the promise below to signal that the `remainingFilesCounter` has dropped to zero.
269
+ await build_step.promise;
270
+ const contents = build_step.prepareLongBuildFileContent(), warnings = controller.incrementBuild();
271
+ // we increment the `remainingFilesCounter` because returning from this function will cause it to drop to `-1` if we don't increment.
272
+ ++controller.remainingFilesCounter;
273
+ return { contents, loader: "ts", resolveDir: "./", warnings };
274
+ });
275
+ // long build file(s) should not be emitted into the filesystem.
276
+ sbuild.onEmit({
277
+ filter: /.*/,
278
+ inputs: [{ filter: /.*/, namespace: plugin_namespace }],
279
+ }, (args) => { return { write: false }; });
280
+ };
281
+ };
282
+ /** {@inheritDoc longBuildPluginSetup} */
283
+ export const longBuildPlugin = (config) => {
284
+ return {
285
+ name: "oazmi-superbuild-long_build-plugin",
286
+ setup: longBuildPluginSetup(config),
287
+ };
288
+ };
@@ -0,0 +1,48 @@
1
+ /** a plugin that replicates esbuild's native resource/path resolution and loading behavior through the plugin api layer.
2
+ *
3
+ * - for resolving paths, the plugin creates a sub-build that is free of any contaminating plugins to get esbuild to resolve the input resource naturally.
4
+ * - for loading content, the plugin places an `onLoad` hook to capture all file-namespace paths,
5
+ * and then mimics esbuild's native loading behavior by guessing the loader it would use,
6
+ * and then `fetch`es the content (without invoking esbuild's native loading in the process).
7
+ *
8
+ * @module
9
+ */
10
+ import type { EsbuildBuildOptions, EsbuildPlugin, EsbuildPluginBuild, EsbuildPluginSetup, EsbuildResolveOptions, EsbuildResolveResult } from "../esbuild/strongtypes.js";
11
+ /** this plugin replicates esbuild's native path resolution and loading behavior through the plugin api layer.
12
+ *
13
+ * > [!note]
14
+ * > you will probably want to place this as the last plugin, if you don't want it interfering with your other plugins' resolving and loading mechanisms.
15
+ *
16
+ * - for resolving paths, the plugin creates a sub-build that is free of any contaminating plugins to get esbuild to resolve the input resource naturally.
17
+ * - for loading content, the plugin places an `onLoad` hook to capture all file-namespace paths,
18
+ * and then mimics esbuild's native loading behavior by guessing the loader it would use,
19
+ * and then `fetch`es the content (without invoking esbuild's native loading in the process).
20
+ *
21
+ * > _Van_: It was Asche who was supposed to come here, not you, replica.
22
+ * >
23
+ * > _Luke_: Even if you refuse to acknowledge me, I am ME! Master... no, Van! Prepare to DIE!
24
+ */
25
+ export declare const nativeReplicaPluginSetup: () => EsbuildPluginSetup;
26
+ /** {@inheritDoc nativeReplicaPluginSetup} */
27
+ export declare const nativeReplicaPlugin: () => EsbuildPlugin;
28
+ /** this class provides {@link resolve} method that is capable of resolving paths using esbuild's node-resolution scanner.
29
+ *
30
+ * it works by invoking esbuild's `PluginBuild.resolve` function whenever the {@link resolve} method is called,
31
+ * and it holds an `onLoad` hook hostage by hanging forever,
32
+ * so that the internal sub-build does not conclude until the {@link stop} method has been called.
33
+ */
34
+ export declare class EsbuildNativeResolver {
35
+ #private;
36
+ protected entryPoint: string;
37
+ protected namespace: string;
38
+ protected readonly startBuildPromise: Promise<void>;
39
+ protected readonly startBuildResolve: (() => void);
40
+ protected readonly stopBuildPromise: Promise<void>;
41
+ protected readonly stopBuildResolve: (() => void);
42
+ constructor(base_esbuild: EsbuildPluginBuild["esbuild"], build_options?: EsbuildBuildOptions);
43
+ resolve(path: string, options?: EsbuildResolveOptions): Promise<EsbuildResolveResult>;
44
+ stop(): Promise<void>;
45
+ protected initOptions(build_options?: EsbuildBuildOptions): EsbuildBuildOptions;
46
+ protected initPlugin(): EsbuildPlugin;
47
+ }
48
+ //# sourceMappingURL=native_replica.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"native_replica.d.ts","sourceRoot":"","sources":["../../src/plugins/native_replica.ts"],"names":[],"mappings":"AAAA;;;;;;;;EAQE;AAIF,OAAO,KAAK,EAAE,mBAAmB,EAAE,aAAa,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,qBAAqB,EAAE,oBAAoB,EAA6B,MAAM,2BAA2B,CAAA;AAKnM;;;;;;;;;;;;;EAaE;AACF,eAAO,MAAM,wBAAwB,QAAO,kBAqC3C,CAAA;AAED,6CAA6C;AAC7C,eAAO,MAAM,mBAAmB,QAAO,aAKtC,CAAA;AAYD;;;;;EAKE;AACF,qBAAa,qBAAqB;;IACjC,SAAS,CAAC,UAAU,SAA0B;IAC9C,SAAS,CAAC,SAAS,SAAa;IAChC,SAAS,CAAC,QAAQ,CAAC,iBAAiB,EAAE,OAAO,CAAC,IAAI,CAAC,CAAA;IACnD,SAAS,CAAC,QAAQ,CAAC,iBAAiB,EAAE,CAAC,MAAM,IAAI,CAAC,CAAA;IAClD,SAAS,CAAC,QAAQ,CAAC,gBAAgB,EAAE,OAAO,CAAC,IAAI,CAAC,CAAA;IAClD,SAAS,CAAC,QAAQ,CAAC,gBAAgB,EAAE,CAAC,MAAM,IAAI,CAAC,CAAA;gBAKrC,YAAY,EAAE,kBAAkB,CAAC,SAAS,CAAC,EAAE,aAAa,CAAC,EAAE,mBAAmB;IAQ/E,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,qBAAqB,GAAG,OAAO,CAAC,oBAAoB,CAAC;IAKrF,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAKlC,SAAS,CAAC,WAAW,CAAC,aAAa,GAAE,mBAAwB,GAAG,mBAAmB;IAgBnF,SAAS,CAAC,UAAU,IAAI,aAAa;CA0BrC"}
@@ -0,0 +1,122 @@
1
+ /** a plugin that replicates esbuild's native resource/path resolution and loading behavior through the plugin api layer.
2
+ *
3
+ * - for resolving paths, the plugin creates a sub-build that is free of any contaminating plugins to get esbuild to resolve the input resource naturally.
4
+ * - for loading content, the plugin places an `onLoad` hook to capture all file-namespace paths,
5
+ * and then mimics esbuild's native loading behavior by guessing the loader it would use,
6
+ * and then `fetch`es the content (without invoking esbuild's native loading in the process).
7
+ *
8
+ * @module
9
+ */
10
+ import { escapeLiteralStringForRegex, fileUrlToLocalPath, json_stringify, promiseOutside, resolveAsUrl } from "../deps.js";
11
+ import { guessExtensionLoader_Factory } from "../esbuild/native.js";
12
+ import { INNER_PLUGIN_BUILD } from "../super/typedefs.js";
13
+ /** this plugin replicates esbuild's native path resolution and loading behavior through the plugin api layer.
14
+ *
15
+ * > [!note]
16
+ * > you will probably want to place this as the last plugin, if you don't want it interfering with your other plugins' resolving and loading mechanisms.
17
+ *
18
+ * - for resolving paths, the plugin creates a sub-build that is free of any contaminating plugins to get esbuild to resolve the input resource naturally.
19
+ * - for loading content, the plugin places an `onLoad` hook to capture all file-namespace paths,
20
+ * and then mimics esbuild's native loading behavior by guessing the loader it would use,
21
+ * and then `fetch`es the content (without invoking esbuild's native loading in the process).
22
+ *
23
+ * > _Van_: It was Asche who was supposed to come here, not you, replica.
24
+ * >
25
+ * > _Luke_: Even if you refuse to acknowledge me, I am ME! Master... no, Van! Prepare to DIE!
26
+ */
27
+ export const nativeReplicaPluginSetup = () => {
28
+ return async (build) => {
29
+ const user_ext_to_loader_map = build.initialOptions.loader ?? {}, guess_extension_loader = guessExtensionLoader_Factory(user_ext_to_loader_map),
30
+ // if super-build is being used, we must extract the original hidden `esbuild` from it, otherwise the native-resolver won't work.
31
+ base_esbuild = INNER_PLUGIN_BUILD in build
32
+ ? build[INNER_PLUGIN_BUILD].esbuild
33
+ : build.esbuild, native_resolver = new EsbuildNativeResolver(base_esbuild, build.initialOptions);
34
+ build.onEnd(() => native_resolver.stop()); // stop the sub-build from hanging once the main build has concluded.
35
+ build.onResolve({ filter: /.*/ }, (args) => {
36
+ const { path, ...rest_args } = args;
37
+ return native_resolver.resolve(args.path, rest_args);
38
+ });
39
+ build.onLoad({ filter: /.*/, namespace: "file" }, async (args) => {
40
+ const path_url = resolveAsUrl(args.path), with_attr = args.with, loader = guess_extension_loader(path_url, with_attr), resolveDir = fileUrlToLocalPath(new URL("./", path_url)), path = fileUrlToLocalPath(path_url);
41
+ const response = await fetch(path_url, { method: "GET" });
42
+ if (!response.ok) {
43
+ const message = `ERROR: network fetch response for url "${path_url.href}" was not ok (${response.status}). response header:\n${json_stringify(response.headers)}`;
44
+ return { errors: [{ text: message }] };
45
+ }
46
+ const contents = await response.bytes();
47
+ // to mimic esbuild's native loader behavior, we don't pass the `args.pluginData` (even though, I'd like pass it).
48
+ // TODO: though, what if I were to pass it over? how bad would it be? will it realistically affect any existing popular plugin?
49
+ return { contents, loader, resolveDir, watchFiles: [path] };
50
+ });
51
+ };
52
+ };
53
+ /** {@inheritDoc nativeReplicaPluginSetup} */
54
+ export const nativeReplicaPlugin = () => {
55
+ return {
56
+ name: "oazmi-superbuild-native_loader-plugin",
57
+ setup: nativeReplicaPluginSetup(),
58
+ };
59
+ };
60
+ /** this class provides {@link resolve} method that is capable of resolving paths using esbuild's node-resolution scanner.
61
+ *
62
+ * it works by invoking esbuild's `PluginBuild.resolve` function whenever the {@link resolve} method is called,
63
+ * and it holds an `onLoad` hook hostage by hanging forever,
64
+ * so that the internal sub-build does not conclude until the {@link stop} method has been called.
65
+ */
66
+ export class EsbuildNativeResolver {
67
+ entryPoint = "<the-unloadable-void>";
68
+ namespace = "the-void";
69
+ startBuildPromise;
70
+ startBuildResolve;
71
+ stopBuildPromise;
72
+ stopBuildResolve;
73
+ #internal_resolve;
74
+ #build_result;
75
+ constructor(base_esbuild, build_options) {
76
+ [this.startBuildPromise, this.startBuildResolve] = promiseOutside();
77
+ [this.stopBuildPromise, this.stopBuildResolve] = promiseOutside();
78
+ build_options = this.initOptions(build_options);
79
+ build_options.plugins = [this.initPlugin()];
80
+ this.#build_result = base_esbuild.build(build_options);
81
+ }
82
+ async resolve(path, options) {
83
+ await this.startBuildPromise;
84
+ return this.#internal_resolve(path, options);
85
+ }
86
+ async stop() {
87
+ this.stopBuildResolve();
88
+ await this.#build_result;
89
+ }
90
+ initOptions(build_options = {}) {
91
+ const { absWorkingDir, alias, conditions, external, mainFields, nodePaths, packages, platform, resolveExtensions, tsconfig, tsconfigRaw, } = build_options;
92
+ const entrypoint = this.entryPoint;
93
+ return {
94
+ absWorkingDir, alias, conditions, external,
95
+ mainFields, nodePaths, packages, platform,
96
+ resolveExtensions, tsconfig, tsconfigRaw,
97
+ bundle: false, minify: false, write: false,
98
+ outdir: "./temp/", entryPoints: [entrypoint],
99
+ };
100
+ }
101
+ initPlugin() {
102
+ const self = this;
103
+ const setup_fn = (build) => {
104
+ const entrypoint = self.entryPoint, filter = RegExp(escapeLiteralStringForRegex(entrypoint) + "$"), namespace = self.namespace;
105
+ build.onResolve({ filter }, async (args) => {
106
+ return { path: entrypoint, namespace };
107
+ });
108
+ build.onLoad({ filter, namespace }, async (args) => {
109
+ self.startBuildResolve();
110
+ self.#internal_resolve = (path, args) => {
111
+ return build.resolve(path, { kind: "entry-point", resolveDir: "./", ...args });
112
+ };
113
+ await self.stopBuildPromise;
114
+ return { contents: "", loader: "empty" };
115
+ });
116
+ };
117
+ return {
118
+ name: "native-esbuild-resolver-capture",
119
+ setup: setup_fn,
120
+ };
121
+ }
122
+ }