domflax 0.1.2 → 0.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +25 -8
- package/dist/{chunk-DNHOGPYV.js → chunk-3Z5ZWLXX.js} +407 -51
- package/dist/chunk-3Z5ZWLXX.js.map +1 -0
- package/dist/{chunk-DOQEBGWB.js → chunk-5FWENSD2.js} +63 -8
- package/dist/chunk-5FWENSD2.js.map +1 -0
- package/dist/chunk-EVENAJYI.js +336 -0
- package/dist/chunk-EVENAJYI.js.map +1 -0
- package/dist/{chunk-DWLB7FRR.js → chunk-H5KTGI3A.js} +153 -7
- package/dist/chunk-H5KTGI3A.js.map +1 -0
- package/dist/{chunk-6WVVF6AD.js → chunk-U5GOONKV.js} +5 -2
- package/dist/{chunk-6WVVF6AD.js.map → chunk-U5GOONKV.js.map} +1 -1
- package/dist/cli.cjs +995 -166
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +245 -229
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +614 -68
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +34 -18
- package/dist/index.d.ts +34 -18
- package/dist/index.js +4 -4
- package/dist/{pattern-F5xBtIE-.d.cts → pattern-CP9_HpVK.d.cts} +1 -1
- package/dist/{pattern-CV607P87.d.ts → pattern-CYgsv-jO.d.ts} +1 -1
- package/dist/pattern-kit.cjs.map +1 -1
- package/dist/pattern-kit.d.cts +2 -2
- package/dist/pattern-kit.d.ts +2 -2
- package/dist/pattern-kit.js +2 -2
- package/dist/{resolve-ops-DIwEelH-.d.ts → resolve-ops-Ci7LgYHC.d.cts} +9 -0
- package/dist/{resolve-ops-DIwEelH-.d.cts → resolve-ops-Ci7LgYHC.d.ts} +9 -0
- package/dist/verify.d.cts +1 -1
- package/dist/verify.d.ts +1 -1
- package/dist/verify.js +1 -1
- package/dist/webpack-loader.cjs +614 -68
- package/dist/webpack-loader.cjs.map +1 -1
- package/dist/webpack-loader.d.cts +2 -2
- package/dist/webpack-loader.d.ts +2 -2
- package/dist/webpack-loader.js +4 -4
- package/dist/worker.cjs +5955 -0
- package/dist/worker.cjs.map +1 -0
- package/dist/worker.d.cts +2 -0
- package/dist/worker.d.ts +2 -0
- package/dist/worker.js +72 -0
- package/dist/worker.js.map +1 -0
- package/package.json +4 -2
- package/dist/chunk-DNHOGPYV.js.map +0 -1
- package/dist/chunk-DOQEBGWB.js.map +0 -1
- package/dist/chunk-DWLB7FRR.js.map +0 -1
package/dist/cli.js
CHANGED
|
@@ -1,23 +1,18 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
import
|
|
10
|
-
buildSelectorIndex,
|
|
11
|
-
createSyntheticSink,
|
|
12
|
-
normalizer,
|
|
13
|
-
runPasses,
|
|
14
|
-
syncClassesFromComputed
|
|
15
|
-
} from "./chunk-DWLB7FRR.js";
|
|
3
|
+
createTransform,
|
|
4
|
+
destinationFor,
|
|
5
|
+
isGitClean,
|
|
6
|
+
planWrites
|
|
7
|
+
} from "./chunk-EVENAJYI.js";
|
|
8
|
+
import "./chunk-3Z5ZWLXX.js";
|
|
9
|
+
import "./chunk-H5KTGI3A.js";
|
|
16
10
|
import {
|
|
17
11
|
__commonJS,
|
|
12
|
+
__dirname,
|
|
18
13
|
__toESM,
|
|
19
14
|
init_esm_shims
|
|
20
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-U5GOONKV.js";
|
|
21
16
|
|
|
22
17
|
// ../../node_modules/sisteransi/src/index.js
|
|
23
18
|
var require_src = __commonJS({
|
|
@@ -172,6 +167,14 @@ function toSafety(raw) {
|
|
|
172
167
|
if (n === 0 || n === 1 || n === 2 || n === 3) return n;
|
|
173
168
|
throw new Error(`domflax: invalid --safety "${raw}" (expected 0, 1, 2 or 3)`);
|
|
174
169
|
}
|
|
170
|
+
function toPositiveInt(raw, flag) {
|
|
171
|
+
if (raw === void 0) return null;
|
|
172
|
+
const n = Number(raw);
|
|
173
|
+
if (!Number.isInteger(n) || n < 1) {
|
|
174
|
+
throw new Error(`domflax: invalid ${flag} "${raw}" (expected a positive integer)`);
|
|
175
|
+
}
|
|
176
|
+
return n;
|
|
177
|
+
}
|
|
175
178
|
function parseInvocation(argv) {
|
|
176
179
|
const { values, positionals } = parseArgs({
|
|
177
180
|
args: argv,
|
|
@@ -187,7 +190,9 @@ function parseInvocation(argv) {
|
|
|
187
190
|
"no-interactive": { type: "boolean", default: false },
|
|
188
191
|
yes: { type: "boolean", short: "y", default: false },
|
|
189
192
|
safety: { type: "string" },
|
|
190
|
-
"project-root": { type: "string" }
|
|
193
|
+
"project-root": { type: "string" },
|
|
194
|
+
"max-memory": { type: "string" },
|
|
195
|
+
concurrency: { type: "string" }
|
|
191
196
|
}
|
|
192
197
|
});
|
|
193
198
|
const provider = values.provider ?? DEFAULT_PROVIDER;
|
|
@@ -206,7 +211,9 @@ function parseInvocation(argv) {
|
|
|
206
211
|
interactive: values["no-interactive"] !== true && values.yes !== true,
|
|
207
212
|
passes: null,
|
|
208
213
|
safety: toSafety(values.safety),
|
|
209
|
-
projectRoot: values["project-root"] ?? null
|
|
214
|
+
projectRoot: values["project-root"] ?? null,
|
|
215
|
+
maxMemory: toPositiveInt(values["max-memory"], "--max-memory"),
|
|
216
|
+
concurrency: toPositiveInt(values.concurrency, "--concurrency")
|
|
210
217
|
};
|
|
211
218
|
}
|
|
212
219
|
function shouldPrompt(options, isTty) {
|
|
@@ -230,218 +237,219 @@ var USAGE = [
|
|
|
230
237
|
" --dangerously-overwrite-source overwrite source in place (needs a clean git tree)",
|
|
231
238
|
" --no-git-check skip the clean-git-tree gate",
|
|
232
239
|
" --safety <0|1|2|3> optimization aggressiveness (default: 2)",
|
|
240
|
+
" --max-memory <MB> memory budget; caps pool RAM AND parallelism (default: ~70% free RAM)",
|
|
241
|
+
" --concurrency <N> max parallel workers (still clamped by --max-memory)",
|
|
233
242
|
" --yes, --no-interactive never launch the wizard (CI-safe)",
|
|
234
243
|
"",
|
|
244
|
+
"Many files are processed across CPU cores by a memory-bounded worker pool; small jobs run inline.",
|
|
235
245
|
"With no paths in an interactive terminal, a guided wizard launches."
|
|
236
246
|
].join("\n");
|
|
237
247
|
|
|
238
|
-
// ../cli/src/
|
|
248
|
+
// ../cli/src/pool.ts
|
|
239
249
|
init_esm_shims();
|
|
240
|
-
import {
|
|
250
|
+
import { existsSync } from "fs";
|
|
251
|
+
import * as os from "os";
|
|
241
252
|
import * as path from "path";
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
253
|
+
import { fileURLToPath } from "url";
|
|
254
|
+
import { Worker } from "worker_threads";
|
|
255
|
+
var PER_WORKER_MB = 160;
|
|
256
|
+
var MIN_OLD_GEN_MB = 64;
|
|
257
|
+
function emptyTotals() {
|
|
258
|
+
return { files: 0, changed: 0, nodesRemoved: 0, classesSaved: 0, bytesSaved: 0 };
|
|
245
259
|
}
|
|
246
|
-
function
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
});
|
|
253
|
-
return out.trim().length === 0;
|
|
254
|
-
} catch {
|
|
255
|
-
return false;
|
|
256
|
-
}
|
|
257
|
-
}
|
|
258
|
-
function planWrites(options, gitClean) {
|
|
259
|
-
if (options.dangerouslyOverwriteSource) {
|
|
260
|
-
if (!options.noGitCheck && !gitClean) {
|
|
261
|
-
return {
|
|
262
|
-
ok: false,
|
|
263
|
-
error: "refusing --dangerously-overwrite-source: git working tree is not clean. Commit or stash first, or pass --no-git-check to override."
|
|
264
|
-
};
|
|
265
|
-
}
|
|
266
|
-
return { ok: true, value: { mode: "overwrite-source", outDir: null } };
|
|
267
|
-
}
|
|
268
|
-
const outDir = path.resolve(options.out ?? "domflax-out");
|
|
269
|
-
return { ok: true, value: { mode: "out-dir", outDir } };
|
|
270
|
-
}
|
|
271
|
-
function destinationFor(file, inputRoot, plan) {
|
|
272
|
-
const absFile = path.resolve(file);
|
|
273
|
-
if (plan.mode === "overwrite-source") {
|
|
274
|
-
return { ok: true, value: absFile };
|
|
275
|
-
}
|
|
276
|
-
const outDir = plan.outDir;
|
|
277
|
-
const rel = path.relative(inputRoot, absFile);
|
|
278
|
-
const safeRel = rel === "" || rel.startsWith("..") || path.isAbsolute(rel) ? path.basename(absFile) : rel;
|
|
279
|
-
const dest = path.join(outDir, safeRel);
|
|
280
|
-
if (path.resolve(dest) === absFile && !isDisposablePath(absFile)) {
|
|
281
|
-
return {
|
|
282
|
-
ok: false,
|
|
283
|
-
error: `refusing to overwrite source file ${absFile}: the output path resolves onto the source. Choose a different --out, or pass --dangerously-overwrite-source (with a clean git tree).`
|
|
284
|
-
};
|
|
285
|
-
}
|
|
286
|
-
return { ok: true, value: dest };
|
|
260
|
+
function addStats(totals, stats, changed) {
|
|
261
|
+
totals.files += 1;
|
|
262
|
+
if (changed) totals.changed += 1;
|
|
263
|
+
totals.nodesRemoved += stats.nodesRemoved;
|
|
264
|
+
totals.classesSaved += stats.classesSaved;
|
|
265
|
+
totals.bytesSaved += stats.bytesSaved;
|
|
287
266
|
}
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
init_esm_shims();
|
|
291
|
-
function buildResolver(provider, css, projectRoot) {
|
|
292
|
-
if (provider === "custom") {
|
|
293
|
-
return createCssResolver([], { files: css, projectRoot });
|
|
294
|
-
}
|
|
295
|
-
return createTailwindResolver({ projectRoot });
|
|
267
|
+
function clamp(n, lo, hi) {
|
|
268
|
+
return Math.max(lo, Math.min(hi, n));
|
|
296
269
|
}
|
|
297
|
-
function
|
|
298
|
-
const
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
bucket.push(p2);
|
|
307
|
-
}
|
|
308
|
-
const passes = [];
|
|
309
|
-
for (const [phase, pats] of byPhase) {
|
|
310
|
-
passes.push({ phase, category: `${phase}/builtin`, patterns: pats });
|
|
311
|
-
}
|
|
312
|
-
return passes;
|
|
270
|
+
function computeWorkerCount(options) {
|
|
271
|
+
const cpus2 = Math.max(1, os.cpus().length);
|
|
272
|
+
const freeMB = Math.floor(os.freemem() / (1024 * 1024));
|
|
273
|
+
const budgetMB = Math.max(PER_WORKER_MB, options.maxMemory ?? Math.floor(freeMB * 0.7));
|
|
274
|
+
const byMemory = Math.max(1, Math.floor(budgetMB / PER_WORKER_MB));
|
|
275
|
+
const target = options.concurrency ?? Math.max(1, cpus2 - 1);
|
|
276
|
+
const workers = clamp(Math.min(target, byMemory), 1, byMemory);
|
|
277
|
+
const perWorkerCapMB = Math.max(MIN_OLD_GEN_MB, Math.floor(budgetMB / workers));
|
|
278
|
+
return { workers, budgetMB, perWorkerCapMB };
|
|
313
279
|
}
|
|
314
|
-
function
|
|
315
|
-
|
|
316
|
-
const set = new Set(names);
|
|
317
|
-
return builtinPatterns.filter((p2) => set.has(p2.name));
|
|
280
|
+
function inlineThreshold(workers) {
|
|
281
|
+
return Math.max(4, 2 * workers);
|
|
318
282
|
}
|
|
319
|
-
function
|
|
320
|
-
|
|
321
|
-
const lower = clean.toLowerCase();
|
|
322
|
-
if (lower.endsWith(".tsx")) return "tsx";
|
|
323
|
-
if (lower.endsWith(".jsx")) return "jsx";
|
|
324
|
-
return null;
|
|
283
|
+
function shouldUsePool(fileCount, plan) {
|
|
284
|
+
return plan.workers > 1 && fileCount > inlineThreshold(plan.workers);
|
|
325
285
|
}
|
|
326
|
-
function
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
total += m2[1].split(/\s+/).filter((t) => t.length > 0).length;
|
|
286
|
+
function moduleDir() {
|
|
287
|
+
try {
|
|
288
|
+
return path.dirname(fileURLToPath(import.meta.url));
|
|
289
|
+
} catch {
|
|
290
|
+
return typeof __dirname !== "undefined" ? __dirname : process.cwd();
|
|
332
291
|
}
|
|
333
|
-
return total;
|
|
334
|
-
}
|
|
335
|
-
function bytes(s) {
|
|
336
|
-
return Buffer.byteLength(s, "utf8");
|
|
337
292
|
}
|
|
338
|
-
function
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
bytesBefore: bytes(code),
|
|
351
|
-
bytesAfter: bytes(code),
|
|
352
|
-
bytesSaved: 0
|
|
353
|
-
}
|
|
354
|
-
};
|
|
293
|
+
function resolveWorkerPath() {
|
|
294
|
+
const dir = moduleDir();
|
|
295
|
+
const candidates = [
|
|
296
|
+
path.join(dir, "worker.cjs"),
|
|
297
|
+
path.join(dir, "worker.js"),
|
|
298
|
+
path.join(dir, "..", "dist", "worker.cjs"),
|
|
299
|
+
path.join(dir, "..", "dist", "worker.js")
|
|
300
|
+
];
|
|
301
|
+
for (const c of candidates) {
|
|
302
|
+
if (existsSync(c)) return c;
|
|
303
|
+
}
|
|
304
|
+
return candidates[0];
|
|
355
305
|
}
|
|
356
|
-
function
|
|
357
|
-
const
|
|
358
|
-
const
|
|
359
|
-
const
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
306
|
+
function runPool(files, init, plan, onWrote) {
|
|
307
|
+
const workerPath = resolveWorkerPath();
|
|
308
|
+
const totals = emptyTotals();
|
|
309
|
+
const wrote = [];
|
|
310
|
+
const errors = [];
|
|
311
|
+
let failures = 0;
|
|
312
|
+
const budgetBytes = plan.budgetMB * 1024 * 1024;
|
|
313
|
+
let nextIndex = 0;
|
|
314
|
+
let completed = 0;
|
|
315
|
+
const total = files.length;
|
|
316
|
+
let respawns = 0;
|
|
317
|
+
const maxRespawns = total + plan.workers + 8;
|
|
318
|
+
return new Promise((resolve3) => {
|
|
319
|
+
const handles = /* @__PURE__ */ new Set();
|
|
320
|
+
const finishIfDone = () => {
|
|
321
|
+
if (completed < total) return;
|
|
322
|
+
for (const h2 of handles) {
|
|
323
|
+
if (!h2.dead) {
|
|
324
|
+
try {
|
|
325
|
+
h2.worker.postMessage({ type: "stop" });
|
|
326
|
+
} catch {
|
|
327
|
+
}
|
|
328
|
+
void h2.worker.terminate();
|
|
329
|
+
}
|
|
368
330
|
}
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
const nodesIn = doc.nodes.size;
|
|
372
|
-
for (const node of doc.nodes.values()) node.meta.safetyFloor = 3;
|
|
373
|
-
const ctx = {
|
|
374
|
-
doc,
|
|
375
|
-
safetyCeiling: options.safety,
|
|
376
|
-
normalizer,
|
|
377
|
-
// Real CSS-selector-safety index from the active resolver (custom-CSS reports combinator /
|
|
378
|
-
// structural-pseudo coupling; Tailwind has none → null index, behaviour unchanged).
|
|
379
|
-
selectors: buildSelectorIndex(doc, resolver),
|
|
380
|
-
resolver,
|
|
381
|
-
gate
|
|
331
|
+
handles.clear();
|
|
332
|
+
resolve3({ totals, failures, wrote, errors });
|
|
382
333
|
};
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
bytesBefore: bytes(code),
|
|
409
|
-
bytesAfter: bytes(out),
|
|
410
|
-
bytesSaved: bytes(code) - bytes(out)
|
|
334
|
+
const recordFailure = (file, error) => {
|
|
335
|
+
failures += 1;
|
|
336
|
+
completed += 1;
|
|
337
|
+
errors.push({ path: file, error });
|
|
338
|
+
};
|
|
339
|
+
const dispatch = (h2) => {
|
|
340
|
+
if (h2.dead) return;
|
|
341
|
+
if (nextIndex >= total) {
|
|
342
|
+
h2.current = null;
|
|
343
|
+
try {
|
|
344
|
+
h2.worker.postMessage({ type: "stop" });
|
|
345
|
+
} catch {
|
|
346
|
+
}
|
|
347
|
+
return;
|
|
348
|
+
}
|
|
349
|
+
if (process.memoryUsage().rss > budgetBytes) {
|
|
350
|
+
setTimeout(() => dispatch(h2), 25);
|
|
351
|
+
return;
|
|
352
|
+
}
|
|
353
|
+
const file = files[nextIndex++];
|
|
354
|
+
h2.current = file;
|
|
355
|
+
try {
|
|
356
|
+
h2.worker.postMessage({ type: "file", path: file });
|
|
357
|
+
} catch {
|
|
358
|
+
onWorkerDown(h2);
|
|
411
359
|
}
|
|
412
360
|
};
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
361
|
+
const onMessage = (h2, msg) => {
|
|
362
|
+
if (msg.type === "ready") {
|
|
363
|
+
h2.ready = true;
|
|
364
|
+
dispatch(h2);
|
|
365
|
+
return;
|
|
366
|
+
}
|
|
367
|
+
h2.current = null;
|
|
368
|
+
if (msg.ok) {
|
|
369
|
+
addStats(totals, msg.stats, msg.changed);
|
|
370
|
+
if (msg.wrote) {
|
|
371
|
+
wrote.push(msg.wrote);
|
|
372
|
+
onWrote?.(msg.wrote);
|
|
373
|
+
}
|
|
374
|
+
} else {
|
|
375
|
+
failures += 1;
|
|
376
|
+
errors.push({ path: msg.path, error: msg.error });
|
|
377
|
+
}
|
|
378
|
+
completed += 1;
|
|
379
|
+
if (completed >= total) {
|
|
380
|
+
finishIfDone();
|
|
381
|
+
return;
|
|
382
|
+
}
|
|
383
|
+
dispatch(h2);
|
|
384
|
+
};
|
|
385
|
+
const drainRemaining = (reason) => {
|
|
386
|
+
while (nextIndex < total) recordFailure(files[nextIndex++], reason);
|
|
387
|
+
finishIfDone();
|
|
388
|
+
};
|
|
389
|
+
const onWorkerDown = (h2) => {
|
|
390
|
+
if (h2.dead) return;
|
|
391
|
+
h2.dead = true;
|
|
392
|
+
handles.delete(h2);
|
|
393
|
+
const lost = h2.current;
|
|
394
|
+
h2.current = null;
|
|
395
|
+
if (lost !== null) recordFailure(lost, "worker crashed while processing this file");
|
|
396
|
+
void h2.worker.terminate();
|
|
397
|
+
if (completed >= total) {
|
|
398
|
+
finishIfDone();
|
|
399
|
+
return;
|
|
400
|
+
}
|
|
401
|
+
if (nextIndex >= total) {
|
|
402
|
+
if (handles.size === 0) finishIfDone();
|
|
403
|
+
return;
|
|
404
|
+
}
|
|
405
|
+
if (respawns < maxRespawns) {
|
|
406
|
+
respawns += 1;
|
|
407
|
+
spawn();
|
|
408
|
+
} else if (handles.size === 0) {
|
|
409
|
+
drainRemaining("worker pool exhausted its respawn budget (memory cap too small?)");
|
|
410
|
+
}
|
|
411
|
+
};
|
|
412
|
+
const spawn = () => {
|
|
413
|
+
let worker;
|
|
414
|
+
try {
|
|
415
|
+
worker = new Worker(workerPath, {
|
|
416
|
+
workerData: init,
|
|
417
|
+
resourceLimits: { maxOldGenerationSizeMb: plan.perWorkerCapMB }
|
|
418
|
+
});
|
|
419
|
+
} catch {
|
|
420
|
+
if (nextIndex < total) recordFailure(files[nextIndex++], "failed to spawn worker");
|
|
421
|
+
if (completed >= total) finishIfDone();
|
|
422
|
+
else if (handles.size === 0 && nextIndex < total) spawn();
|
|
423
|
+
return;
|
|
424
|
+
}
|
|
425
|
+
const h2 = { worker, current: null, ready: false, dead: false };
|
|
426
|
+
handles.add(h2);
|
|
427
|
+
worker.on("message", (m2) => onMessage(h2, m2));
|
|
428
|
+
worker.on("error", () => onWorkerDown(h2));
|
|
429
|
+
worker.on("exit", (code) => {
|
|
430
|
+
if (code !== 0) onWorkerDown(h2);
|
|
431
|
+
});
|
|
432
|
+
};
|
|
433
|
+
const initial = Math.min(plan.workers, total);
|
|
434
|
+
for (let i = 0; i < initial; i++) spawn();
|
|
435
|
+
if (initial === 0) finishIfDone();
|
|
436
|
+
});
|
|
424
437
|
}
|
|
425
438
|
|
|
426
439
|
// ../cli/src/walk.ts
|
|
427
440
|
init_esm_shims();
|
|
428
441
|
import * as fs from "fs";
|
|
429
442
|
import * as path2 from "path";
|
|
430
|
-
var SUPPORTED_EXTS = [".jsx", ".tsx"];
|
|
431
|
-
var HTML_EXTS = [".html", ".htm"];
|
|
443
|
+
var SUPPORTED_EXTS = [".jsx", ".tsx", ".html", ".htm"];
|
|
432
444
|
var SKIP_DIRS = /* @__PURE__ */ new Set(["node_modules", ".git", "domflax-out"]);
|
|
433
445
|
function isSupported(file) {
|
|
434
446
|
const lower = file.toLowerCase();
|
|
435
447
|
return SUPPORTED_EXTS.some((ext) => lower.endsWith(ext));
|
|
436
448
|
}
|
|
437
|
-
function isHtml(file) {
|
|
438
|
-
const lower = file.toLowerCase();
|
|
439
|
-
return HTML_EXTS.some((ext) => lower.endsWith(ext));
|
|
440
|
-
}
|
|
441
449
|
function hasGlobMagic(p2) {
|
|
442
450
|
return /[*?[\]{}]/.test(p2);
|
|
443
451
|
}
|
|
444
|
-
function walkDir(dir, out
|
|
452
|
+
function walkDir(dir, out) {
|
|
445
453
|
let entries;
|
|
446
454
|
try {
|
|
447
455
|
entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
@@ -452,10 +460,9 @@ function walkDir(dir, out, counts) {
|
|
|
452
460
|
const full = path2.join(dir, entry.name);
|
|
453
461
|
if (entry.isDirectory()) {
|
|
454
462
|
if (SKIP_DIRS.has(entry.name)) continue;
|
|
455
|
-
walkDir(full, out
|
|
463
|
+
walkDir(full, out);
|
|
456
464
|
} else if (entry.isFile()) {
|
|
457
465
|
if (isSupported(entry.name)) out.push(full);
|
|
458
|
-
else if (isHtml(entry.name)) counts.html += 1;
|
|
459
466
|
}
|
|
460
467
|
}
|
|
461
468
|
}
|
|
@@ -466,7 +473,6 @@ function globSyncMaybe() {
|
|
|
466
473
|
function discoverInputs(paths) {
|
|
467
474
|
const files = [];
|
|
468
475
|
const warnings = [];
|
|
469
|
-
const counts = { html: 0 };
|
|
470
476
|
const seen = /* @__PURE__ */ new Set();
|
|
471
477
|
const push = (f) => {
|
|
472
478
|
const abs = path2.resolve(f);
|
|
@@ -490,12 +496,11 @@ function discoverInputs(paths) {
|
|
|
490
496
|
stat = null;
|
|
491
497
|
}
|
|
492
498
|
if (stat?.isDirectory()) {
|
|
493
|
-
walkDir(path2.resolve(p2), files
|
|
499
|
+
walkDir(path2.resolve(p2), files);
|
|
494
500
|
continue;
|
|
495
501
|
}
|
|
496
502
|
if (stat?.isFile()) {
|
|
497
503
|
if (isSupported(p2)) push(p2);
|
|
498
|
-
else if (isHtml(p2)) counts.html += 1;
|
|
499
504
|
else warnings.push(`unsupported file type, skipped: ${p2}`);
|
|
500
505
|
continue;
|
|
501
506
|
}
|
|
@@ -507,8 +512,7 @@ function discoverInputs(paths) {
|
|
|
507
512
|
}
|
|
508
513
|
const matched = glob(p2);
|
|
509
514
|
const supported = matched.filter(isSupported);
|
|
510
|
-
|
|
511
|
-
if (supported.length === 0) warnings.push(`no .jsx/.tsx files matched: ${p2}`);
|
|
515
|
+
if (supported.length === 0) warnings.push(`no .jsx/.tsx/.html files matched: ${p2}`);
|
|
512
516
|
for (const m2 of supported) push(m2);
|
|
513
517
|
continue;
|
|
514
518
|
}
|
|
@@ -523,11 +527,6 @@ function discoverInputs(paths) {
|
|
|
523
527
|
deduped.push(abs);
|
|
524
528
|
}
|
|
525
529
|
}
|
|
526
|
-
if (deduped.length === 0 && counts.html > 0) {
|
|
527
|
-
warnings.push(
|
|
528
|
-
`found ${counts.html} .html file${counts.html === 1 ? "" : "s"} but HTML optimization isn't supported yet (domflax currently optimizes .jsx/.tsx source; HTML is on the roadmap: https://github.com/Krishnesh-Mishra/domflax#roadmap).`
|
|
529
|
-
);
|
|
530
|
-
}
|
|
531
530
|
return { files: deduped, inputRoot, warnings };
|
|
532
531
|
}
|
|
533
532
|
|
|
@@ -1305,13 +1304,6 @@ async function runWizard(base) {
|
|
|
1305
1304
|
}
|
|
1306
1305
|
|
|
1307
1306
|
// ../cli/src/index.ts
|
|
1308
|
-
function addStats(totals, stats, changed) {
|
|
1309
|
-
totals.files += 1;
|
|
1310
|
-
if (changed) totals.changed += 1;
|
|
1311
|
-
totals.nodesRemoved += stats.nodesRemoved;
|
|
1312
|
-
totals.classesSaved += stats.classesSaved;
|
|
1313
|
-
totals.bytesSaved += stats.bytesSaved;
|
|
1314
|
-
}
|
|
1315
1307
|
function printReport(totals) {
|
|
1316
1308
|
console.log("");
|
|
1317
1309
|
console.log("domflax report");
|
|
@@ -1321,23 +1313,8 @@ function printReport(totals) {
|
|
|
1321
1313
|
console.log(` classes saved : ${totals.classesSaved}`);
|
|
1322
1314
|
console.log(` bytes saved : ${totals.bytesSaved}`);
|
|
1323
1315
|
}
|
|
1324
|
-
|
|
1325
|
-
const { files, inputRoot, warnings } = discoverInputs(options.paths);
|
|
1326
|
-
for (const w2 of warnings) console.error(`domflax: ${w2}`);
|
|
1327
|
-
if (files.length === 0) {
|
|
1328
|
-
console.error("domflax: no .jsx/.tsx files found for the given paths");
|
|
1329
|
-
return { exitCode: 1 };
|
|
1330
|
-
}
|
|
1331
|
-
const projectRoot = options.projectRoot ?? process.cwd();
|
|
1332
|
-
const gitClean = options.dangerouslyOverwriteSource && !options.noGitCheck ? isGitClean(projectRoot) : true;
|
|
1333
|
-
const planned = planWrites(options, gitClean);
|
|
1334
|
-
if (!planned.ok) {
|
|
1335
|
-
console.error(`domflax: ${planned.error}`);
|
|
1336
|
-
return { exitCode: 1 };
|
|
1337
|
-
}
|
|
1338
|
-
const plan = planned.value;
|
|
1316
|
+
function runInline(files, options, inputRoot, plan, totals) {
|
|
1339
1317
|
const transform = createTransform(options);
|
|
1340
|
-
const totals = { files: 0, changed: 0, nodesRemoved: 0, classesSaved: 0, bytesSaved: 0 };
|
|
1341
1318
|
let failures = 0;
|
|
1342
1319
|
for (const file of files) {
|
|
1343
1320
|
let code;
|
|
@@ -1372,6 +1349,45 @@ async function execute(options) {
|
|
|
1372
1349
|
failures += 1;
|
|
1373
1350
|
}
|
|
1374
1351
|
}
|
|
1352
|
+
return failures;
|
|
1353
|
+
}
|
|
1354
|
+
async function execute(options) {
|
|
1355
|
+
const { files, inputRoot, warnings } = discoverInputs(options.paths);
|
|
1356
|
+
for (const w2 of warnings) console.error(`domflax: ${w2}`);
|
|
1357
|
+
if (files.length === 0) {
|
|
1358
|
+
console.error("domflax: no .jsx/.tsx files found for the given paths");
|
|
1359
|
+
return { exitCode: 1 };
|
|
1360
|
+
}
|
|
1361
|
+
const projectRoot = options.projectRoot ?? process.cwd();
|
|
1362
|
+
const gitClean = options.dangerouslyOverwriteSource && !options.noGitCheck ? isGitClean(projectRoot) : true;
|
|
1363
|
+
const planned = planWrites(options, gitClean);
|
|
1364
|
+
if (!planned.ok) {
|
|
1365
|
+
console.error(`domflax: ${planned.error}`);
|
|
1366
|
+
return { exitCode: 1 };
|
|
1367
|
+
}
|
|
1368
|
+
const plan = planned.value;
|
|
1369
|
+
const poolPlan = computeWorkerCount(options);
|
|
1370
|
+
const usePool = !options.dryRun && shouldUsePool(files.length, poolPlan);
|
|
1371
|
+
const totals = emptyTotals();
|
|
1372
|
+
let failures = 0;
|
|
1373
|
+
if (usePool) {
|
|
1374
|
+
const outcome = await runPool(
|
|
1375
|
+
files,
|
|
1376
|
+
{ options, inputRoot, plan },
|
|
1377
|
+
poolPlan
|
|
1378
|
+
// Per-file "wrote" lines are collected and printed in deterministic (sorted) order below.
|
|
1379
|
+
);
|
|
1380
|
+
Object.assign(totals, outcome.totals);
|
|
1381
|
+
failures = outcome.failures;
|
|
1382
|
+
for (const { path: p2, error } of outcome.errors) {
|
|
1383
|
+
console.error(`domflax: failed ${path4.relative(process.cwd(), p2) || p2}: ${error}`);
|
|
1384
|
+
}
|
|
1385
|
+
for (const dest of [...outcome.wrote].sort()) {
|
|
1386
|
+
console.log(`domflax: wrote ${path4.relative(process.cwd(), dest) || dest}`);
|
|
1387
|
+
}
|
|
1388
|
+
} else {
|
|
1389
|
+
failures += runInline(files, options, inputRoot, plan, totals);
|
|
1390
|
+
}
|
|
1375
1391
|
if (options.dryRun) {
|
|
1376
1392
|
console.log("\ndomflax: dry run \u2014 no files were written.");
|
|
1377
1393
|
} else if (totals.changed === 0) {
|