@decohere/flux 0.0.1-dev.108 → 0.0.1-dev.11
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/commonjs/src/flux.command.js +2 -2
- package/commonjs/src/flux.module.js +7 -8
- package/commonjs/src/hot-reload-server.js +215 -302
- package/commonjs/src/index.js +2 -34
- package/commonjs/src/serve.action.js +5 -76
- package/commonjs/src/serve.command.js +3 -31
- package/es6/src/flux.command.js +2 -2
- package/es6/src/flux.module.js +7 -8
- package/es6/src/hot-reload-server.js +172 -283
- package/es6/src/index.js +3 -5
- package/es6/src/serve.action.js +7 -71
- package/es6/src/serve.command.js +3 -31
- package/package.json +6 -7
- package/types/src/flux.module.d.ts +0 -2
- package/types/src/hot-reload-server.d.ts +22 -55
- package/types/src/index.d.ts +1 -8
- package/types/src/serve.action.d.ts +1 -11
- package/types/src/serve.command.d.ts +0 -5
- package/README.md +0 -247
- package/commonjs/bench/load.bench.js +0 -145
- package/commonjs/src/deferred-script-runner.js +0 -56
- package/commonjs/src/flux.js +0 -56
- package/commonjs/src/rewrite-serve-specifier.js +0 -59
- package/commonjs/src/run.action.js +0 -47
- package/commonjs/src/run.command.js +0 -65
- package/commonjs/src/slice-serve.js +0 -130
- package/commonjs/src/source-module-loader.js +0 -237
- package/es6/bench/load.bench.js +0 -136
- package/es6/src/deferred-script-runner.js +0 -46
- package/es6/src/flux.js +0 -41
- package/es6/src/rewrite-serve-specifier.js +0 -49
- package/es6/src/run.action.js +0 -37
- package/es6/src/run.command.js +0 -55
- package/es6/src/slice-serve.js +0 -105
- package/es6/src/source-module-loader.js +0 -181
- package/types/bench/load.bench.d.ts +0 -1
- package/types/src/deferred-script-runner.d.ts +0 -18
- package/types/src/flux.d.ts +0 -43
- package/types/src/rewrite-serve-specifier.d.ts +0 -14
- package/types/src/run.action.d.ts +0 -15
- package/types/src/run.command.d.ts +0 -11
- package/types/src/slice-serve.d.ts +0 -52
- package/types/src/source-module-loader.d.ts +0 -58
|
@@ -1,237 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", {
|
|
3
|
-
value: true
|
|
4
|
-
});
|
|
5
|
-
Object.defineProperty(exports, "SourceModuleLoader", {
|
|
6
|
-
enumerable: true,
|
|
7
|
-
get: function() {
|
|
8
|
-
return SourceModuleLoader;
|
|
9
|
-
}
|
|
10
|
-
});
|
|
11
|
-
const _nodemodule = require("node:module");
|
|
12
|
-
const _nodepath = /*#__PURE__*/ _interop_require_default(require("node:path"));
|
|
13
|
-
const _nodeurl = require("node:url");
|
|
14
|
-
const _decorators = require("@decohere/crucible/decorators");
|
|
15
|
-
const _forge = require("@decohere/forge");
|
|
16
|
-
const _mesh = require("@decohere/mesh");
|
|
17
|
-
const _io = require("@decohere/nexus/io");
|
|
18
|
-
const _scribe = require("@decohere/scribe");
|
|
19
|
-
const _rewriteservespecifier = require("./rewrite-serve-specifier.js");
|
|
20
|
-
function _interop_require_default(obj) {
|
|
21
|
-
return obj && obj.__esModule ? obj : {
|
|
22
|
-
default: obj
|
|
23
|
-
};
|
|
24
|
-
}
|
|
25
|
-
function _getRequireWildcardCache(nodeInterop) {
|
|
26
|
-
if (typeof WeakMap !== "function") return null;
|
|
27
|
-
var cacheBabelInterop = new WeakMap();
|
|
28
|
-
var cacheNodeInterop = new WeakMap();
|
|
29
|
-
return (_getRequireWildcardCache = function(nodeInterop) {
|
|
30
|
-
return nodeInterop ? cacheNodeInterop : cacheBabelInterop;
|
|
31
|
-
})(nodeInterop);
|
|
32
|
-
}
|
|
33
|
-
function _interop_require_wildcard(obj, nodeInterop) {
|
|
34
|
-
if (!nodeInterop && obj && obj.__esModule) {
|
|
35
|
-
return obj;
|
|
36
|
-
}
|
|
37
|
-
if (obj === null || typeof obj !== "object" && typeof obj !== "function") {
|
|
38
|
-
return {
|
|
39
|
-
default: obj
|
|
40
|
-
};
|
|
41
|
-
}
|
|
42
|
-
var cache = _getRequireWildcardCache(nodeInterop);
|
|
43
|
-
if (cache && cache.has(obj)) {
|
|
44
|
-
return cache.get(obj);
|
|
45
|
-
}
|
|
46
|
-
var newObj = {
|
|
47
|
-
__proto__: null
|
|
48
|
-
};
|
|
49
|
-
var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor;
|
|
50
|
-
for(var key in obj){
|
|
51
|
-
if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) {
|
|
52
|
-
var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null;
|
|
53
|
-
if (desc && (desc.get || desc.set)) {
|
|
54
|
-
Object.defineProperty(newObj, key, desc);
|
|
55
|
-
} else {
|
|
56
|
-
newObj[key] = obj[key];
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
newObj.default = obj;
|
|
61
|
-
if (cache) {
|
|
62
|
-
cache.set(obj, newObj);
|
|
63
|
-
}
|
|
64
|
-
return newObj;
|
|
65
|
-
}
|
|
66
|
-
function _ts_decorate(decorators, target, key, desc) {
|
|
67
|
-
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
68
|
-
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
69
|
-
else for(var i = decorators.length - 1; i >= 0; i--)if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
70
|
-
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
71
|
-
}
|
|
72
|
-
class SourceModuleLoader {
|
|
73
|
-
logger = _scribe.scribe.logger(SourceModuleLoader.name);
|
|
74
|
-
transpiler = new _forge.SwcTranspiler();
|
|
75
|
-
disposed = false;
|
|
76
|
-
hooksRegistered = false;
|
|
77
|
-
workspace;
|
|
78
|
-
buildConfig = "debug";
|
|
79
|
-
fileInfoMap = new Map();
|
|
80
|
-
transpileCache = new Map();
|
|
81
|
-
/** SWC options per project, built on first use and kept until the next `configure()`. */ swcConfigs = new Map();
|
|
82
|
-
aliasPaths = {};
|
|
83
|
-
aliasBaseUrl = _nodepath.default.resolve(".");
|
|
84
|
-
versionFileUrl = (fileUrl)=>fileUrl;
|
|
85
|
-
onResolved;
|
|
86
|
-
getWorkspace() {
|
|
87
|
-
return this.workspace;
|
|
88
|
-
}
|
|
89
|
-
getBuildConfig() {
|
|
90
|
-
return this.buildConfig;
|
|
91
|
-
}
|
|
92
|
-
hasSourceFile(absolutePath) {
|
|
93
|
-
return this.fileInfoMap.has(absolutePath);
|
|
94
|
-
}
|
|
95
|
-
sourceFilePaths() {
|
|
96
|
-
return this.fileInfoMap.keys();
|
|
97
|
-
}
|
|
98
|
-
setSourceFile(absolutePath, project) {
|
|
99
|
-
this.fileInfoMap.set(absolutePath, {
|
|
100
|
-
project
|
|
101
|
-
});
|
|
102
|
-
}
|
|
103
|
-
async configure(options) {
|
|
104
|
-
this.disposed = false;
|
|
105
|
-
this.transpileCache.clear();
|
|
106
|
-
this.swcConfigs.clear();
|
|
107
|
-
this.buildConfig = options.buildConfig;
|
|
108
|
-
this.workspace = options.workspace ?? await (0, _forge.createWorkspace)();
|
|
109
|
-
this.versionFileUrl = options.versionFileUrl ?? ((fileUrl)=>fileUrl);
|
|
110
|
-
this.onResolved = options.onResolved;
|
|
111
|
-
this.fileInfoMap = await this.buildFileInfoMap(this.buildConfig);
|
|
112
|
-
const aliases = this.workspace.getPackageAliases(this.buildConfig);
|
|
113
|
-
this.aliasBaseUrl = aliases.baseUrl;
|
|
114
|
-
this.aliasPaths = aliases.paths;
|
|
115
|
-
}
|
|
116
|
-
registerHooks() {
|
|
117
|
-
if (this.hooksRegistered) return;
|
|
118
|
-
this.hooksRegistered = true;
|
|
119
|
-
// Compiled code carries inline source maps; Node only applies them to stack traces when
|
|
120
|
-
// this is on. Without it, errors point at compiled line numbers (#506).
|
|
121
|
-
process.setSourceMapsEnabled(true);
|
|
122
|
-
(0, _nodemodule.registerHooks)({
|
|
123
|
-
resolve: (specifier, context, next)=>{
|
|
124
|
-
if (this.disposed) return next(specifier, context);
|
|
125
|
-
const parentUrl = context.parentURL ?? "";
|
|
126
|
-
const rewritten = (0, _rewriteservespecifier.rewriteServeSpecifier)({
|
|
127
|
-
specifier,
|
|
128
|
-
parentUrl,
|
|
129
|
-
isWatchedTs: (filePath)=>this.fileInfoMap.has(filePath),
|
|
130
|
-
resolveBare: (bare)=>_mesh.packageAliases.resolvePath(bare, this.aliasPaths, this.aliasBaseUrl),
|
|
131
|
-
versionFileUrl: this.versionFileUrl
|
|
132
|
-
}) ?? specifier;
|
|
133
|
-
const result = next(rewritten, context);
|
|
134
|
-
this.onResolved?.(result, parentUrl);
|
|
135
|
-
return result;
|
|
136
|
-
},
|
|
137
|
-
load: (url, context, next)=>{
|
|
138
|
-
if (this.disposed) return next(url, context);
|
|
139
|
-
const result = this.loadTs(url);
|
|
140
|
-
if (result != null) {
|
|
141
|
-
return {
|
|
142
|
-
format: "module",
|
|
143
|
-
source: result.source,
|
|
144
|
-
shortCircuit: true
|
|
145
|
-
};
|
|
146
|
-
}
|
|
147
|
-
return next(url, context);
|
|
148
|
-
}
|
|
149
|
-
});
|
|
150
|
-
}
|
|
151
|
-
async importEntry(absolutePath) {
|
|
152
|
-
const url = this.versionFileUrl(_io.io.pathToFileUrl(_nodepath.default.resolve(absolutePath)));
|
|
153
|
-
return Promise.resolve(url).then((p)=>/*#__PURE__*/ _interop_require_wildcard(require(p)));
|
|
154
|
-
}
|
|
155
|
-
invalidateTranspile(...absolutePaths) {
|
|
156
|
-
for (const fullPath of absolutePaths){
|
|
157
|
-
this.transpileCache.delete(fullPath);
|
|
158
|
-
this.transpiler.invalidateContentCache(new _io.FileEx({
|
|
159
|
-
fullPath
|
|
160
|
-
}));
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
dispose() {
|
|
164
|
-
this.disposed = true;
|
|
165
|
-
this.transpileCache.clear();
|
|
166
|
-
this.swcConfigs.clear();
|
|
167
|
-
this.fileInfoMap.clear();
|
|
168
|
-
this.workspace?.[Symbol.dispose]();
|
|
169
|
-
this.workspace = undefined;
|
|
170
|
-
}
|
|
171
|
-
async buildFileInfoMap(buildConfig) {
|
|
172
|
-
const projects = this.workspace?.getProjects(buildConfig) ?? [];
|
|
173
|
-
const entries = await Promise.all(projects.map(async (project)=>{
|
|
174
|
-
const files = await project.getAllFiles();
|
|
175
|
-
return files.map((file)=>[
|
|
176
|
-
file.fullPath,
|
|
177
|
-
{
|
|
178
|
-
project
|
|
179
|
-
}
|
|
180
|
-
]);
|
|
181
|
-
}));
|
|
182
|
-
return new Map(entries.flat());
|
|
183
|
-
}
|
|
184
|
-
loadTs(url) {
|
|
185
|
-
if (!url.startsWith("file:")) return null;
|
|
186
|
-
// fileURLToPath, not URL.pathname: decodes %20 and gives Windows paths, so files
|
|
187
|
-
// whose path has a space still match Mesh's list (#511).
|
|
188
|
-
const cleanPath = (0, _nodeurl.fileURLToPath)(url);
|
|
189
|
-
const fileInfo = this.fileInfoMap.get(cleanPath);
|
|
190
|
-
if (fileInfo == null) return null;
|
|
191
|
-
const cached = this.transpileCache.get(cleanPath);
|
|
192
|
-
if (cached != null) return {
|
|
193
|
-
source: cached
|
|
194
|
-
};
|
|
195
|
-
const file = new _io.FileEx({
|
|
196
|
-
fullPath: cleanPath
|
|
197
|
-
});
|
|
198
|
-
const response = this.transpiler.transformFileSync(file, _forge.BuildTargets.es6, {}, this.swcConfigFor(fileInfo.project));
|
|
199
|
-
if (response.outcome !== "success") {
|
|
200
|
-
this.logger.error(`Failed to transpile ${cleanPath}`, response);
|
|
201
|
-
throw new Error(`Failed to transpile ${cleanPath}`);
|
|
202
|
-
}
|
|
203
|
-
this.transpileCache.set(cleanPath, response.code);
|
|
204
|
-
return {
|
|
205
|
-
source: response.code
|
|
206
|
-
};
|
|
207
|
-
}
|
|
208
|
-
/**
|
|
209
|
-
* The project's SWC options, built once: rebuilding them for every file was about a quarter
|
|
210
|
-
* of load time (#513). Import specifiers are left as written, without `jsc.paths` or
|
|
211
|
-
* `resolveFully`: the resolve hook maps them to source files (aliases, `.js` to `.ts`,
|
|
212
|
-
* directory indexes), so SWC does not resolve them a second time against the disk.
|
|
213
|
-
*/ swcConfigFor(project) {
|
|
214
|
-
const cached = this.swcConfigs.get(project);
|
|
215
|
-
if (cached != null) return cached;
|
|
216
|
-
const base = this.transpiler.createBaseConfig(_forge.BuildTargets.es6, {
|
|
217
|
-
tsConfig: project.getTsConfigSync(),
|
|
218
|
-
userConfig: project.getSwcConfigSync(),
|
|
219
|
-
aliasPaths: false,
|
|
220
|
-
workspace: this.workspace
|
|
221
|
-
});
|
|
222
|
-
// `module` is the ES module config (`type: "es6"` above); the spread loses the narrowing.
|
|
223
|
-
const module = {
|
|
224
|
-
...base.module,
|
|
225
|
-
resolveFully: false
|
|
226
|
-
};
|
|
227
|
-
const config = {
|
|
228
|
-
...base,
|
|
229
|
-
module
|
|
230
|
-
};
|
|
231
|
-
this.swcConfigs.set(project, config);
|
|
232
|
-
return config;
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
SourceModuleLoader = _ts_decorate([
|
|
236
|
-
(0, _decorators.injectable)()
|
|
237
|
-
], SourceModuleLoader);
|
package/es6/bench/load.bench.js
DELETED
|
@@ -1,136 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Cold-load benchmark for flux: how long the load hook takes to compile and import a workspace
|
|
3
|
-
* whose files import each other, the way an app's do (#513).
|
|
4
|
-
*
|
|
5
|
-
* pnpm bench:flux # 8 libraries × 40 files, 10 processes
|
|
6
|
-
* BENCH_LIBS=4 BENCH_FILES=100 BENCH_RUNS=5 pnpm bench:flux
|
|
7
|
-
*
|
|
8
|
-
* Generates the workspace in a temp directory: each library re-exports a `models/` directory
|
|
9
|
-
* through its index (a directory import), each model imports the previous one (relative, with
|
|
10
|
-
* `.js`) and the previous library by package name, and has a decorated class. Each process
|
|
11
|
-
* imports the last library twice under different URL versions with a fresh loader cache, so
|
|
12
|
-
* both loads transpile every file: the first is a real cold start, the second runs with Node
|
|
13
|
-
* and SWC warmed up. Prints the median of each and the time per file.
|
|
14
|
-
*/ import { spawnSync } from "node:child_process";
|
|
15
|
-
import { mkdtempSync, mkdirSync, rmSync, writeFileSync } from "node:fs";
|
|
16
|
-
import { tmpdir } from "node:os";
|
|
17
|
-
import path from "node:path";
|
|
18
|
-
import { fileURLToPath } from "node:url";
|
|
19
|
-
import { createWorkspace } from "@decohere/forge";
|
|
20
|
-
import { SourceModuleLoader } from "../src/source-module-loader.js";
|
|
21
|
-
const libs = Number(process.env.BENCH_LIBS ?? 8);
|
|
22
|
-
const filesPerLib = Number(process.env.BENCH_FILES ?? 40);
|
|
23
|
-
const runs = Number(process.env.BENCH_RUNS ?? 10);
|
|
24
|
-
function write(file, content) {
|
|
25
|
-
mkdirSync(path.dirname(file), {
|
|
26
|
-
recursive: true
|
|
27
|
-
});
|
|
28
|
-
writeFileSync(file, content);
|
|
29
|
-
}
|
|
30
|
-
function generate(root) {
|
|
31
|
-
write(path.join(root, "package.json"), JSON.stringify({
|
|
32
|
-
name: "flux-bench",
|
|
33
|
-
type: "module"
|
|
34
|
-
}));
|
|
35
|
-
write(path.join(root, "tsconfig.json"), JSON.stringify({
|
|
36
|
-
compilerOptions: {
|
|
37
|
-
experimentalDecorators: true
|
|
38
|
-
}
|
|
39
|
-
}));
|
|
40
|
-
for(let lib = 0; lib < libs; lib++){
|
|
41
|
-
const dir = path.join(root, "projects", `lib-${lib}`);
|
|
42
|
-
write(path.join(dir, "package.json"), JSON.stringify({
|
|
43
|
-
name: `@bench/lib-${lib}`,
|
|
44
|
-
type: "module",
|
|
45
|
-
main: "src/index.ts"
|
|
46
|
-
}));
|
|
47
|
-
const previousLib = lib > 0 ? `@bench/lib-${lib - 1}` : null;
|
|
48
|
-
write(path.join(dir, "src/index.ts"), `export * from "./models";\n`);
|
|
49
|
-
const exports = [];
|
|
50
|
-
for(let file = 0; file < filesPerLib; file++){
|
|
51
|
-
const name = `Model${lib}x${file}`;
|
|
52
|
-
const previous = file > 0 ? `Model${lib}x${file - 1}` : null;
|
|
53
|
-
write(path.join(dir, "src/models", `model-${file}.ts`), [
|
|
54
|
-
previous ? `import { ${previous} } from "./model-${file - 1}.js";` : "",
|
|
55
|
-
previousLib && file === 0 ? `import { Model${lib - 1}x0 } from "${previousLib}";` : "",
|
|
56
|
-
`const tag = (_target: unknown) => {};`,
|
|
57
|
-
`@tag`,
|
|
58
|
-
`export class ${name} {`,
|
|
59
|
-
`\tpublic readonly id: number = ${file};`,
|
|
60
|
-
`\tpublic constructor(public readonly label: string = "${name}") {}`,
|
|
61
|
-
`\tpublic describe(): string { return \`\${this.label}:\${this.id}\`; }`,
|
|
62
|
-
previous ? `\tpublic previous = ${previous};` : "",
|
|
63
|
-
previousLib && file === 0 ? `\tpublic upstream = Model${lib - 1}x0;` : "",
|
|
64
|
-
`}`
|
|
65
|
-
].filter(Boolean).join("\n"));
|
|
66
|
-
exports.push(`export * from "./model-${file}.js";`);
|
|
67
|
-
}
|
|
68
|
-
write(path.join(dir, "src/models/index.ts"), `${exports.join("\n")}\n`);
|
|
69
|
-
}
|
|
70
|
-
return path.join(root, "projects", `lib-${libs - 1}`, "src/index.ts");
|
|
71
|
-
}
|
|
72
|
-
/** One sample, in this process: the first load (cold) and a second one (warm Node and SWC). */ async function sample() {
|
|
73
|
-
const root = mkdtempSync(path.join(tmpdir(), "flux-bench-"));
|
|
74
|
-
try {
|
|
75
|
-
const entry = generate(root);
|
|
76
|
-
const workspace = await createWorkspace({
|
|
77
|
-
rootDir: root
|
|
78
|
-
});
|
|
79
|
-
const loader = new SourceModuleLoader();
|
|
80
|
-
const load = async (version)=>{
|
|
81
|
-
const started = performance.now();
|
|
82
|
-
await loader.configure({
|
|
83
|
-
buildConfig: "debug",
|
|
84
|
-
workspace,
|
|
85
|
-
versionFileUrl: (fileUrl)=>`${fileUrl}?v=${version}`
|
|
86
|
-
});
|
|
87
|
-
loader.registerHooks();
|
|
88
|
-
await loader.importEntry(entry);
|
|
89
|
-
return performance.now() - started;
|
|
90
|
-
};
|
|
91
|
-
const cold = await load(1);
|
|
92
|
-
const warm = await load(2);
|
|
93
|
-
return {
|
|
94
|
-
files: [
|
|
95
|
-
...loader.sourceFilePaths()
|
|
96
|
-
].length,
|
|
97
|
-
cold,
|
|
98
|
-
warm
|
|
99
|
-
};
|
|
100
|
-
} finally{
|
|
101
|
-
rmSync(root, {
|
|
102
|
-
recursive: true,
|
|
103
|
-
force: true
|
|
104
|
-
});
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
const median = (values)=>[
|
|
108
|
-
...values
|
|
109
|
-
].sort((a, b)=>a - b)[Math.floor(values.length / 2)] ?? 0;
|
|
110
|
-
if (process.argv.includes("--sample")) {
|
|
111
|
-
console.log(JSON.stringify(await sample()));
|
|
112
|
-
} else {
|
|
113
|
-
// Each sample runs in a fresh process: Node never unloads modules, so loads in one process
|
|
114
|
-
// slow down as the heap grows and the numbers drift.
|
|
115
|
-
const results = Array.from({
|
|
116
|
-
length: runs
|
|
117
|
-
}, ()=>{
|
|
118
|
-
const child = spawnSync(process.execPath, [
|
|
119
|
-
...process.execArgv,
|
|
120
|
-
fileURLToPath(import.meta.url),
|
|
121
|
-
"--sample"
|
|
122
|
-
], {
|
|
123
|
-
encoding: "utf8",
|
|
124
|
-
env: process.env
|
|
125
|
-
});
|
|
126
|
-
if (child.status !== 0) throw new Error(`sample failed:\n${child.stderr}`);
|
|
127
|
-
const last = child.stdout.trim().split("\n").at(-1) ?? "";
|
|
128
|
-
return JSON.parse(last);
|
|
129
|
-
});
|
|
130
|
-
const files = results[0]?.files ?? 0;
|
|
131
|
-
const report = (label, values)=>{
|
|
132
|
-
const ms = median(values);
|
|
133
|
-
return `${label} ${ms.toFixed(1)} ms (${(ms / files * 1000).toFixed(0)} µs/file)`;
|
|
134
|
-
};
|
|
135
|
-
console.log(`flux load, ${files} files, median of ${runs} processes: ` + `${report("first", results.map((r)=>r.cold))}, ` + `${report("second", results.map((r)=>r.warm))}`);
|
|
136
|
-
}
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
function _ts_decorate(decorators, target, key, desc) {
|
|
2
|
-
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
-
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
-
else for(var i = decorators.length - 1; i >= 0; i--)if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
-
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
-
}
|
|
7
|
-
import { spawn } from "node:child_process";
|
|
8
|
-
import { injectable } from "@decohere/crucible/decorators";
|
|
9
|
-
import { detectPackageManager, packageManagerFromString } from "@decohere/nexus/interop";
|
|
10
|
-
import { scribe } from "@decohere/scribe";
|
|
11
|
-
export class DeferredScriptRunner {
|
|
12
|
-
logger = scribe.logger(DeferredScriptRunner.name);
|
|
13
|
-
children = [];
|
|
14
|
-
start(options) {
|
|
15
|
-
const pm = detectPackageManager(options.workspaceRoot) ?? packageManagerFromString("pnpm");
|
|
16
|
-
this.logger.info(`deferred ${options.label} — running ${pm.name} run ${options.script} in ${options.cwd}`);
|
|
17
|
-
const child = spawn(pm.name, [
|
|
18
|
-
"run",
|
|
19
|
-
options.script
|
|
20
|
-
], {
|
|
21
|
-
cwd: options.cwd,
|
|
22
|
-
stdio: "inherit",
|
|
23
|
-
env: process.env,
|
|
24
|
-
shell: false
|
|
25
|
-
});
|
|
26
|
-
child.on("exit", (code, signal)=>{
|
|
27
|
-
if (signal) return;
|
|
28
|
-
if (code != null && code !== 0) {
|
|
29
|
-
this.logger.warn(`deferred ${options.label} exited with ${code}`);
|
|
30
|
-
}
|
|
31
|
-
});
|
|
32
|
-
this.children.push(child);
|
|
33
|
-
return child;
|
|
34
|
-
}
|
|
35
|
-
async [Symbol.asyncDispose]() {
|
|
36
|
-
for (const child of this.children){
|
|
37
|
-
if (!child.killed) {
|
|
38
|
-
child.kill("SIGTERM");
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
this.children.length = 0;
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
DeferredScriptRunner = _ts_decorate([
|
|
45
|
-
injectable()
|
|
46
|
-
], DeferredScriptRunner);
|
package/es6/src/flux.js
DELETED
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
import path from "node:path";
|
|
2
|
-
import { HotReloadServer } from "./hot-reload-server.js";
|
|
3
|
-
import { SourceModuleLoader } from "./source-module-loader.js";
|
|
4
|
-
/** Process-level one-shot loader so a second `run()` reconfigures instead of stacking hooks. */ const runLoader = new SourceModuleLoader();
|
|
5
|
-
async function run(entry, options = {}) {
|
|
6
|
-
const trimmed = entry.trim();
|
|
7
|
-
if (trimmed == null || trimmed === "") {
|
|
8
|
-
throw new Error("flux.run requires an entry file path");
|
|
9
|
-
}
|
|
10
|
-
const absoluteEntry = path.resolve(trimmed);
|
|
11
|
-
await runLoader.configure({
|
|
12
|
-
workspace: options.workspace,
|
|
13
|
-
buildConfig: options.configuration ?? "debug"
|
|
14
|
-
});
|
|
15
|
-
runLoader.registerHooks();
|
|
16
|
-
process.argv = [
|
|
17
|
-
process.execPath,
|
|
18
|
-
absoluteEntry,
|
|
19
|
-
...options.args ?? []
|
|
20
|
-
];
|
|
21
|
-
return runLoader.importEntry(absoluteEntry);
|
|
22
|
-
}
|
|
23
|
-
async function serve(options = {}) {
|
|
24
|
-
const server = new HotReloadServer();
|
|
25
|
-
await server.start({
|
|
26
|
-
buildConfig: options.configuration ?? "debug",
|
|
27
|
-
project: options.project,
|
|
28
|
-
projects: options.projects,
|
|
29
|
-
workspace: options.workspace,
|
|
30
|
-
rebootDebounceMs: options.rebootDebounceMs
|
|
31
|
-
});
|
|
32
|
-
return server;
|
|
33
|
-
}
|
|
34
|
-
function dispose() {
|
|
35
|
-
runLoader.dispose();
|
|
36
|
-
}
|
|
37
|
-
export const flux = {
|
|
38
|
-
run,
|
|
39
|
-
serve,
|
|
40
|
-
dispose
|
|
41
|
-
};
|
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
import path from "node:path";
|
|
2
|
-
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
3
|
-
import { packageAliases } from "@decohere/mesh";
|
|
4
|
-
/**
|
|
5
|
-
* Map a resolve-hook specifier to a versioned watched `.ts` file URL.
|
|
6
|
-
* Covers relative `.js` / `.ts` / extensionless imports, directory imports (`./models` is
|
|
7
|
-
* `./models/index.ts`), and bare workspace package names and subpaths. Flux compiles without
|
|
8
|
-
* SWC's own path resolution, so this is the only place imports are mapped to sources (#513).
|
|
9
|
-
*/ export function rewriteServeSpecifier(options) {
|
|
10
|
-
const { specifier, parentUrl, isWatchedTs, resolveBare, versionFileUrl } = options;
|
|
11
|
-
const relativeTs = resolveRelativeWatchedTs(specifier, parentUrl, isWatchedTs);
|
|
12
|
-
if (relativeTs != null) {
|
|
13
|
-
return versionFileUrl(pathToFileURL(relativeTs).toString());
|
|
14
|
-
}
|
|
15
|
-
const bareTarget = resolveBare(specifier);
|
|
16
|
-
const bareTs = bareTarget == null ? null : watchedTs(bareTarget, isWatchedTs);
|
|
17
|
-
if (bareTs != null) {
|
|
18
|
-
return versionFileUrl(pathToFileURL(bareTs).toString());
|
|
19
|
-
}
|
|
20
|
-
return null;
|
|
21
|
-
}
|
|
22
|
-
/**
|
|
23
|
-
* The watched `.ts` file a path names: itself (with `.js` read as `.ts`, or `.ts` added), else
|
|
24
|
-
* the `index.ts` of the directory it names. A file wins over a directory of the same name.
|
|
25
|
-
*/ function watchedTs(filePath, isWatchedTs) {
|
|
26
|
-
const withoutSlash = filePath.replace(/[/\\]+$/, "");
|
|
27
|
-
const stem = withoutSlash.replace(/\.(js|ts)$/, "");
|
|
28
|
-
// From the stem: Mesh's alias lookup has already added `.ts` to a subpath that names a
|
|
29
|
-
// directory (`@lib/models` arrives as `…/models.ts`).
|
|
30
|
-
const candidates = [
|
|
31
|
-
`${stem}.ts`,
|
|
32
|
-
path.join(stem, "index.ts")
|
|
33
|
-
];
|
|
34
|
-
return candidates.find((candidate)=>isWatchedTs(candidate)) ?? null;
|
|
35
|
-
}
|
|
36
|
-
function resolveRelativeWatchedTs(specifier, parentUrl, isWatchedTs) {
|
|
37
|
-
if (packageAliases.isBareSpecifier(specifier)) return null;
|
|
38
|
-
if (!(specifier.startsWith(".") || specifier.startsWith("/"))) return null;
|
|
39
|
-
const parentClean = parentUrl.split("?")[0];
|
|
40
|
-
if (parentClean == null || parentClean === "") return null;
|
|
41
|
-
let resolved;
|
|
42
|
-
try {
|
|
43
|
-
resolved = new URL(specifier, parentClean);
|
|
44
|
-
} catch {
|
|
45
|
-
return null;
|
|
46
|
-
}
|
|
47
|
-
if (resolved.protocol !== "file:") return null;
|
|
48
|
-
return watchedTs(fileURLToPath(resolved), isWatchedTs);
|
|
49
|
-
}
|
package/es6/src/run.action.js
DELETED
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
function _ts_decorate(decorators, target, key, desc) {
|
|
2
|
-
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
-
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
-
else for(var i = decorators.length - 1; i >= 0; i--)if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
-
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
-
}
|
|
7
|
-
function _ts_metadata(k, v) {
|
|
8
|
-
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
9
|
-
}
|
|
10
|
-
import { injectable } from "@decohere/crucible/decorators";
|
|
11
|
-
import { Workspace } from "@decohere/mesh";
|
|
12
|
-
import { ActionResponse } from "@decohere/nexus/cli";
|
|
13
|
-
import { scribe } from "@decohere/scribe";
|
|
14
|
-
import { flux } from "./flux.js";
|
|
15
|
-
export class RunAction {
|
|
16
|
-
workspace;
|
|
17
|
-
logger = scribe.logger(RunAction.name);
|
|
18
|
-
constructor(workspace){
|
|
19
|
-
this.workspace = workspace;
|
|
20
|
-
}
|
|
21
|
-
async run(options) {
|
|
22
|
-
this.logger.trace(`Running ${options.entry}`);
|
|
23
|
-
await flux.run(options.entry, {
|
|
24
|
-
configuration: options.configuration,
|
|
25
|
-
args: options.args,
|
|
26
|
-
workspace: this.workspace
|
|
27
|
-
});
|
|
28
|
-
return ActionResponse.Success(RunAction.name);
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
RunAction = _ts_decorate([
|
|
32
|
-
injectable(),
|
|
33
|
-
_ts_metadata("design:type", Function),
|
|
34
|
-
_ts_metadata("design:paramtypes", [
|
|
35
|
-
typeof Workspace === "undefined" ? Object : Workspace
|
|
36
|
-
])
|
|
37
|
-
], RunAction);
|
package/es6/src/run.command.js
DELETED
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
import { ConfigurationOption, DecohereCommand } from "@decohere/nexus/cli";
|
|
2
|
-
import { RunAction } from "./run.action.js";
|
|
3
|
-
export class RunCommand extends DecohereCommand {
|
|
4
|
-
get actions() {
|
|
5
|
-
return [
|
|
6
|
-
RunAction
|
|
7
|
-
];
|
|
8
|
-
}
|
|
9
|
-
constructor(name){
|
|
10
|
-
super(name);
|
|
11
|
-
this.description("Compile and run a TypeScript entry on the fly (no watch / HMR)");
|
|
12
|
-
this.argument("<entry>", "Path to the TypeScript entry file");
|
|
13
|
-
this.argument("[args...]", "Arguments forwarded to the entry after rewriting argv");
|
|
14
|
-
this.addOption(new ConfigurationOption("debug"));
|
|
15
|
-
}
|
|
16
|
-
/**
|
|
17
|
-
* Commander passes positionals before options when `<entry> [args...]` is declared.
|
|
18
|
-
* The CLI host ModuleFactory expects `(opts, cmd)` — normalize and stash entry/args on opts.
|
|
19
|
-
*/ action(fn) {
|
|
20
|
-
return super.action((...args)=>{
|
|
21
|
-
const cmd = args.at(-1);
|
|
22
|
-
const opts = args.at(-2);
|
|
23
|
-
const { entry, entryArgs } = normalizeRunPositionals(args.slice(0, -2));
|
|
24
|
-
cmd.setOptionValue("entry", entry);
|
|
25
|
-
cmd.setOptionValue("args", entryArgs);
|
|
26
|
-
return fn(opts, cmd);
|
|
27
|
-
});
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
/** Commander yields `[entry, args[]]` or sometimes a flat list depending on arity. */ function normalizeRunPositionals(positionals) {
|
|
31
|
-
if (positionals.length === 0) {
|
|
32
|
-
return {
|
|
33
|
-
entry: "",
|
|
34
|
-
entryArgs: []
|
|
35
|
-
};
|
|
36
|
-
}
|
|
37
|
-
const first = positionals[0];
|
|
38
|
-
if (typeof first !== "string" || first === "") {
|
|
39
|
-
return {
|
|
40
|
-
entry: "",
|
|
41
|
-
entryArgs: []
|
|
42
|
-
};
|
|
43
|
-
}
|
|
44
|
-
const second = positionals[1];
|
|
45
|
-
if (Array.isArray(second)) {
|
|
46
|
-
return {
|
|
47
|
-
entry: first,
|
|
48
|
-
entryArgs: second.filter((s)=>typeof s === "string")
|
|
49
|
-
};
|
|
50
|
-
}
|
|
51
|
-
return {
|
|
52
|
-
entry: first,
|
|
53
|
-
entryArgs: positionals.slice(1).filter((s)=>typeof s === "string" && s !== "")
|
|
54
|
-
};
|
|
55
|
-
}
|