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.cjs
CHANGED
|
@@ -175,8 +175,8 @@ init_cjs_shims();
|
|
|
175
175
|
|
|
176
176
|
// ../cli/src/index.ts
|
|
177
177
|
init_cjs_shims();
|
|
178
|
-
var
|
|
179
|
-
var
|
|
178
|
+
var import_node_fs4 = require("fs");
|
|
179
|
+
var path9 = __toESM(require("path"), 1);
|
|
180
180
|
|
|
181
181
|
// ../cli/src/options.ts
|
|
182
182
|
init_cjs_shims();
|
|
@@ -192,6 +192,14 @@ function toSafety(raw) {
|
|
|
192
192
|
if (n === 0 || n === 1 || n === 2 || n === 3) return n;
|
|
193
193
|
throw new Error(`domflax: invalid --safety "${raw}" (expected 0, 1, 2 or 3)`);
|
|
194
194
|
}
|
|
195
|
+
function toPositiveInt(raw, flag) {
|
|
196
|
+
if (raw === void 0) return null;
|
|
197
|
+
const n = Number(raw);
|
|
198
|
+
if (!Number.isInteger(n) || n < 1) {
|
|
199
|
+
throw new Error(`domflax: invalid ${flag} "${raw}" (expected a positive integer)`);
|
|
200
|
+
}
|
|
201
|
+
return n;
|
|
202
|
+
}
|
|
195
203
|
function parseInvocation(argv) {
|
|
196
204
|
const { values, positionals } = (0, import_node_util.parseArgs)({
|
|
197
205
|
args: argv,
|
|
@@ -207,7 +215,9 @@ function parseInvocation(argv) {
|
|
|
207
215
|
"no-interactive": { type: "boolean", default: false },
|
|
208
216
|
yes: { type: "boolean", short: "y", default: false },
|
|
209
217
|
safety: { type: "string" },
|
|
210
|
-
"project-root": { type: "string" }
|
|
218
|
+
"project-root": { type: "string" },
|
|
219
|
+
"max-memory": { type: "string" },
|
|
220
|
+
concurrency: { type: "string" }
|
|
211
221
|
}
|
|
212
222
|
});
|
|
213
223
|
const provider = values.provider ?? DEFAULT_PROVIDER;
|
|
@@ -226,7 +236,9 @@ function parseInvocation(argv) {
|
|
|
226
236
|
interactive: values["no-interactive"] !== true && values.yes !== true,
|
|
227
237
|
passes: null,
|
|
228
238
|
safety: toSafety(values.safety),
|
|
229
|
-
projectRoot: values["project-root"] ?? null
|
|
239
|
+
projectRoot: values["project-root"] ?? null,
|
|
240
|
+
maxMemory: toPositiveInt(values["max-memory"], "--max-memory"),
|
|
241
|
+
concurrency: toPositiveInt(values.concurrency, "--concurrency")
|
|
230
242
|
};
|
|
231
243
|
}
|
|
232
244
|
function shouldPrompt(options, isTty) {
|
|
@@ -250,18 +262,212 @@ var USAGE = [
|
|
|
250
262
|
" --dangerously-overwrite-source overwrite source in place (needs a clean git tree)",
|
|
251
263
|
" --no-git-check skip the clean-git-tree gate",
|
|
252
264
|
" --safety <0|1|2|3> optimization aggressiveness (default: 2)",
|
|
265
|
+
" --max-memory <MB> memory budget; caps pool RAM AND parallelism (default: ~70% free RAM)",
|
|
266
|
+
" --concurrency <N> max parallel workers (still clamped by --max-memory)",
|
|
253
267
|
" --yes, --no-interactive never launch the wizard (CI-safe)",
|
|
254
268
|
"",
|
|
269
|
+
"Many files are processed across CPU cores by a memory-bounded worker pool; small jobs run inline.",
|
|
255
270
|
"With no paths in an interactive terminal, a guided wizard launches."
|
|
256
271
|
].join("\n");
|
|
257
272
|
|
|
273
|
+
// ../cli/src/pool.ts
|
|
274
|
+
init_cjs_shims();
|
|
275
|
+
var import_node_fs = require("fs");
|
|
276
|
+
var os = __toESM(require("os"), 1);
|
|
277
|
+
var path = __toESM(require("path"), 1);
|
|
278
|
+
var import_node_url = require("url");
|
|
279
|
+
var import_node_worker_threads = require("worker_threads");
|
|
280
|
+
var PER_WORKER_MB = 160;
|
|
281
|
+
var MIN_OLD_GEN_MB = 64;
|
|
282
|
+
function emptyTotals() {
|
|
283
|
+
return { files: 0, changed: 0, nodesRemoved: 0, classesSaved: 0, bytesSaved: 0 };
|
|
284
|
+
}
|
|
285
|
+
function addStats(totals, stats, changed) {
|
|
286
|
+
totals.files += 1;
|
|
287
|
+
if (changed) totals.changed += 1;
|
|
288
|
+
totals.nodesRemoved += stats.nodesRemoved;
|
|
289
|
+
totals.classesSaved += stats.classesSaved;
|
|
290
|
+
totals.bytesSaved += stats.bytesSaved;
|
|
291
|
+
}
|
|
292
|
+
function clamp(n, lo, hi) {
|
|
293
|
+
return Math.max(lo, Math.min(hi, n));
|
|
294
|
+
}
|
|
295
|
+
function computeWorkerCount(options) {
|
|
296
|
+
const cpus2 = Math.max(1, os.cpus().length);
|
|
297
|
+
const freeMB = Math.floor(os.freemem() / (1024 * 1024));
|
|
298
|
+
const budgetMB = Math.max(PER_WORKER_MB, options.maxMemory ?? Math.floor(freeMB * 0.7));
|
|
299
|
+
const byMemory = Math.max(1, Math.floor(budgetMB / PER_WORKER_MB));
|
|
300
|
+
const target = options.concurrency ?? Math.max(1, cpus2 - 1);
|
|
301
|
+
const workers = clamp(Math.min(target, byMemory), 1, byMemory);
|
|
302
|
+
const perWorkerCapMB = Math.max(MIN_OLD_GEN_MB, Math.floor(budgetMB / workers));
|
|
303
|
+
return { workers, budgetMB, perWorkerCapMB };
|
|
304
|
+
}
|
|
305
|
+
function inlineThreshold(workers) {
|
|
306
|
+
return Math.max(4, 2 * workers);
|
|
307
|
+
}
|
|
308
|
+
function shouldUsePool(fileCount, plan) {
|
|
309
|
+
return plan.workers > 1 && fileCount > inlineThreshold(plan.workers);
|
|
310
|
+
}
|
|
311
|
+
function moduleDir() {
|
|
312
|
+
try {
|
|
313
|
+
return path.dirname((0, import_node_url.fileURLToPath)(importMetaUrl));
|
|
314
|
+
} catch {
|
|
315
|
+
return typeof __dirname !== "undefined" ? __dirname : process.cwd();
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
function resolveWorkerPath() {
|
|
319
|
+
const dir = moduleDir();
|
|
320
|
+
const candidates = [
|
|
321
|
+
path.join(dir, "worker.cjs"),
|
|
322
|
+
path.join(dir, "worker.js"),
|
|
323
|
+
path.join(dir, "..", "dist", "worker.cjs"),
|
|
324
|
+
path.join(dir, "..", "dist", "worker.js")
|
|
325
|
+
];
|
|
326
|
+
for (const c of candidates) {
|
|
327
|
+
if ((0, import_node_fs.existsSync)(c)) return c;
|
|
328
|
+
}
|
|
329
|
+
return candidates[0];
|
|
330
|
+
}
|
|
331
|
+
function runPool(files, init, plan, onWrote) {
|
|
332
|
+
const workerPath = resolveWorkerPath();
|
|
333
|
+
const totals = emptyTotals();
|
|
334
|
+
const wrote = [];
|
|
335
|
+
const errors = [];
|
|
336
|
+
let failures = 0;
|
|
337
|
+
const budgetBytes = plan.budgetMB * 1024 * 1024;
|
|
338
|
+
let nextIndex = 0;
|
|
339
|
+
let completed = 0;
|
|
340
|
+
const total = files.length;
|
|
341
|
+
let respawns = 0;
|
|
342
|
+
const maxRespawns = total + plan.workers + 8;
|
|
343
|
+
return new Promise((resolve6) => {
|
|
344
|
+
const handles = /* @__PURE__ */ new Set();
|
|
345
|
+
const finishIfDone = () => {
|
|
346
|
+
if (completed < total) return;
|
|
347
|
+
for (const h2 of handles) {
|
|
348
|
+
if (!h2.dead) {
|
|
349
|
+
try {
|
|
350
|
+
h2.worker.postMessage({ type: "stop" });
|
|
351
|
+
} catch {
|
|
352
|
+
}
|
|
353
|
+
void h2.worker.terminate();
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
handles.clear();
|
|
357
|
+
resolve6({ totals, failures, wrote, errors });
|
|
358
|
+
};
|
|
359
|
+
const recordFailure = (file, error) => {
|
|
360
|
+
failures += 1;
|
|
361
|
+
completed += 1;
|
|
362
|
+
errors.push({ path: file, error });
|
|
363
|
+
};
|
|
364
|
+
const dispatch = (h2) => {
|
|
365
|
+
if (h2.dead) return;
|
|
366
|
+
if (nextIndex >= total) {
|
|
367
|
+
h2.current = null;
|
|
368
|
+
try {
|
|
369
|
+
h2.worker.postMessage({ type: "stop" });
|
|
370
|
+
} catch {
|
|
371
|
+
}
|
|
372
|
+
return;
|
|
373
|
+
}
|
|
374
|
+
if (process.memoryUsage().rss > budgetBytes) {
|
|
375
|
+
setTimeout(() => dispatch(h2), 25);
|
|
376
|
+
return;
|
|
377
|
+
}
|
|
378
|
+
const file = files[nextIndex++];
|
|
379
|
+
h2.current = file;
|
|
380
|
+
try {
|
|
381
|
+
h2.worker.postMessage({ type: "file", path: file });
|
|
382
|
+
} catch {
|
|
383
|
+
onWorkerDown(h2);
|
|
384
|
+
}
|
|
385
|
+
};
|
|
386
|
+
const onMessage = (h2, msg) => {
|
|
387
|
+
if (msg.type === "ready") {
|
|
388
|
+
h2.ready = true;
|
|
389
|
+
dispatch(h2);
|
|
390
|
+
return;
|
|
391
|
+
}
|
|
392
|
+
h2.current = null;
|
|
393
|
+
if (msg.ok) {
|
|
394
|
+
addStats(totals, msg.stats, msg.changed);
|
|
395
|
+
if (msg.wrote) {
|
|
396
|
+
wrote.push(msg.wrote);
|
|
397
|
+
onWrote?.(msg.wrote);
|
|
398
|
+
}
|
|
399
|
+
} else {
|
|
400
|
+
failures += 1;
|
|
401
|
+
errors.push({ path: msg.path, error: msg.error });
|
|
402
|
+
}
|
|
403
|
+
completed += 1;
|
|
404
|
+
if (completed >= total) {
|
|
405
|
+
finishIfDone();
|
|
406
|
+
return;
|
|
407
|
+
}
|
|
408
|
+
dispatch(h2);
|
|
409
|
+
};
|
|
410
|
+
const drainRemaining = (reason) => {
|
|
411
|
+
while (nextIndex < total) recordFailure(files[nextIndex++], reason);
|
|
412
|
+
finishIfDone();
|
|
413
|
+
};
|
|
414
|
+
const onWorkerDown = (h2) => {
|
|
415
|
+
if (h2.dead) return;
|
|
416
|
+
h2.dead = true;
|
|
417
|
+
handles.delete(h2);
|
|
418
|
+
const lost = h2.current;
|
|
419
|
+
h2.current = null;
|
|
420
|
+
if (lost !== null) recordFailure(lost, "worker crashed while processing this file");
|
|
421
|
+
void h2.worker.terminate();
|
|
422
|
+
if (completed >= total) {
|
|
423
|
+
finishIfDone();
|
|
424
|
+
return;
|
|
425
|
+
}
|
|
426
|
+
if (nextIndex >= total) {
|
|
427
|
+
if (handles.size === 0) finishIfDone();
|
|
428
|
+
return;
|
|
429
|
+
}
|
|
430
|
+
if (respawns < maxRespawns) {
|
|
431
|
+
respawns += 1;
|
|
432
|
+
spawn();
|
|
433
|
+
} else if (handles.size === 0) {
|
|
434
|
+
drainRemaining("worker pool exhausted its respawn budget (memory cap too small?)");
|
|
435
|
+
}
|
|
436
|
+
};
|
|
437
|
+
const spawn = () => {
|
|
438
|
+
let worker;
|
|
439
|
+
try {
|
|
440
|
+
worker = new import_node_worker_threads.Worker(workerPath, {
|
|
441
|
+
workerData: init,
|
|
442
|
+
resourceLimits: { maxOldGenerationSizeMb: plan.perWorkerCapMB }
|
|
443
|
+
});
|
|
444
|
+
} catch {
|
|
445
|
+
if (nextIndex < total) recordFailure(files[nextIndex++], "failed to spawn worker");
|
|
446
|
+
if (completed >= total) finishIfDone();
|
|
447
|
+
else if (handles.size === 0 && nextIndex < total) spawn();
|
|
448
|
+
return;
|
|
449
|
+
}
|
|
450
|
+
const h2 = { worker, current: null, ready: false, dead: false };
|
|
451
|
+
handles.add(h2);
|
|
452
|
+
worker.on("message", (m2) => onMessage(h2, m2));
|
|
453
|
+
worker.on("error", () => onWorkerDown(h2));
|
|
454
|
+
worker.on("exit", (code) => {
|
|
455
|
+
if (code !== 0) onWorkerDown(h2);
|
|
456
|
+
});
|
|
457
|
+
};
|
|
458
|
+
const initial = Math.min(plan.workers, total);
|
|
459
|
+
for (let i = 0; i < initial; i++) spawn();
|
|
460
|
+
if (initial === 0) finishIfDone();
|
|
461
|
+
});
|
|
462
|
+
}
|
|
463
|
+
|
|
258
464
|
// ../cli/src/safety.ts
|
|
259
465
|
init_cjs_shims();
|
|
260
466
|
var import_node_child_process = require("child_process");
|
|
261
|
-
var
|
|
467
|
+
var path2 = __toESM(require("path"), 1);
|
|
262
468
|
var DISPOSABLE_DIRS = /* @__PURE__ */ new Set(["dist", "build", "out", ".next"]);
|
|
263
469
|
function isDisposablePath(file) {
|
|
264
|
-
return
|
|
470
|
+
return path2.resolve(file).split(path2.sep).some((seg) => DISPOSABLE_DIRS.has(seg));
|
|
265
471
|
}
|
|
266
472
|
function isGitClean(cwd) {
|
|
267
473
|
try {
|
|
@@ -285,19 +491,19 @@ function planWrites(options, gitClean) {
|
|
|
285
491
|
}
|
|
286
492
|
return { ok: true, value: { mode: "overwrite-source", outDir: null } };
|
|
287
493
|
}
|
|
288
|
-
const outDir =
|
|
494
|
+
const outDir = path2.resolve(options.out ?? "domflax-out");
|
|
289
495
|
return { ok: true, value: { mode: "out-dir", outDir } };
|
|
290
496
|
}
|
|
291
497
|
function destinationFor(file, inputRoot, plan) {
|
|
292
|
-
const absFile =
|
|
498
|
+
const absFile = path2.resolve(file);
|
|
293
499
|
if (plan.mode === "overwrite-source") {
|
|
294
500
|
return { ok: true, value: absFile };
|
|
295
501
|
}
|
|
296
502
|
const outDir = plan.outDir;
|
|
297
|
-
const rel =
|
|
298
|
-
const safeRel = rel === "" || rel.startsWith("..") ||
|
|
299
|
-
const dest =
|
|
300
|
-
if (
|
|
503
|
+
const rel = path2.relative(inputRoot, absFile);
|
|
504
|
+
const safeRel = rel === "" || rel.startsWith("..") || path2.isAbsolute(rel) ? path2.basename(absFile) : rel;
|
|
505
|
+
const dest = path2.join(outDir, safeRel);
|
|
506
|
+
if (path2.resolve(dest) === absFile && !isDisposablePath(absFile)) {
|
|
301
507
|
return {
|
|
302
508
|
ok: false,
|
|
303
509
|
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).`
|
|
@@ -382,6 +588,7 @@ function defaultMeta(safetyFloor = 0) {
|
|
|
382
588
|
declaresCustomProperties: false,
|
|
383
589
|
whitespaceSensitive: false,
|
|
384
590
|
touched: false,
|
|
591
|
+
styleDirty: false,
|
|
385
592
|
synthetic: false,
|
|
386
593
|
safetyFloor
|
|
387
594
|
};
|
|
@@ -566,6 +773,14 @@ function markTouched(state, id) {
|
|
|
566
773
|
state.touched.add(id);
|
|
567
774
|
}
|
|
568
775
|
}
|
|
776
|
+
function markStyleDirty(state, id) {
|
|
777
|
+
const n = state.doc.nodes.get(id);
|
|
778
|
+
if (n) {
|
|
779
|
+
n.meta.touched = true;
|
|
780
|
+
n.meta.styleDirty = true;
|
|
781
|
+
state.touched.add(id);
|
|
782
|
+
}
|
|
783
|
+
}
|
|
569
784
|
function removeSubtree(state, id) {
|
|
570
785
|
const node = state.doc.nodes.get(id);
|
|
571
786
|
if (!node) return;
|
|
@@ -858,7 +1073,7 @@ function applyOne(state, op) {
|
|
|
858
1073
|
return [precond(op, op.target, "setClassList target is not an element")];
|
|
859
1074
|
}
|
|
860
1075
|
el.computed = cloneStyleMap(op.style);
|
|
861
|
-
|
|
1076
|
+
markStyleDirty(state, op.target);
|
|
862
1077
|
return [];
|
|
863
1078
|
}
|
|
864
1079
|
case "mergeStyle": {
|
|
@@ -881,7 +1096,7 @@ function applyOne(state, op) {
|
|
|
881
1096
|
const src = doc.nodes.get(op.source);
|
|
882
1097
|
if (src) markTouched(state, op.source);
|
|
883
1098
|
}
|
|
884
|
-
|
|
1099
|
+
markStyleDirty(state, op.target);
|
|
885
1100
|
return [];
|
|
886
1101
|
}
|
|
887
1102
|
case "foldInheritedStyles":
|
|
@@ -932,7 +1147,7 @@ function applyFold(state, op) {
|
|
|
932
1147
|
}
|
|
933
1148
|
if (folded) {
|
|
934
1149
|
into.computed = { blocks: nextBlocks };
|
|
935
|
-
|
|
1150
|
+
markStyleDirty(state, intoId);
|
|
936
1151
|
}
|
|
937
1152
|
}
|
|
938
1153
|
for (const d3 of issues) state.diagnostics.push(d3);
|
|
@@ -1197,8 +1412,123 @@ init_cjs_shims();
|
|
|
1197
1412
|
var DISPLAY = "display";
|
|
1198
1413
|
var POSITION = "position";
|
|
1199
1414
|
var TRANSFORM = "transform";
|
|
1415
|
+
var ALIGN_ITEMS = "align-items";
|
|
1416
|
+
var JUSTIFY_CONTENT = "justify-content";
|
|
1417
|
+
var JUSTIFY_ITEMS = "justify-items";
|
|
1418
|
+
var PLACE_ITEMS = "place-items";
|
|
1419
|
+
var PLACE_SELF = "place-self";
|
|
1200
1420
|
var CONTEXT_SAFE_DISPLAYS = /* @__PURE__ */ new Set(["block", "contents", ""]);
|
|
1201
1421
|
var STATIC_POSITIONS = /* @__PURE__ */ new Set(["static", ""]);
|
|
1422
|
+
var CENTERING_DISPLAYS = /* @__PURE__ */ new Set(["flex", "grid"]);
|
|
1423
|
+
var GRID_PARENT_DISPLAYS = /* @__PURE__ */ new Set(["grid"]);
|
|
1424
|
+
var STRETCHY_ITEM_ALIGN = /* @__PURE__ */ new Set(["normal", "stretch"]);
|
|
1425
|
+
var PARENT_ITEMS_ALIGN_PROPS = [ALIGN_ITEMS, JUSTIFY_ITEMS, PLACE_ITEMS];
|
|
1426
|
+
function isBaseCondition(block) {
|
|
1427
|
+
const c = block.condition;
|
|
1428
|
+
return c.media === "" && c.states.length === 0 && c.pseudoElement === "";
|
|
1429
|
+
}
|
|
1430
|
+
function baseValue(sm, prop) {
|
|
1431
|
+
for (const block of sm.blocks.values()) {
|
|
1432
|
+
if (!isBaseCondition(block)) continue;
|
|
1433
|
+
const d3 = block.decls.get(prop);
|
|
1434
|
+
return d3 ? String(d3.value) : null;
|
|
1435
|
+
}
|
|
1436
|
+
return null;
|
|
1437
|
+
}
|
|
1438
|
+
function parentIsFillingGrid(before, wrapper, norm) {
|
|
1439
|
+
if (wrapper.parent == null) return false;
|
|
1440
|
+
const p2 = before.nodes.get(wrapper.parent);
|
|
1441
|
+
if (!p2 || p2.kind !== "element") return false;
|
|
1442
|
+
const pc2 = norm.normalizeStyleMap(p2.computed);
|
|
1443
|
+
let baseIsGrid = false;
|
|
1444
|
+
for (const block of pc2.blocks.values()) {
|
|
1445
|
+
const disp = block.decls.get(DISPLAY);
|
|
1446
|
+
if (disp) {
|
|
1447
|
+
if (!GRID_PARENT_DISPLAYS.has(String(disp.value))) return false;
|
|
1448
|
+
if (isBaseCondition(block)) baseIsGrid = true;
|
|
1449
|
+
}
|
|
1450
|
+
for (const prop of PARENT_ITEMS_ALIGN_PROPS) {
|
|
1451
|
+
const d3 = block.decls.get(prop);
|
|
1452
|
+
if (d3 && !STRETCHY_ITEM_ALIGN.has(String(d3.value))) return false;
|
|
1453
|
+
}
|
|
1454
|
+
}
|
|
1455
|
+
return baseIsGrid;
|
|
1456
|
+
}
|
|
1457
|
+
function wrapperHasOnlyCenteringStyle(wrapperComputed, childComputed, norm) {
|
|
1458
|
+
for (const block of wrapperComputed.blocks.values()) {
|
|
1459
|
+
const base = isBaseCondition(block);
|
|
1460
|
+
const ck = conditionKey(block.condition);
|
|
1461
|
+
for (const [prop, decl] of block.decls) {
|
|
1462
|
+
const val = String(decl.value);
|
|
1463
|
+
if (prop === DISPLAY) {
|
|
1464
|
+
if (base && CENTERING_DISPLAYS.has(val)) continue;
|
|
1465
|
+
return false;
|
|
1466
|
+
}
|
|
1467
|
+
if (prop === ALIGN_ITEMS) {
|
|
1468
|
+
if (base && val === "center") continue;
|
|
1469
|
+
return false;
|
|
1470
|
+
}
|
|
1471
|
+
if (prop === JUSTIFY_CONTENT) {
|
|
1472
|
+
if (base && val === "center") continue;
|
|
1473
|
+
return false;
|
|
1474
|
+
}
|
|
1475
|
+
if (prop === POSITION) {
|
|
1476
|
+
if (STATIC_POSITIONS.has(val)) continue;
|
|
1477
|
+
return false;
|
|
1478
|
+
}
|
|
1479
|
+
if (prop === TRANSFORM) {
|
|
1480
|
+
if (val === "none") continue;
|
|
1481
|
+
return false;
|
|
1482
|
+
}
|
|
1483
|
+
if (isInherited2(decl, norm)) continue;
|
|
1484
|
+
if (childReproduces(childComputed, ck, prop, val)) continue;
|
|
1485
|
+
return false;
|
|
1486
|
+
}
|
|
1487
|
+
}
|
|
1488
|
+
return true;
|
|
1489
|
+
}
|
|
1490
|
+
function wrapperCentersSingleElement(before, wrapper) {
|
|
1491
|
+
let elements = 0;
|
|
1492
|
+
for (const cid of wrapper.children) {
|
|
1493
|
+
const n = before.nodes.get(cid);
|
|
1494
|
+
if (!n) continue;
|
|
1495
|
+
if (n.kind === "element") {
|
|
1496
|
+
elements += 1;
|
|
1497
|
+
continue;
|
|
1498
|
+
}
|
|
1499
|
+
if (n.kind === "comment") continue;
|
|
1500
|
+
if (n.kind === "text" && n.value.trim() === "") continue;
|
|
1501
|
+
return false;
|
|
1502
|
+
}
|
|
1503
|
+
return elements === 1;
|
|
1504
|
+
}
|
|
1505
|
+
function childHasSelfAlign(childBefore, norm) {
|
|
1506
|
+
if (!childBefore) return false;
|
|
1507
|
+
const sm = norm.normalizeStyleMap(childBefore);
|
|
1508
|
+
for (const block of sm.blocks.values()) {
|
|
1509
|
+
for (const prop of SELF_ALIGN_PROPS) {
|
|
1510
|
+
const d3 = block.decls.get(prop);
|
|
1511
|
+
if (d3 && !NEUTRAL_ALIGN.has(String(d3.value))) return true;
|
|
1512
|
+
}
|
|
1513
|
+
}
|
|
1514
|
+
return false;
|
|
1515
|
+
}
|
|
1516
|
+
function childGainsPlaceSelfCenter(childAfter) {
|
|
1517
|
+
if (baseValue(childAfter, PLACE_SELF) === "center") return true;
|
|
1518
|
+
return baseValue(childAfter, "align-self") === "center" && baseValue(childAfter, "justify-self") === "center";
|
|
1519
|
+
}
|
|
1520
|
+
function isContextCompensatedCentering(before, wrapper, wrapperComputed, childBefore, childAfter, norm) {
|
|
1521
|
+
if (!childAfter) return false;
|
|
1522
|
+
if (!CENTERING_DISPLAYS.has(baseValue(wrapperComputed, DISPLAY) ?? "")) return false;
|
|
1523
|
+
if (baseValue(wrapperComputed, ALIGN_ITEMS) !== "center") return false;
|
|
1524
|
+
if (baseValue(wrapperComputed, JUSTIFY_CONTENT) !== "center") return false;
|
|
1525
|
+
const childAfterNorm = norm.normalizeStyleMap(childAfter);
|
|
1526
|
+
if (!childGainsPlaceSelfCenter(childAfterNorm)) return false;
|
|
1527
|
+
if (!wrapperHasOnlyCenteringStyle(wrapperComputed, childAfterNorm, norm)) return false;
|
|
1528
|
+
if (!wrapperCentersSingleElement(before, wrapper)) return false;
|
|
1529
|
+
if (childHasSelfAlign(childBefore, norm)) return false;
|
|
1530
|
+
return parentIsFillingGrid(before, wrapper, norm);
|
|
1531
|
+
}
|
|
1202
1532
|
var SELF_ALIGN_PROPS = [
|
|
1203
1533
|
"place-self",
|
|
1204
1534
|
"align-self",
|
|
@@ -1298,6 +1628,9 @@ function classifyFlattenOps(before, after, ops, norm) {
|
|
|
1298
1628
|
const wrapperComputed = norm.normalizeStyleMap(wrapper.computed);
|
|
1299
1629
|
const childAfter = childId != null ? getElement(after, childId)?.computed ?? null : null;
|
|
1300
1630
|
const childBefore = childId != null ? getElement(before, childId)?.computed ?? null : null;
|
|
1631
|
+
if (isContextCompensatedCentering(before, wrapper, wrapperComputed, childBefore, childAfter, norm)) {
|
|
1632
|
+
return { kind: "provably-safe", wrapperId, childId };
|
|
1633
|
+
}
|
|
1301
1634
|
if (establishesChildContext(wrapperComputed)) {
|
|
1302
1635
|
return { kind: "needs-verification", wrapperId, childId };
|
|
1303
1636
|
}
|
|
@@ -1579,15 +1912,34 @@ function sameTokens(a, b3) {
|
|
|
1579
1912
|
for (let i = 0; i < a.length; i += 1) if (a[i] !== b3[i]) return false;
|
|
1580
1913
|
return true;
|
|
1581
1914
|
}
|
|
1915
|
+
function residualStyle(computed2, covered, norm) {
|
|
1916
|
+
const cov = norm.normalizeStyleMap(covered);
|
|
1917
|
+
const blocks = /* @__PURE__ */ new Map();
|
|
1918
|
+
for (const [key, block] of norm.normalizeStyleMap(computed2).blocks) {
|
|
1919
|
+
const covBlock = cov.blocks.get(key);
|
|
1920
|
+
const decls = /* @__PURE__ */ new Map();
|
|
1921
|
+
for (const [prop, decl] of block.decls) {
|
|
1922
|
+
const covDecl = covBlock?.decls.get(prop);
|
|
1923
|
+
if (covDecl && covDecl.value === decl.value && covDecl.important === decl.important) continue;
|
|
1924
|
+
decls.set(prop, decl);
|
|
1925
|
+
}
|
|
1926
|
+
if (decls.size > 0) blocks.set(key, { condition: block.condition, decls });
|
|
1927
|
+
}
|
|
1928
|
+
return { blocks };
|
|
1929
|
+
}
|
|
1582
1930
|
function syncClassesFromComputed(doc, resolver, norm) {
|
|
1583
1931
|
const sink = createSyntheticSink();
|
|
1584
1932
|
for (const id of elementIds(doc)) {
|
|
1585
1933
|
const el = getElement(doc, id);
|
|
1586
|
-
if (!el
|
|
1934
|
+
if (!el) continue;
|
|
1935
|
+
if (!el.meta.styleDirty) continue;
|
|
1587
1936
|
if (el.classes.opaque || el.classes.hasDynamic) continue;
|
|
1588
1937
|
const tokens = staticTokensOf(el.classes);
|
|
1938
|
+
const retained = tokens.filter((t) => !resolver.selectorUsage(t).droppable);
|
|
1939
|
+
const covered = retained.length > 0 ? resolver.resolve({ classes: retained }).styles : null;
|
|
1940
|
+
const target = covered ? residualStyle(el.computed, covered, norm) : el.computed;
|
|
1589
1941
|
const ctx = { normalizer: norm, sink };
|
|
1590
|
-
const emitted = resolver.emit(
|
|
1942
|
+
const emitted = resolver.emit(target, ctx).classes;
|
|
1591
1943
|
if (emitted.length === 0) continue;
|
|
1592
1944
|
const emittedSet = new Set(emitted);
|
|
1593
1945
|
const next = [];
|
|
@@ -1610,6 +1962,350 @@ function syncClassesFromComputed(doc, resolver, norm) {
|
|
|
1610
1962
|
}
|
|
1611
1963
|
}
|
|
1612
1964
|
|
|
1965
|
+
// ../frontend-html/src/index.ts
|
|
1966
|
+
init_cjs_shims();
|
|
1967
|
+
|
|
1968
|
+
// ../frontend-html/src/backend.ts
|
|
1969
|
+
init_cjs_shims();
|
|
1970
|
+
var import_magic_string = __toESM(require("magic-string"), 1);
|
|
1971
|
+
function staticTokensOf2(classes) {
|
|
1972
|
+
const out = [];
|
|
1973
|
+
for (const seg of classes.segments) {
|
|
1974
|
+
if (seg.kind === "static") for (const t of seg.tokens) out.push(t.value);
|
|
1975
|
+
}
|
|
1976
|
+
return out;
|
|
1977
|
+
}
|
|
1978
|
+
function sameTokens2(a, b3) {
|
|
1979
|
+
if (a.length !== b3.length) return false;
|
|
1980
|
+
for (let i = 0; i < a.length; i += 1) if (a[i] !== b3[i]) return false;
|
|
1981
|
+
return true;
|
|
1982
|
+
}
|
|
1983
|
+
function primarySource(doc) {
|
|
1984
|
+
for (const sf of doc.sources.values()) {
|
|
1985
|
+
if (typeof sf.text === "string" && sf.text.length > 0) return sf;
|
|
1986
|
+
}
|
|
1987
|
+
return null;
|
|
1988
|
+
}
|
|
1989
|
+
function collectKept(doc) {
|
|
1990
|
+
const out = [];
|
|
1991
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1992
|
+
const visit = (id) => {
|
|
1993
|
+
if (seen.has(id)) return;
|
|
1994
|
+
seen.add(id);
|
|
1995
|
+
const n = doc.nodes.get(id);
|
|
1996
|
+
if (!n) return;
|
|
1997
|
+
out.push(n);
|
|
1998
|
+
if (n.kind === "element" || n.kind === "fragment") for (const c of n.children) visit(c);
|
|
1999
|
+
};
|
|
2000
|
+
visit(doc.root);
|
|
2001
|
+
return out;
|
|
2002
|
+
}
|
|
2003
|
+
function strictlyContains(a, b3) {
|
|
2004
|
+
if (a.file !== b3.file) return false;
|
|
2005
|
+
if (a.start <= b3.start && b3.end <= a.end) return !(a.start === b3.start && a.end === b3.end);
|
|
2006
|
+
return false;
|
|
2007
|
+
}
|
|
2008
|
+
function backrefIds(doc) {
|
|
2009
|
+
const out = [];
|
|
2010
|
+
const max = doc.alloc.peek;
|
|
2011
|
+
for (let i = 1; i < max; i += 1) {
|
|
2012
|
+
const id = i;
|
|
2013
|
+
if (doc.backref.get(id)) out.push(id);
|
|
2014
|
+
}
|
|
2015
|
+
return out;
|
|
2016
|
+
}
|
|
2017
|
+
function currentTokens(sf, valueSpan) {
|
|
2018
|
+
const raw = sf.text.slice(valueSpan.start, valueSpan.end).trim();
|
|
2019
|
+
const unquoted = raw.replace(/^['"]/, "").replace(/['"]$/, "");
|
|
2020
|
+
return unquoted.split(/\s+/).filter((t) => t.length > 0);
|
|
2021
|
+
}
|
|
2022
|
+
function editClasses(ms, doc, sf, el) {
|
|
2023
|
+
const classes = el.classes;
|
|
2024
|
+
if (classes.hasDynamic || classes.opaque) return false;
|
|
2025
|
+
const tokens = staticTokensOf2(classes);
|
|
2026
|
+
const valueSpan = classes.valueSpan;
|
|
2027
|
+
if (valueSpan && valueSpan.file === sf.id) {
|
|
2028
|
+
if (sameTokens2(currentTokens(sf, valueSpan), tokens)) return false;
|
|
2029
|
+
const current = sf.text.slice(valueSpan.start, valueSpan.end).trim();
|
|
2030
|
+
const quote = current.startsWith("'") ? "'" : '"';
|
|
2031
|
+
ms.overwrite(valueSpan.start, valueSpan.end, `${quote}${tokens.join(" ")}${quote}`);
|
|
2032
|
+
return true;
|
|
2033
|
+
}
|
|
2034
|
+
if (tokens.length === 0) return false;
|
|
2035
|
+
const openTag = doc.backref.get(el.id)?.openTagSpan;
|
|
2036
|
+
if (!openTag || openTag.file !== sf.id) return false;
|
|
2037
|
+
ms.appendLeft(openTag.start + 1 + el.tag.length, ` class="${tokens.join(" ")}"`);
|
|
2038
|
+
return true;
|
|
2039
|
+
}
|
|
2040
|
+
function surgicalPrint(doc) {
|
|
2041
|
+
const sf = primarySource(doc);
|
|
2042
|
+
if (!sf) return null;
|
|
2043
|
+
const ms = new import_magic_string.default(sf.text);
|
|
2044
|
+
const kept = collectKept(doc);
|
|
2045
|
+
const keptSpans = [];
|
|
2046
|
+
for (const n of kept) if (n.span && n.span.file === sf.id) keptSpans.push(n.span);
|
|
2047
|
+
const removed = [];
|
|
2048
|
+
for (const id of backrefIds(doc)) {
|
|
2049
|
+
if (doc.nodes.has(id)) continue;
|
|
2050
|
+
const back = doc.backref.get(id);
|
|
2051
|
+
if (!back || back.span.file !== sf.id) continue;
|
|
2052
|
+
const unwrapped = keptSpans.some((k3) => strictlyContains(back.span, k3));
|
|
2053
|
+
removed.push({ backref: back, unwrapped });
|
|
2054
|
+
}
|
|
2055
|
+
const fullRemovals = removed.filter((r2) => !r2.unwrapped).map((r2) => r2.backref.span);
|
|
2056
|
+
for (const r2 of removed) {
|
|
2057
|
+
const s = r2.backref.span;
|
|
2058
|
+
if (fullRemovals.some((f) => f !== s && strictlyContains(f, s))) continue;
|
|
2059
|
+
if (r2.unwrapped) {
|
|
2060
|
+
const open = r2.backref.openTagSpan;
|
|
2061
|
+
const close = r2.backref.closeTagSpan;
|
|
2062
|
+
if (open && open.file === sf.id && open.end > open.start) ms.remove(open.start, open.end);
|
|
2063
|
+
if (close && close.file === sf.id && close.end > close.start) ms.remove(close.start, close.end);
|
|
2064
|
+
} else {
|
|
2065
|
+
ms.remove(s.start, s.end);
|
|
2066
|
+
}
|
|
2067
|
+
}
|
|
2068
|
+
for (const n of kept) if (n.kind === "element") editClasses(ms, doc, sf, n);
|
|
2069
|
+
return ms.toString();
|
|
2070
|
+
}
|
|
2071
|
+
function doPrint(doc) {
|
|
2072
|
+
return surgicalPrint(doc) ?? "";
|
|
2073
|
+
}
|
|
2074
|
+
|
|
2075
|
+
// ../frontend-html/src/parse.ts
|
|
2076
|
+
init_cjs_shims();
|
|
2077
|
+
var import_node_module = require("module");
|
|
2078
|
+
|
|
2079
|
+
// ../frontend-html/src/walk.ts
|
|
2080
|
+
init_cjs_shims();
|
|
2081
|
+
var HTML_LANGS = ["html"];
|
|
2082
|
+
var FILE_ID = 1;
|
|
2083
|
+
function looksLikeHtml(id, code) {
|
|
2084
|
+
if (/\.html?$/i.test(id)) return true;
|
|
2085
|
+
const head = code.slice(0, 256).trimStart().toLowerCase();
|
|
2086
|
+
return head.startsWith("<!doctype html") || head.startsWith("<html") || head.startsWith("<");
|
|
2087
|
+
}
|
|
2088
|
+
var OPAQUE_SUBTREE_TAGS = /* @__PURE__ */ new Set([
|
|
2089
|
+
"script",
|
|
2090
|
+
"style",
|
|
2091
|
+
"template",
|
|
2092
|
+
"svg",
|
|
2093
|
+
"pre",
|
|
2094
|
+
"textarea"
|
|
2095
|
+
]);
|
|
2096
|
+
function isOpaqueSubtreeTag(tag) {
|
|
2097
|
+
return OPAQUE_SUBTREE_TAGS.has(tag);
|
|
2098
|
+
}
|
|
2099
|
+
function elementIsOpaque(attrs) {
|
|
2100
|
+
for (const a of attrs) {
|
|
2101
|
+
const n = a.name.toLowerCase();
|
|
2102
|
+
if (n === "id" || n === "contenteditable") return true;
|
|
2103
|
+
if (n.startsWith("on")) return true;
|
|
2104
|
+
}
|
|
2105
|
+
return false;
|
|
2106
|
+
}
|
|
2107
|
+
function hasEventHandler(attrs) {
|
|
2108
|
+
for (const a of attrs) if (/^on/i.test(a.name)) return true;
|
|
2109
|
+
return false;
|
|
2110
|
+
}
|
|
2111
|
+
function span(start, end) {
|
|
2112
|
+
return { file: FILE_ID, start, end };
|
|
2113
|
+
}
|
|
2114
|
+
function attrsLocOf(loc) {
|
|
2115
|
+
if (!loc) return void 0;
|
|
2116
|
+
return loc.startTag?.attrs ?? loc.attrs;
|
|
2117
|
+
}
|
|
2118
|
+
function classValueSpan(loc, source) {
|
|
2119
|
+
const attrsLoc = attrsLocOf(loc);
|
|
2120
|
+
const cl = attrsLoc?.["class"];
|
|
2121
|
+
if (!cl) return null;
|
|
2122
|
+
const text = source.slice(cl.startOffset, cl.endOffset);
|
|
2123
|
+
const eq = text.indexOf("=");
|
|
2124
|
+
if (eq === -1) return null;
|
|
2125
|
+
let i = eq + 1;
|
|
2126
|
+
while (i < text.length && /\s/.test(text[i])) i += 1;
|
|
2127
|
+
if (i >= text.length) return null;
|
|
2128
|
+
return span(cl.startOffset + i, cl.endOffset);
|
|
2129
|
+
}
|
|
2130
|
+
|
|
2131
|
+
// ../frontend-html/src/parse.ts
|
|
2132
|
+
var cachedParse5 = null;
|
|
2133
|
+
function loadParse5() {
|
|
2134
|
+
if (cachedParse5) return cachedParse5;
|
|
2135
|
+
const req = (0, import_node_module.createRequire)(importMetaUrl);
|
|
2136
|
+
cachedParse5 = req("parse5");
|
|
2137
|
+
return cachedParse5;
|
|
2138
|
+
}
|
|
2139
|
+
function doParse(code, ctx) {
|
|
2140
|
+
const diagnostics = [];
|
|
2141
|
+
const doc = createDocument("html");
|
|
2142
|
+
const backref = doc.backref;
|
|
2143
|
+
const parse5 = loadParse5();
|
|
2144
|
+
const document2 = parse5.parse(code, { sourceCodeLocationInfo: true });
|
|
2145
|
+
const eol = code.includes("\r\n") ? "\r\n" : "\n";
|
|
2146
|
+
const sourceFile = {
|
|
2147
|
+
id: FILE_ID,
|
|
2148
|
+
path: ctx.id,
|
|
2149
|
+
text: code,
|
|
2150
|
+
frontend: "html",
|
|
2151
|
+
eol,
|
|
2152
|
+
indentUnit: " ",
|
|
2153
|
+
native: document2
|
|
2154
|
+
};
|
|
2155
|
+
doc.sources.set(FILE_ID, sourceFile);
|
|
2156
|
+
const resolveComputed = (tokens, tag, nodeId) => {
|
|
2157
|
+
if (tokens.length === 0) return emptyStyleMap();
|
|
2158
|
+
const res = ctx.resolver.resolve({ classes: tokens, element: { tagName: tag, namespace: "html" } });
|
|
2159
|
+
for (const w2 of res.warnings) {
|
|
2160
|
+
diagnostics.push({
|
|
2161
|
+
code: "DF_STYLE_CONFLICT_UNRESOLVED",
|
|
2162
|
+
severity: w2.severity,
|
|
2163
|
+
message: w2.message,
|
|
2164
|
+
nodeId
|
|
2165
|
+
});
|
|
2166
|
+
}
|
|
2167
|
+
return ctx.normalizer.normalizeStyleMap(res.styles);
|
|
2168
|
+
};
|
|
2169
|
+
const splitTokens = (raw) => raw.split(/\s+/).filter((t) => t.length > 0);
|
|
2170
|
+
const appendChild = (node, parentId, out) => {
|
|
2171
|
+
const name = node.nodeName;
|
|
2172
|
+
if (name === "#text") {
|
|
2173
|
+
const value = node.value ?? "";
|
|
2174
|
+
const id = doc.alloc.next();
|
|
2175
|
+
const loc = node.sourceCodeLocation ?? null;
|
|
2176
|
+
doc.nodes.set(
|
|
2177
|
+
id,
|
|
2178
|
+
createText(id, value, {
|
|
2179
|
+
parent: parentId,
|
|
2180
|
+
span: loc ? span(loc.startOffset, loc.endOffset) : null,
|
|
2181
|
+
collapsible: /^\s*$/.test(value)
|
|
2182
|
+
})
|
|
2183
|
+
);
|
|
2184
|
+
out.push(id);
|
|
2185
|
+
return;
|
|
2186
|
+
}
|
|
2187
|
+
if (name === "#comment") {
|
|
2188
|
+
const id = doc.alloc.next();
|
|
2189
|
+
const loc = node.sourceCodeLocation ?? null;
|
|
2190
|
+
doc.nodes.set(
|
|
2191
|
+
id,
|
|
2192
|
+
createComment(id, node.data ?? "", {
|
|
2193
|
+
parent: parentId,
|
|
2194
|
+
span: loc ? span(loc.startOffset, loc.endOffset) : null
|
|
2195
|
+
})
|
|
2196
|
+
);
|
|
2197
|
+
out.push(id);
|
|
2198
|
+
return;
|
|
2199
|
+
}
|
|
2200
|
+
if (name === "#documentType") return;
|
|
2201
|
+
if (name.startsWith("#")) {
|
|
2202
|
+
for (const c of node.childNodes ?? []) appendChild(c, parentId, out);
|
|
2203
|
+
return;
|
|
2204
|
+
}
|
|
2205
|
+
out.push(buildElement(node, parentId));
|
|
2206
|
+
};
|
|
2207
|
+
const buildElement = (node, parentId) => {
|
|
2208
|
+
const id = doc.alloc.next();
|
|
2209
|
+
const tag = (node.tagName ?? node.nodeName).toLowerCase();
|
|
2210
|
+
const loc = node.sourceCodeLocation ?? null;
|
|
2211
|
+
const attrsArr = node.attrs ?? [];
|
|
2212
|
+
const opaqueSubtree = isOpaqueSubtreeTag(tag);
|
|
2213
|
+
const synthetic = loc == null;
|
|
2214
|
+
const opaque2 = opaqueSubtree || synthetic || elementIsOpaque(attrsArr);
|
|
2215
|
+
const meta = defaultMeta();
|
|
2216
|
+
meta.hasEventHandlers = hasEventHandler(attrsArr);
|
|
2217
|
+
meta.safetyFloor = opaque2 ? 0 : 3;
|
|
2218
|
+
let classes = emptyClassList();
|
|
2219
|
+
let classTokens = [];
|
|
2220
|
+
const entries = /* @__PURE__ */ new Map();
|
|
2221
|
+
const order = [];
|
|
2222
|
+
for (const a of attrsArr) {
|
|
2223
|
+
if (a.name.toLowerCase() === "class") {
|
|
2224
|
+
classTokens = splitTokens(a.value);
|
|
2225
|
+
const valueSpan = classValueSpan(loc, code);
|
|
2226
|
+
const clAttr = attrsLocOf(loc)?.["class"];
|
|
2227
|
+
const seg = {
|
|
2228
|
+
kind: "static",
|
|
2229
|
+
span: valueSpan ?? void 0,
|
|
2230
|
+
tokens: classTokens.map((value) => ({ value }))
|
|
2231
|
+
};
|
|
2232
|
+
classes = {
|
|
2233
|
+
form: "string-literal",
|
|
2234
|
+
segments: [seg],
|
|
2235
|
+
valueSpan,
|
|
2236
|
+
attrSpan: clAttr ? span(clAttr.startOffset, clAttr.endOffset) : void 0,
|
|
2237
|
+
hasDynamic: false,
|
|
2238
|
+
opaque: false,
|
|
2239
|
+
rewritable: valueSpan != null
|
|
2240
|
+
};
|
|
2241
|
+
continue;
|
|
2242
|
+
}
|
|
2243
|
+
const v2 = a.value;
|
|
2244
|
+
entries.set(a.name, { kind: "static", value: v2 === "" ? true : v2 });
|
|
2245
|
+
order.push(a.name);
|
|
2246
|
+
}
|
|
2247
|
+
const attrs = { entries, spreads: [], order };
|
|
2248
|
+
const computed2 = resolveComputed(classTokens, tag, id);
|
|
2249
|
+
const children = [];
|
|
2250
|
+
if (!opaqueSubtree) {
|
|
2251
|
+
for (const c of node.childNodes ?? []) appendChild(c, id, children);
|
|
2252
|
+
}
|
|
2253
|
+
const el = createElement(id, {
|
|
2254
|
+
tag,
|
|
2255
|
+
namespace: "html",
|
|
2256
|
+
isComponent: false,
|
|
2257
|
+
selfClosing: loc ? loc.endTag == null : false,
|
|
2258
|
+
classes,
|
|
2259
|
+
computed: computed2,
|
|
2260
|
+
attrs,
|
|
2261
|
+
children,
|
|
2262
|
+
parent: parentId,
|
|
2263
|
+
span: loc ? span(loc.startOffset, loc.endOffset) : null,
|
|
2264
|
+
meta
|
|
2265
|
+
});
|
|
2266
|
+
doc.nodes.set(id, el);
|
|
2267
|
+
if (loc) {
|
|
2268
|
+
backref.set(id, {
|
|
2269
|
+
nodeId: id,
|
|
2270
|
+
span: span(loc.startOffset, loc.endOffset),
|
|
2271
|
+
openTagSpan: loc.startTag ? span(loc.startTag.startOffset, loc.startTag.endOffset) : null,
|
|
2272
|
+
closeTagSpan: loc.endTag ? span(loc.endTag.startOffset, loc.endTag.endOffset) : null,
|
|
2273
|
+
innerSpan: null,
|
|
2274
|
+
selfClosing: loc.endTag == null
|
|
2275
|
+
});
|
|
2276
|
+
}
|
|
2277
|
+
return id;
|
|
2278
|
+
};
|
|
2279
|
+
const rootFrag = doc.nodes.get(doc.root);
|
|
2280
|
+
appendChild(document2, doc.root, rootFrag.children);
|
|
2281
|
+
return { doc, diagnostics };
|
|
2282
|
+
}
|
|
2283
|
+
|
|
2284
|
+
// ../frontend-html/src/index.ts
|
|
2285
|
+
var htmlFrontend = {
|
|
2286
|
+
name: "html",
|
|
2287
|
+
langs: HTML_LANGS,
|
|
2288
|
+
canParse(id, code) {
|
|
2289
|
+
return looksLikeHtml(id, code);
|
|
2290
|
+
},
|
|
2291
|
+
parse(code, ctx) {
|
|
2292
|
+
return doParse(code, ctx);
|
|
2293
|
+
}
|
|
2294
|
+
};
|
|
2295
|
+
function createHtmlFrontend() {
|
|
2296
|
+
return htmlFrontend;
|
|
2297
|
+
}
|
|
2298
|
+
var htmlBackend = {
|
|
2299
|
+
name: "html",
|
|
2300
|
+
langs: HTML_LANGS,
|
|
2301
|
+
print(doc, _plan, _ctx) {
|
|
2302
|
+
return { code: doPrint(doc), map: null, edits: [], diagnostics: [] };
|
|
2303
|
+
}
|
|
2304
|
+
};
|
|
2305
|
+
function createHtmlBackend() {
|
|
2306
|
+
return htmlBackend;
|
|
2307
|
+
}
|
|
2308
|
+
|
|
1613
2309
|
// ../frontend-jsx/src/index.ts
|
|
1614
2310
|
init_cjs_shims();
|
|
1615
2311
|
|
|
@@ -1621,7 +2317,7 @@ init_cjs_shims();
|
|
|
1621
2317
|
var import_traverse = __toESM(require("@babel/traverse"), 1);
|
|
1622
2318
|
var traverse = typeof import_traverse.default === "function" ? import_traverse.default : import_traverse.default.default;
|
|
1623
2319
|
var JSX_LANGS = ["jsx", "tsx"];
|
|
1624
|
-
var
|
|
2320
|
+
var FILE_ID2 = 1;
|
|
1625
2321
|
function jsxName(node) {
|
|
1626
2322
|
switch (node.type) {
|
|
1627
2323
|
case "JSXIdentifier":
|
|
@@ -1746,7 +2442,7 @@ function looksLikeJsx(id, code) {
|
|
|
1746
2442
|
// ../frontend-jsx/src/frontend-parse.ts
|
|
1747
2443
|
init_cjs_shims();
|
|
1748
2444
|
var import_parser = require("@babel/parser");
|
|
1749
|
-
function
|
|
2445
|
+
function doParse2(code, ctx) {
|
|
1750
2446
|
const diagnostics = [];
|
|
1751
2447
|
const doc = createDocument("jsx");
|
|
1752
2448
|
const backref = doc.backref;
|
|
@@ -1756,7 +2452,7 @@ function doParse(code, ctx) {
|
|
|
1756
2452
|
});
|
|
1757
2453
|
const eol = code.includes("\r\n") ? "\r\n" : "\n";
|
|
1758
2454
|
const sourceFile = {
|
|
1759
|
-
id:
|
|
2455
|
+
id: FILE_ID2,
|
|
1760
2456
|
path: ctx.id,
|
|
1761
2457
|
text: code,
|
|
1762
2458
|
frontend: "jsx",
|
|
@@ -1764,23 +2460,23 @@ function doParse(code, ctx) {
|
|
|
1764
2460
|
indentUnit: " ",
|
|
1765
2461
|
native: ast
|
|
1766
2462
|
};
|
|
1767
|
-
doc.sources.set(
|
|
2463
|
+
doc.sources.set(FILE_ID2, sourceFile);
|
|
1768
2464
|
const spanOf = (node) => {
|
|
1769
2465
|
if (node.start == null || node.end == null) return null;
|
|
1770
|
-
const
|
|
1771
|
-
file:
|
|
2466
|
+
const span2 = {
|
|
2467
|
+
file: FILE_ID2,
|
|
1772
2468
|
start: node.start,
|
|
1773
2469
|
end: node.end,
|
|
1774
2470
|
startLoc: node.loc ? { line: node.loc.start.line, column: node.loc.start.column } : void 0,
|
|
1775
2471
|
endLoc: node.loc ? { line: node.loc.end.line, column: node.loc.end.column } : void 0
|
|
1776
2472
|
};
|
|
1777
|
-
return
|
|
2473
|
+
return span2;
|
|
1778
2474
|
};
|
|
1779
2475
|
const sliceOf = (node) => node.start == null || node.end == null ? "" : code.slice(node.start, node.end);
|
|
1780
2476
|
const internExpr = (node, spread) => {
|
|
1781
2477
|
const payload = { text: sliceOf(node), spread };
|
|
1782
2478
|
return doc.exprs.intern({
|
|
1783
|
-
span: spanOf(node) ?? { file:
|
|
2479
|
+
span: spanOf(node) ?? { file: FILE_ID2, start: 0, end: 0 },
|
|
1784
2480
|
kind: exprKind(node),
|
|
1785
2481
|
payload
|
|
1786
2482
|
});
|
|
@@ -1826,7 +2522,7 @@ function doParse(code, ctx) {
|
|
|
1826
2522
|
}
|
|
1827
2523
|
return emptyClassList();
|
|
1828
2524
|
};
|
|
1829
|
-
const
|
|
2525
|
+
const staticTokensOf4 = (classes) => {
|
|
1830
2526
|
const out = [];
|
|
1831
2527
|
for (const seg of classes.segments) {
|
|
1832
2528
|
if (seg.kind === "static") for (const t of seg.tokens) out.push(t.value);
|
|
@@ -1904,7 +2600,7 @@ function doParse(code, ctx) {
|
|
|
1904
2600
|
doc.nodes.set(id, createFragment(id, { children, parent: parentId, span: spanOf(node) }));
|
|
1905
2601
|
backref.set(id, {
|
|
1906
2602
|
nodeId: id,
|
|
1907
|
-
span: spanOf(node) ?? { file:
|
|
2603
|
+
span: spanOf(node) ?? { file: FILE_ID2, start: 0, end: 0 },
|
|
1908
2604
|
openTagSpan: spanOf(node.openingFragment),
|
|
1909
2605
|
closeTagSpan: spanOf(node.closingFragment),
|
|
1910
2606
|
innerSpan: null,
|
|
@@ -1953,7 +2649,7 @@ function doParse(code, ctx) {
|
|
|
1953
2649
|
}
|
|
1954
2650
|
let computed2 = emptyStyleMap();
|
|
1955
2651
|
if (!classes.hasDynamic) {
|
|
1956
|
-
const tokens =
|
|
2652
|
+
const tokens = staticTokensOf4(classes);
|
|
1957
2653
|
if (tokens.length > 0) {
|
|
1958
2654
|
const res = ctx.resolver.resolve({
|
|
1959
2655
|
classes: tokens,
|
|
@@ -1986,13 +2682,13 @@ function doParse(code, ctx) {
|
|
|
1986
2682
|
});
|
|
1987
2683
|
doc.nodes.set(id, el);
|
|
1988
2684
|
const inner = children.length > 0 ? spanOf(node.children[0]) && spanOf(node.children.at(-1)) ? {
|
|
1989
|
-
file:
|
|
2685
|
+
file: FILE_ID2,
|
|
1990
2686
|
start: spanOf(node.children[0]).start,
|
|
1991
2687
|
end: spanOf(node.children.at(-1)).end
|
|
1992
2688
|
} : null : null;
|
|
1993
2689
|
backref.set(id, {
|
|
1994
2690
|
nodeId: id,
|
|
1995
|
-
span: spanOf(node) ?? { file:
|
|
2691
|
+
span: spanOf(node) ?? { file: FILE_ID2, start: 0, end: 0 },
|
|
1996
2692
|
openTagSpan: spanOf(opening),
|
|
1997
2693
|
closeTagSpan: node.closingElement ? spanOf(node.closingElement) : null,
|
|
1998
2694
|
innerSpan: inner,
|
|
@@ -2002,13 +2698,13 @@ function doParse(code, ctx) {
|
|
|
2002
2698
|
};
|
|
2003
2699
|
const roots = [];
|
|
2004
2700
|
traverse(ast, {
|
|
2005
|
-
JSXElement(
|
|
2006
|
-
roots.push(
|
|
2007
|
-
|
|
2701
|
+
JSXElement(path10) {
|
|
2702
|
+
roots.push(path10.node);
|
|
2703
|
+
path10.skip();
|
|
2008
2704
|
},
|
|
2009
|
-
JSXFragment(
|
|
2010
|
-
roots.push(
|
|
2011
|
-
|
|
2705
|
+
JSXFragment(path10) {
|
|
2706
|
+
roots.push(path10.node);
|
|
2707
|
+
path10.skip();
|
|
2012
2708
|
}
|
|
2013
2709
|
});
|
|
2014
2710
|
const rootFrag = doc.nodes.get(doc.root);
|
|
@@ -2027,7 +2723,7 @@ var jsxFrontend = {
|
|
|
2027
2723
|
return looksLikeJsx(id, code);
|
|
2028
2724
|
},
|
|
2029
2725
|
parse(code, ctx) {
|
|
2030
|
-
return
|
|
2726
|
+
return doParse2(code, ctx);
|
|
2031
2727
|
}
|
|
2032
2728
|
};
|
|
2033
2729
|
function createJsxFrontend() {
|
|
@@ -2036,7 +2732,7 @@ function createJsxFrontend() {
|
|
|
2036
2732
|
|
|
2037
2733
|
// ../frontend-jsx/src/backend.ts
|
|
2038
2734
|
init_cjs_shims();
|
|
2039
|
-
var
|
|
2735
|
+
var import_magic_string2 = __toESM(require("magic-string"), 1);
|
|
2040
2736
|
var JSX_LANGS2 = ["jsx", "tsx"];
|
|
2041
2737
|
function exprText(doc, ref) {
|
|
2042
2738
|
const rec = doc.exprs.get(ref);
|
|
@@ -2050,20 +2746,20 @@ function exprText(doc, ref) {
|
|
|
2050
2746
|
}
|
|
2051
2747
|
return { text: "", spread: false };
|
|
2052
2748
|
}
|
|
2053
|
-
function
|
|
2749
|
+
function staticTokensOf3(classes) {
|
|
2054
2750
|
const out = [];
|
|
2055
2751
|
for (const seg of classes.segments) {
|
|
2056
2752
|
if (seg.kind === "static") for (const t of seg.tokens) out.push(t.value);
|
|
2057
2753
|
}
|
|
2058
2754
|
return out;
|
|
2059
2755
|
}
|
|
2060
|
-
function
|
|
2756
|
+
function primarySource2(doc) {
|
|
2061
2757
|
for (const sf of doc.sources.values()) {
|
|
2062
2758
|
if (typeof sf.text === "string" && sf.text.length > 0) return sf;
|
|
2063
2759
|
}
|
|
2064
2760
|
return null;
|
|
2065
2761
|
}
|
|
2066
|
-
function
|
|
2762
|
+
function collectKept2(doc) {
|
|
2067
2763
|
const out = [];
|
|
2068
2764
|
const seen = /* @__PURE__ */ new Set();
|
|
2069
2765
|
const visit = (id) => {
|
|
@@ -2077,15 +2773,15 @@ function collectKept(doc) {
|
|
|
2077
2773
|
visit(doc.root);
|
|
2078
2774
|
return out;
|
|
2079
2775
|
}
|
|
2080
|
-
function
|
|
2776
|
+
function strictlyContains2(a, b3) {
|
|
2081
2777
|
if (a.file !== b3.file) return false;
|
|
2082
2778
|
if (a.start <= b3.start && b3.end <= a.end) return !(a.start === b3.start && a.end === b3.end);
|
|
2083
2779
|
return false;
|
|
2084
2780
|
}
|
|
2085
|
-
function
|
|
2781
|
+
function editClasses2(ms, doc, sf, el) {
|
|
2086
2782
|
const classes = el.classes;
|
|
2087
2783
|
if (classes.hasDynamic || classes.opaque) return false;
|
|
2088
|
-
const tokens =
|
|
2784
|
+
const tokens = staticTokensOf3(classes);
|
|
2089
2785
|
const valueSpan = classes.valueSpan;
|
|
2090
2786
|
if (valueSpan && valueSpan.file === sf.id) {
|
|
2091
2787
|
const current = sf.text.slice(valueSpan.start, valueSpan.end);
|
|
@@ -2149,10 +2845,10 @@ function transferKeyOnUnwrap(ms, doc, sf, region, kept) {
|
|
|
2149
2845
|
const inside = [];
|
|
2150
2846
|
for (const n of kept) {
|
|
2151
2847
|
if (n.kind !== "element" || !n.span || n.span.file !== sf.id) continue;
|
|
2152
|
-
if (
|
|
2848
|
+
if (strictlyContains2(region.span, n.span)) inside.push(n);
|
|
2153
2849
|
}
|
|
2154
2850
|
const maximal = inside.filter(
|
|
2155
|
-
(n) => !inside.some((o2) => o2 !== n && o2.span && n.span &&
|
|
2851
|
+
(n) => !inside.some((o2) => o2 !== n && o2.span && n.span && strictlyContains2(o2.span, n.span))
|
|
2156
2852
|
);
|
|
2157
2853
|
if (maximal.length !== 1) return;
|
|
2158
2854
|
const child = maximal[0];
|
|
@@ -2161,25 +2857,25 @@ function transferKeyOnUnwrap(ms, doc, sf, region, kept) {
|
|
|
2161
2857
|
if (extractKeyAttr(sf.text.slice(childOpen.start, childOpen.end))) return;
|
|
2162
2858
|
ms.appendLeft(childOpen.start + 1 + child.tag.length, ` ${keyAttr}`);
|
|
2163
2859
|
}
|
|
2164
|
-
function
|
|
2165
|
-
const sf =
|
|
2860
|
+
function surgicalPrint2(doc) {
|
|
2861
|
+
const sf = primarySource2(doc);
|
|
2166
2862
|
if (!sf) return null;
|
|
2167
|
-
const ms = new
|
|
2168
|
-
const kept =
|
|
2863
|
+
const ms = new import_magic_string2.default(sf.text);
|
|
2864
|
+
const kept = collectKept2(doc);
|
|
2169
2865
|
const keptSpans = [];
|
|
2170
2866
|
for (const n of kept) if (n.span && n.span.file === sf.id) keptSpans.push(n.span);
|
|
2171
2867
|
const removed = [];
|
|
2172
|
-
for (const id of
|
|
2868
|
+
for (const id of backrefIds2(doc)) {
|
|
2173
2869
|
if (doc.nodes.has(id)) continue;
|
|
2174
2870
|
const back = doc.backref.get(id);
|
|
2175
2871
|
if (!back || back.span.file !== sf.id) continue;
|
|
2176
|
-
const unwrapped = keptSpans.some((k3) =>
|
|
2872
|
+
const unwrapped = keptSpans.some((k3) => strictlyContains2(back.span, k3));
|
|
2177
2873
|
removed.push({ backref: back, unwrapped });
|
|
2178
2874
|
}
|
|
2179
2875
|
const fullRemovals = removed.filter((r2) => !r2.unwrapped).map((r2) => r2.backref.span);
|
|
2180
2876
|
for (const r2 of removed) {
|
|
2181
|
-
const
|
|
2182
|
-
const coveredByFull = fullRemovals.some((f) => f !==
|
|
2877
|
+
const span2 = r2.backref.span;
|
|
2878
|
+
const coveredByFull = fullRemovals.some((f) => f !== span2 && strictlyContains2(f, span2));
|
|
2183
2879
|
if (coveredByFull) continue;
|
|
2184
2880
|
if (r2.unwrapped) {
|
|
2185
2881
|
transferKeyOnUnwrap(ms, doc, sf, r2.backref, kept);
|
|
@@ -2190,15 +2886,15 @@ function surgicalPrint(doc) {
|
|
|
2190
2886
|
ms.remove(close.start, close.end);
|
|
2191
2887
|
}
|
|
2192
2888
|
} else {
|
|
2193
|
-
ms.remove(
|
|
2889
|
+
ms.remove(span2.start, span2.end);
|
|
2194
2890
|
}
|
|
2195
2891
|
}
|
|
2196
2892
|
for (const n of kept) {
|
|
2197
|
-
if (n.kind === "element")
|
|
2893
|
+
if (n.kind === "element") editClasses2(ms, doc, sf, n);
|
|
2198
2894
|
}
|
|
2199
2895
|
return ms.toString();
|
|
2200
2896
|
}
|
|
2201
|
-
function
|
|
2897
|
+
function backrefIds2(doc) {
|
|
2202
2898
|
const out = [];
|
|
2203
2899
|
const max = doc.alloc.peek;
|
|
2204
2900
|
for (let i = 1; i < max; i += 1) {
|
|
@@ -2213,7 +2909,7 @@ function classText(doc, classes) {
|
|
|
2213
2909
|
if (dynamic && dynamic.kind === "dynamic") {
|
|
2214
2910
|
return `className={${exprText(doc, dynamic.expr).text}}`;
|
|
2215
2911
|
}
|
|
2216
|
-
const tokens =
|
|
2912
|
+
const tokens = staticTokensOf3(classes);
|
|
2217
2913
|
return `className="${tokens.join(" ")}"`;
|
|
2218
2914
|
}
|
|
2219
2915
|
function attrText(doc, name, value) {
|
|
@@ -2266,15 +2962,15 @@ function rePrint(doc) {
|
|
|
2266
2962
|
if (!root || root.kind !== "fragment") return printNode(doc, doc.root);
|
|
2267
2963
|
return root.children.map((c) => printNode(doc, c)).join("");
|
|
2268
2964
|
}
|
|
2269
|
-
function
|
|
2270
|
-
const surgical =
|
|
2965
|
+
function doPrint2(doc) {
|
|
2966
|
+
const surgical = surgicalPrint2(doc);
|
|
2271
2967
|
return surgical ?? rePrint(doc);
|
|
2272
2968
|
}
|
|
2273
2969
|
var jsxBackend = {
|
|
2274
2970
|
name: "babel-jsx",
|
|
2275
2971
|
langs: JSX_LANGS2,
|
|
2276
2972
|
print(doc, _plan, _ctx) {
|
|
2277
|
-
const code =
|
|
2973
|
+
const code = doPrint2(doc);
|
|
2278
2974
|
return { code, map: null, edits: [], diagnostics: [] };
|
|
2279
2975
|
}
|
|
2280
2976
|
};
|
|
@@ -2994,19 +3690,28 @@ var flexCenterWrapper = definePattern({
|
|
|
2994
3690
|
flattenInto: "child",
|
|
2995
3691
|
childGains: { placeSelf: "center" }
|
|
2996
3692
|
},
|
|
2997
|
-
// Collapsing a flex-centering wrapper to `place-self:center` on the child
|
|
2998
|
-
// the child's NEW parent is
|
|
2999
|
-
//
|
|
3000
|
-
//
|
|
3001
|
-
//
|
|
3002
|
-
// unwrap, opacity-barrier safety) is
|
|
3693
|
+
// Collapsing a flex-centering wrapper to `place-self:center` on the child is render-identical ONLY
|
|
3694
|
+
// when the child's NEW parent is a statically-known GRID that lets the wrapper fill its area (there
|
|
3695
|
+
// `place-self`'s align-self AND justify-self both take effect). Under that ONE context the flatten is
|
|
3696
|
+
// classified `provably-safe` and commits; under a flex/block/unknown parent — or when the wrapper
|
|
3697
|
+
// drops any own style — it stays `needs-verification` and the conservative production gate PRESERVES
|
|
3698
|
+
// it. Op-level correctness (purity, id-preserving unwrap, opacity-barrier safety) is additionally
|
|
3699
|
+
// asserted by the invariant suite over every pattern.
|
|
3003
3700
|
test: {
|
|
3701
|
+
cases: [
|
|
3702
|
+
{
|
|
3703
|
+
name: "grid parent \u2192 flattened (child gains place-self-center)",
|
|
3704
|
+
before: '<div className="grid"><div className="flex items-center justify-center"><span className="bg-red-200">x</span></div></div>',
|
|
3705
|
+
after: '<div className="grid"><span className="bg-red-200 place-self-center">x</span></div>'
|
|
3706
|
+
}
|
|
3707
|
+
],
|
|
3004
3708
|
noMatch: [
|
|
3005
|
-
//
|
|
3006
|
-
// (the wrapper itself establishes a flex formatting context) → left unchanged.
|
|
3007
|
-
'<div className="grid"><div className="flex items-center justify-center"><span className="bg-red-200">x</span></div></div>',
|
|
3008
|
-
// Non-flex/grid parent (document root): place-self centering would not hold → left unchanged.
|
|
3709
|
+
// Non-grid (flex) parent (document root): `justify-self` is ignored in flex → not provably safe.
|
|
3009
3710
|
'<div className="flex justify-center items-center"><div className="bg-red-200">Hello</div></div>',
|
|
3711
|
+
// Grid parent, but the wrapper drops padding when removed → not layout-neutral (rule 3).
|
|
3712
|
+
'<div className="grid"><div className="p-4 flex items-center justify-center"><span className="bg-red-200">x</span></div></div>',
|
|
3713
|
+
// Grid parent forcing place-items-center: the wrapper would not fill its area → fill guard skips.
|
|
3714
|
+
'<div className="grid place-items-center"><div className="flex items-center justify-center"><span className="bg-red-200">x</span></div></div>',
|
|
3010
3715
|
// onClick is a hard opacity barrier → the wrapper is load-bearing regardless of the gate.
|
|
3011
3716
|
'<div className="flex justify-center items-center" onClick={handleClick}><div className="bg-red-200">Hello</div></div>'
|
|
3012
3717
|
]
|
|
@@ -4226,11 +4931,11 @@ var paddingShorthand = definePattern({
|
|
|
4226
4931
|
|
|
4227
4932
|
// ../patterns/src/library/compress/place-shorthand.pattern.ts
|
|
4228
4933
|
init_cjs_shims();
|
|
4229
|
-
var
|
|
4230
|
-
var
|
|
4231
|
-
var
|
|
4934
|
+
var ALIGN_ITEMS2 = "align-items";
|
|
4935
|
+
var JUSTIFY_ITEMS2 = "justify-items";
|
|
4936
|
+
var PLACE_ITEMS2 = "place-items";
|
|
4232
4937
|
var ALIGN_CONTENT = "align-content";
|
|
4233
|
-
var
|
|
4938
|
+
var JUSTIFY_CONTENT2 = "justify-content";
|
|
4234
4939
|
var PLACE_CONTENT = "place-content";
|
|
4235
4940
|
var BASE_KEY8 = conditionKey(BASE_CONDITION);
|
|
4236
4941
|
function samePair(a, b3) {
|
|
@@ -4270,21 +4975,21 @@ var placeShorthand = definePattern({
|
|
|
4270
4975
|
rewriteClasses(computed2) {
|
|
4271
4976
|
const base = computed2.blocks.get(BASE_KEY8);
|
|
4272
4977
|
if (!base) return null;
|
|
4273
|
-
const alignItems = base.decls.get(
|
|
4274
|
-
const justifyItems = base.decls.get(
|
|
4978
|
+
const alignItems = base.decls.get(ALIGN_ITEMS2);
|
|
4979
|
+
const justifyItems = base.decls.get(JUSTIFY_ITEMS2);
|
|
4275
4980
|
const alignContent = base.decls.get(ALIGN_CONTENT);
|
|
4276
|
-
const justifyContent = base.decls.get(
|
|
4981
|
+
const justifyContent = base.decls.get(JUSTIFY_CONTENT2);
|
|
4277
4982
|
const next = new Map(base.decls);
|
|
4278
4983
|
let collapsed = false;
|
|
4279
4984
|
if (samePair(alignItems, justifyItems)) {
|
|
4280
|
-
next.delete(
|
|
4281
|
-
next.delete(
|
|
4282
|
-
next.set(
|
|
4985
|
+
next.delete(ALIGN_ITEMS2);
|
|
4986
|
+
next.delete(JUSTIFY_ITEMS2);
|
|
4987
|
+
next.set(PLACE_ITEMS2, placeDecl(PLACE_ITEMS2, alignItems));
|
|
4283
4988
|
collapsed = true;
|
|
4284
4989
|
}
|
|
4285
4990
|
if (samePair(alignContent, justifyContent)) {
|
|
4286
4991
|
next.delete(ALIGN_CONTENT);
|
|
4287
|
-
next.delete(
|
|
4992
|
+
next.delete(JUSTIFY_CONTENT2);
|
|
4288
4993
|
next.set(PLACE_CONTENT, placeDecl(PLACE_CONTENT, alignContent));
|
|
4289
4994
|
collapsed = true;
|
|
4290
4995
|
}
|
|
@@ -4621,19 +5326,19 @@ init_cjs_shims();
|
|
|
4621
5326
|
|
|
4622
5327
|
// ../resolver-css/src/engine.ts
|
|
4623
5328
|
init_cjs_shims();
|
|
4624
|
-
var
|
|
4625
|
-
var
|
|
5329
|
+
var import_node_module2 = require("module");
|
|
5330
|
+
var path3 = __toESM(require("path"), 1);
|
|
4626
5331
|
function moduleBase() {
|
|
4627
5332
|
return typeof __filename === "string" ? __filename : importMetaUrl;
|
|
4628
5333
|
}
|
|
4629
5334
|
function loadPostcssEngine(projectRoot) {
|
|
4630
5335
|
const bases = [];
|
|
4631
|
-
if (projectRoot) bases.push(
|
|
4632
|
-
bases.push(
|
|
5336
|
+
if (projectRoot) bases.push(path3.join(projectRoot, "__domflax__.js"));
|
|
5337
|
+
bases.push(path3.join(process.cwd(), "__domflax__.js"));
|
|
4633
5338
|
bases.push(moduleBase());
|
|
4634
5339
|
for (const base of bases) {
|
|
4635
5340
|
try {
|
|
4636
|
-
const req = (0,
|
|
5341
|
+
const req = (0, import_node_module2.createRequire)(base);
|
|
4637
5342
|
req.resolve("postcss");
|
|
4638
5343
|
req.resolve("postcss-selector-parser");
|
|
4639
5344
|
const postcss = req("postcss");
|
|
@@ -4684,15 +5389,15 @@ function collectDecls(rule) {
|
|
|
4684
5389
|
|
|
4685
5390
|
// ../resolver-css/src/misc-helpers.ts
|
|
4686
5391
|
init_cjs_shims();
|
|
4687
|
-
var
|
|
5392
|
+
var import_node_fs2 = require("fs");
|
|
4688
5393
|
function isPlainClassToken(token) {
|
|
4689
5394
|
return token.length > 0 && !/[\s.#>+~:[\]()]/.test(token);
|
|
4690
5395
|
}
|
|
4691
|
-
function readCssPath(
|
|
5396
|
+
function readCssPath(path10) {
|
|
4692
5397
|
try {
|
|
4693
|
-
return { id:
|
|
5398
|
+
return { id: path10, css: (0, import_node_fs2.readFileSync)(path10, "utf8") };
|
|
4694
5399
|
} catch (cause) {
|
|
4695
|
-
throw new Error(`resolver-css: cannot read CSS file "${
|
|
5400
|
+
throw new Error(`resolver-css: cannot read CSS file "${path10}"`, { cause });
|
|
4696
5401
|
}
|
|
4697
5402
|
}
|
|
4698
5403
|
function deriveFingerprint(provider, files) {
|
|
@@ -5070,19 +5775,19 @@ function synthesizeResidual(remaining, ctx) {
|
|
|
5070
5775
|
|
|
5071
5776
|
// ../resolver-tailwind/src/tailwind/engine.ts
|
|
5072
5777
|
init_cjs_shims();
|
|
5073
|
-
var
|
|
5074
|
-
var
|
|
5778
|
+
var import_node_module3 = require("module");
|
|
5779
|
+
var path4 = __toESM(require("path"), 1);
|
|
5075
5780
|
function moduleBase2() {
|
|
5076
5781
|
return typeof __filename === "string" ? __filename : importMetaUrl;
|
|
5077
5782
|
}
|
|
5078
5783
|
function projectRequire(projectRoot) {
|
|
5079
5784
|
const bases = [];
|
|
5080
|
-
if (projectRoot) bases.push(
|
|
5081
|
-
bases.push(
|
|
5785
|
+
if (projectRoot) bases.push(path4.join(projectRoot, "__domflax__.js"));
|
|
5786
|
+
bases.push(path4.join(process.cwd(), "__domflax__.js"));
|
|
5082
5787
|
bases.push(moduleBase2());
|
|
5083
5788
|
for (const base of bases) {
|
|
5084
5789
|
try {
|
|
5085
|
-
const candidate = (0,
|
|
5790
|
+
const candidate = (0, import_node_module3.createRequire)(base);
|
|
5086
5791
|
candidate.resolve("tailwindcss/package.json");
|
|
5087
5792
|
return candidate;
|
|
5088
5793
|
} catch {
|
|
@@ -5501,6 +6206,74 @@ function createTailwindResolver(config) {
|
|
|
5501
6206
|
return new TailwindResolver(config);
|
|
5502
6207
|
}
|
|
5503
6208
|
|
|
6209
|
+
// ../cli/src/transform.ts
|
|
6210
|
+
var path6 = __toESM(require("path"), 1);
|
|
6211
|
+
|
|
6212
|
+
// ../cli/src/html-css.ts
|
|
6213
|
+
init_cjs_shims();
|
|
6214
|
+
var import_node_crypto = require("crypto");
|
|
6215
|
+
var import_node_fs3 = require("fs");
|
|
6216
|
+
var path5 = __toESM(require("path"), 1);
|
|
6217
|
+
function isRemoteHref(href) {
|
|
6218
|
+
const h2 = href.trim();
|
|
6219
|
+
return h2.startsWith("//") || /^[a-z][a-z0-9+.-]*:/i.test(h2);
|
|
6220
|
+
}
|
|
6221
|
+
function attrValue(tag, name) {
|
|
6222
|
+
const re = new RegExp(`\\b${name}\\s*=\\s*(?:"([^"]*)"|'([^']*)'|([^\\s"'>]+))`, "i");
|
|
6223
|
+
const m2 = re.exec(tag);
|
|
6224
|
+
if (!m2) return null;
|
|
6225
|
+
return (m2[1] ?? m2[2] ?? m2[3] ?? "").trim();
|
|
6226
|
+
}
|
|
6227
|
+
function extractLinkHrefs(html) {
|
|
6228
|
+
const out = [];
|
|
6229
|
+
const linkRe = /<link\b[^>]*>/gi;
|
|
6230
|
+
let m2;
|
|
6231
|
+
while ((m2 = linkRe.exec(html)) !== null) {
|
|
6232
|
+
const tag = m2[0];
|
|
6233
|
+
const rel = attrValue(tag, "rel");
|
|
6234
|
+
if (rel === null || !/(?:^|\s)stylesheet(?:\s|$)/i.test(rel)) continue;
|
|
6235
|
+
const href = attrValue(tag, "href");
|
|
6236
|
+
if (href) out.push(href);
|
|
6237
|
+
}
|
|
6238
|
+
return out;
|
|
6239
|
+
}
|
|
6240
|
+
function extractInlineStyles(html) {
|
|
6241
|
+
const out = [];
|
|
6242
|
+
const styleRe = /<style\b([^>]*)>([\s\S]*?)<\/style>/gi;
|
|
6243
|
+
let m2;
|
|
6244
|
+
while ((m2 = styleRe.exec(html)) !== null) {
|
|
6245
|
+
const type = attrValue(`<style ${m2[1] ?? ""}>`, "type")?.toLowerCase();
|
|
6246
|
+
if (type && type !== "text/css" && type !== "css") continue;
|
|
6247
|
+
const css = m2[2] ?? "";
|
|
6248
|
+
if (css.trim().length > 0) out.push(css);
|
|
6249
|
+
}
|
|
6250
|
+
return out;
|
|
6251
|
+
}
|
|
6252
|
+
function extractHtmlStylesheets(htmlCode, htmlAbsPath) {
|
|
6253
|
+
const dir = path5.dirname(path5.resolve(htmlAbsPath));
|
|
6254
|
+
const files = [];
|
|
6255
|
+
const seen = /* @__PURE__ */ new Set();
|
|
6256
|
+
for (const rawHref of extractLinkHrefs(htmlCode)) {
|
|
6257
|
+
const href = (rawHref.split(/[?#]/, 1)[0] ?? "").trim();
|
|
6258
|
+
if (!href || isRemoteHref(href)) continue;
|
|
6259
|
+
const abs = path5.resolve(dir, href);
|
|
6260
|
+
if (seen.has(abs)) continue;
|
|
6261
|
+
seen.add(abs);
|
|
6262
|
+
if ((0, import_node_fs3.existsSync)(abs)) files.push(abs);
|
|
6263
|
+
}
|
|
6264
|
+
return { files, inline: extractInlineStyles(htmlCode) };
|
|
6265
|
+
}
|
|
6266
|
+
function cssSetKey(sortedResolvedPaths, inline) {
|
|
6267
|
+
const h2 = (0, import_node_crypto.createHash)("sha1");
|
|
6268
|
+
h2.update(sortedResolvedPaths.join("\n"));
|
|
6269
|
+
h2.update("\0inline\0");
|
|
6270
|
+
for (const block of inline) {
|
|
6271
|
+
h2.update(block);
|
|
6272
|
+
h2.update("\0");
|
|
6273
|
+
}
|
|
6274
|
+
return h2.digest("hex");
|
|
6275
|
+
}
|
|
6276
|
+
|
|
5504
6277
|
// ../cli/src/transform.ts
|
|
5505
6278
|
function buildResolver(provider, css, projectRoot) {
|
|
5506
6279
|
if (provider === "custom") {
|
|
@@ -5537,6 +6310,11 @@ function jsxKindOf(id) {
|
|
|
5537
6310
|
if (lower.endsWith(".jsx")) return "jsx";
|
|
5538
6311
|
return null;
|
|
5539
6312
|
}
|
|
6313
|
+
function htmlKindOf(id) {
|
|
6314
|
+
const lower = (id.split("?", 1)[0] ?? id).toLowerCase();
|
|
6315
|
+
if (lower.endsWith(".html") || lower.endsWith(".htm")) return "html";
|
|
6316
|
+
return null;
|
|
6317
|
+
}
|
|
5540
6318
|
function countClassTokens(code) {
|
|
5541
6319
|
let total = 0;
|
|
5542
6320
|
const re = /\b(?:className|class)\s*=\s*"([^"]*)"/g;
|
|
@@ -5569,9 +6347,25 @@ function passthroughResult(code) {
|
|
|
5569
6347
|
}
|
|
5570
6348
|
function createTransform(options) {
|
|
5571
6349
|
const projectRoot = options.projectRoot ?? process.cwd();
|
|
5572
|
-
const
|
|
6350
|
+
const globalResolver = buildResolver(options.provider, options.css, projectRoot);
|
|
5573
6351
|
const patterns = selectPatterns(options.passes);
|
|
5574
|
-
|
|
6352
|
+
const resolverCache = /* @__PURE__ */ new Map();
|
|
6353
|
+
function resolverFor(code, id) {
|
|
6354
|
+
if (options.provider !== "custom" || htmlKindOf(id) === null) return globalResolver;
|
|
6355
|
+
const { files: localFiles, inline } = extractHtmlStylesheets(code, id);
|
|
6356
|
+
if (localFiles.length === 0 && inline.length === 0) return globalResolver;
|
|
6357
|
+
const globalPaths = options.css.map((p2) => path6.resolve(p2));
|
|
6358
|
+
const sortedPaths = [.../* @__PURE__ */ new Set([...globalPaths, ...localFiles])].sort();
|
|
6359
|
+
const key = cssSetKey(sortedPaths, inline);
|
|
6360
|
+
let resolver = resolverCache.get(key);
|
|
6361
|
+
if (!resolver) {
|
|
6362
|
+
const inlineFiles = inline.map((css, i) => ({ id: `${id}#inline-${i}`, css }));
|
|
6363
|
+
resolver = createCssResolver(inlineFiles, { files: sortedPaths, projectRoot });
|
|
6364
|
+
resolverCache.set(key, resolver);
|
|
6365
|
+
}
|
|
6366
|
+
return resolver;
|
|
6367
|
+
}
|
|
6368
|
+
function prepare(code, id, kind, gate, resolver) {
|
|
5575
6369
|
const parsed = createJsxFrontend().parse(code, {
|
|
5576
6370
|
id,
|
|
5577
6371
|
kind,
|
|
@@ -5596,9 +6390,32 @@ function createTransform(options) {
|
|
|
5596
6390
|
};
|
|
5597
6391
|
return { doc, ctx, passes: buildPasses(patterns), nodesIn };
|
|
5598
6392
|
}
|
|
5599
|
-
function
|
|
6393
|
+
function prepareHtml(code, id, gate, resolver) {
|
|
6394
|
+
const parsed = createHtmlFrontend().parse(code, {
|
|
6395
|
+
id,
|
|
6396
|
+
kind: "html",
|
|
6397
|
+
resolver,
|
|
6398
|
+
normalizer,
|
|
6399
|
+
config: {},
|
|
6400
|
+
onDiagnostic: () => {
|
|
6401
|
+
}
|
|
6402
|
+
});
|
|
6403
|
+
const doc = parsed.doc;
|
|
6404
|
+
const nodesIn = doc.nodes.size;
|
|
6405
|
+
const ctx = {
|
|
6406
|
+
doc,
|
|
6407
|
+
safetyCeiling: options.safety,
|
|
6408
|
+
normalizer,
|
|
6409
|
+
selectors: buildSelectorIndex(doc, resolver),
|
|
6410
|
+
resolver,
|
|
6411
|
+
gate
|
|
6412
|
+
};
|
|
6413
|
+
return { doc, ctx, passes: buildPasses(patterns), nodesIn };
|
|
6414
|
+
}
|
|
6415
|
+
function finish(code, optimized, id, nodesIn, resolver, backend = "jsx") {
|
|
5600
6416
|
syncClassesFromComputed(optimized, resolver, normalizer);
|
|
5601
|
-
const
|
|
6417
|
+
const print = backend === "html" ? createHtmlBackend().print : createJsxBackend().print;
|
|
6418
|
+
const printed = print(
|
|
5602
6419
|
optimized,
|
|
5603
6420
|
{ moduleId: id, ops: [], provenance: /* @__PURE__ */ new Map() },
|
|
5604
6421
|
{ normalizer, resolver, sink: createSyntheticSink(), eol: "\n", onDiagnostic: () => {
|
|
@@ -5626,13 +6443,22 @@ function createTransform(options) {
|
|
|
5626
6443
|
};
|
|
5627
6444
|
}
|
|
5628
6445
|
return {
|
|
5629
|
-
resolver,
|
|
6446
|
+
resolver: globalResolver,
|
|
5630
6447
|
transformFile(code, id) {
|
|
5631
6448
|
const kind = jsxKindOf(id);
|
|
5632
|
-
if (kind
|
|
5633
|
-
|
|
5634
|
-
|
|
5635
|
-
|
|
6449
|
+
if (kind !== null) {
|
|
6450
|
+
const resolver = resolverFor(code, id);
|
|
6451
|
+
const { doc, ctx, passes, nodesIn } = prepare(code, id, kind, "provably-safe", resolver);
|
|
6452
|
+
const { doc: optimized } = runPasses(doc, passes, ctx);
|
|
6453
|
+
return finish(code, optimized, id, nodesIn, resolver);
|
|
6454
|
+
}
|
|
6455
|
+
if (htmlKindOf(id) !== null) {
|
|
6456
|
+
const resolver = resolverFor(code, id);
|
|
6457
|
+
const { doc, ctx, passes, nodesIn } = prepareHtml(code, id, "provably-safe", resolver);
|
|
6458
|
+
const { doc: optimized } = runPasses(doc, passes, ctx);
|
|
6459
|
+
return finish(code, optimized, id, nodesIn, resolver, "html");
|
|
6460
|
+
}
|
|
6461
|
+
return passthroughResult(code);
|
|
5636
6462
|
}
|
|
5637
6463
|
};
|
|
5638
6464
|
}
|
|
@@ -5640,22 +6466,17 @@ function createTransform(options) {
|
|
|
5640
6466
|
// ../cli/src/walk.ts
|
|
5641
6467
|
init_cjs_shims();
|
|
5642
6468
|
var fs = __toESM(require("fs"), 1);
|
|
5643
|
-
var
|
|
5644
|
-
var SUPPORTED_EXTS = [".jsx", ".tsx"];
|
|
5645
|
-
var HTML_EXTS = [".html", ".htm"];
|
|
6469
|
+
var path7 = __toESM(require("path"), 1);
|
|
6470
|
+
var SUPPORTED_EXTS = [".jsx", ".tsx", ".html", ".htm"];
|
|
5646
6471
|
var SKIP_DIRS = /* @__PURE__ */ new Set(["node_modules", ".git", "domflax-out"]);
|
|
5647
6472
|
function isSupported(file) {
|
|
5648
6473
|
const lower = file.toLowerCase();
|
|
5649
6474
|
return SUPPORTED_EXTS.some((ext) => lower.endsWith(ext));
|
|
5650
6475
|
}
|
|
5651
|
-
function isHtml(file) {
|
|
5652
|
-
const lower = file.toLowerCase();
|
|
5653
|
-
return HTML_EXTS.some((ext) => lower.endsWith(ext));
|
|
5654
|
-
}
|
|
5655
6476
|
function hasGlobMagic(p2) {
|
|
5656
6477
|
return /[*?[\]{}]/.test(p2);
|
|
5657
6478
|
}
|
|
5658
|
-
function walkDir(dir, out
|
|
6479
|
+
function walkDir(dir, out) {
|
|
5659
6480
|
let entries;
|
|
5660
6481
|
try {
|
|
5661
6482
|
entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
@@ -5663,13 +6484,12 @@ function walkDir(dir, out, counts) {
|
|
|
5663
6484
|
return;
|
|
5664
6485
|
}
|
|
5665
6486
|
for (const entry of entries) {
|
|
5666
|
-
const full =
|
|
6487
|
+
const full = path7.join(dir, entry.name);
|
|
5667
6488
|
if (entry.isDirectory()) {
|
|
5668
6489
|
if (SKIP_DIRS.has(entry.name)) continue;
|
|
5669
|
-
walkDir(full, out
|
|
6490
|
+
walkDir(full, out);
|
|
5670
6491
|
} else if (entry.isFile()) {
|
|
5671
6492
|
if (isSupported(entry.name)) out.push(full);
|
|
5672
|
-
else if (isHtml(entry.name)) counts.html += 1;
|
|
5673
6493
|
}
|
|
5674
6494
|
}
|
|
5675
6495
|
}
|
|
@@ -5680,10 +6500,9 @@ function globSyncMaybe() {
|
|
|
5680
6500
|
function discoverInputs(paths) {
|
|
5681
6501
|
const files = [];
|
|
5682
6502
|
const warnings = [];
|
|
5683
|
-
const counts = { html: 0 };
|
|
5684
6503
|
const seen = /* @__PURE__ */ new Set();
|
|
5685
6504
|
const push = (f) => {
|
|
5686
|
-
const abs =
|
|
6505
|
+
const abs = path7.resolve(f);
|
|
5687
6506
|
if (!seen.has(abs)) {
|
|
5688
6507
|
seen.add(abs);
|
|
5689
6508
|
files.push(abs);
|
|
@@ -5692,7 +6511,7 @@ function discoverInputs(paths) {
|
|
|
5692
6511
|
let inputRoot = process.cwd();
|
|
5693
6512
|
if (paths.length === 1) {
|
|
5694
6513
|
try {
|
|
5695
|
-
if (fs.statSync(paths[0]).isDirectory()) inputRoot =
|
|
6514
|
+
if (fs.statSync(paths[0]).isDirectory()) inputRoot = path7.resolve(paths[0]);
|
|
5696
6515
|
} catch {
|
|
5697
6516
|
}
|
|
5698
6517
|
}
|
|
@@ -5704,12 +6523,11 @@ function discoverInputs(paths) {
|
|
|
5704
6523
|
stat = null;
|
|
5705
6524
|
}
|
|
5706
6525
|
if (stat?.isDirectory()) {
|
|
5707
|
-
walkDir(
|
|
6526
|
+
walkDir(path7.resolve(p2), files);
|
|
5708
6527
|
continue;
|
|
5709
6528
|
}
|
|
5710
6529
|
if (stat?.isFile()) {
|
|
5711
6530
|
if (isSupported(p2)) push(p2);
|
|
5712
|
-
else if (isHtml(p2)) counts.html += 1;
|
|
5713
6531
|
else warnings.push(`unsupported file type, skipped: ${p2}`);
|
|
5714
6532
|
continue;
|
|
5715
6533
|
}
|
|
@@ -5721,8 +6539,7 @@ function discoverInputs(paths) {
|
|
|
5721
6539
|
}
|
|
5722
6540
|
const matched = glob(p2);
|
|
5723
6541
|
const supported = matched.filter(isSupported);
|
|
5724
|
-
|
|
5725
|
-
if (supported.length === 0) warnings.push(`no .jsx/.tsx files matched: ${p2}`);
|
|
6542
|
+
if (supported.length === 0) warnings.push(`no .jsx/.tsx/.html files matched: ${p2}`);
|
|
5726
6543
|
for (const m2 of supported) push(m2);
|
|
5727
6544
|
continue;
|
|
5728
6545
|
}
|
|
@@ -5731,17 +6548,12 @@ function discoverInputs(paths) {
|
|
|
5731
6548
|
const deduped = [];
|
|
5732
6549
|
const finalSeen = /* @__PURE__ */ new Set();
|
|
5733
6550
|
for (const f of files) {
|
|
5734
|
-
const abs =
|
|
6551
|
+
const abs = path7.resolve(f);
|
|
5735
6552
|
if (!finalSeen.has(abs)) {
|
|
5736
6553
|
finalSeen.add(abs);
|
|
5737
6554
|
deduped.push(abs);
|
|
5738
6555
|
}
|
|
5739
6556
|
}
|
|
5740
|
-
if (deduped.length === 0 && counts.html > 0) {
|
|
5741
|
-
warnings.push(
|
|
5742
|
-
`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).`
|
|
5743
|
-
);
|
|
5744
|
-
}
|
|
5745
6557
|
return { files: deduped, inputRoot, warnings };
|
|
5746
6558
|
}
|
|
5747
6559
|
|
|
@@ -6329,7 +7141,7 @@ var J2 = `${import_picocolors2.default.gray(o)} `;
|
|
|
6329
7141
|
// ../cli/src/detect.ts
|
|
6330
7142
|
init_cjs_shims();
|
|
6331
7143
|
var fs2 = __toESM(require("fs"), 1);
|
|
6332
|
-
var
|
|
7144
|
+
var path8 = __toESM(require("path"), 1);
|
|
6333
7145
|
var SKIP_DIRS2 = /* @__PURE__ */ new Set([
|
|
6334
7146
|
"node_modules",
|
|
6335
7147
|
"dist",
|
|
@@ -6344,11 +7156,11 @@ var COMMON_INPUT_DIRS = ["src", "app", "components", "pages", "lib", "ui", "publ
|
|
|
6344
7156
|
var CSS_FILE_CAP = 200;
|
|
6345
7157
|
var DEFAULT_CSS_DEPTH = 10;
|
|
6346
7158
|
function toRelative(root, abs) {
|
|
6347
|
-
const rel =
|
|
6348
|
-
return rel.split(
|
|
7159
|
+
const rel = path8.relative(root, abs);
|
|
7160
|
+
return rel.split(path8.sep).join("/");
|
|
6349
7161
|
}
|
|
6350
7162
|
function detectCssFiles(root, scanRoots = [], maxDepth = DEFAULT_CSS_DEPTH) {
|
|
6351
|
-
const base =
|
|
7163
|
+
const base = path8.resolve(root);
|
|
6352
7164
|
const found = /* @__PURE__ */ new Map();
|
|
6353
7165
|
let capped = false;
|
|
6354
7166
|
const walk = (dir, depth) => {
|
|
@@ -6360,13 +7172,13 @@ function detectCssFiles(root, scanRoots = [], maxDepth = DEFAULT_CSS_DEPTH) {
|
|
|
6360
7172
|
return;
|
|
6361
7173
|
}
|
|
6362
7174
|
for (const entry of entries) {
|
|
6363
|
-
const full =
|
|
7175
|
+
const full = path8.join(dir, entry.name);
|
|
6364
7176
|
if (entry.isDirectory()) {
|
|
6365
7177
|
if (SKIP_DIRS2.has(entry.name)) continue;
|
|
6366
7178
|
walk(full, depth + 1);
|
|
6367
7179
|
if (capped) return;
|
|
6368
7180
|
} else if (entry.isFile() && entry.name.toLowerCase().endsWith(".css")) {
|
|
6369
|
-
const abs =
|
|
7181
|
+
const abs = path8.resolve(full);
|
|
6370
7182
|
if (!found.has(abs)) {
|
|
6371
7183
|
found.set(abs, toRelative(base, abs));
|
|
6372
7184
|
if (found.size >= CSS_FILE_CAP) {
|
|
@@ -6380,7 +7192,7 @@ function detectCssFiles(root, scanRoots = [], maxDepth = DEFAULT_CSS_DEPTH) {
|
|
|
6380
7192
|
walk(base, 0);
|
|
6381
7193
|
for (const r2 of scanRoots) {
|
|
6382
7194
|
if (capped) break;
|
|
6383
|
-
const abs =
|
|
7195
|
+
const abs = path8.resolve(r2);
|
|
6384
7196
|
if (abs !== base) walk(abs, 0);
|
|
6385
7197
|
}
|
|
6386
7198
|
const list = [...found.values()].sort((a, b3) => a.localeCompare(b3));
|
|
@@ -6390,10 +7202,10 @@ function detectCssFiles(root, scanRoots = [], maxDepth = DEFAULT_CSS_DEPTH) {
|
|
|
6390
7202
|
return list;
|
|
6391
7203
|
}
|
|
6392
7204
|
function detectInputDirs(root) {
|
|
6393
|
-
const resolved =
|
|
7205
|
+
const resolved = path8.resolve(root);
|
|
6394
7206
|
return COMMON_INPUT_DIRS.filter((name) => {
|
|
6395
7207
|
try {
|
|
6396
|
-
return fs2.statSync(
|
|
7208
|
+
return fs2.statSync(path8.join(resolved, name)).isDirectory();
|
|
6397
7209
|
} catch {
|
|
6398
7210
|
return false;
|
|
6399
7211
|
}
|
|
@@ -6519,13 +7331,6 @@ async function runWizard(base) {
|
|
|
6519
7331
|
}
|
|
6520
7332
|
|
|
6521
7333
|
// ../cli/src/index.ts
|
|
6522
|
-
function addStats(totals, stats, changed) {
|
|
6523
|
-
totals.files += 1;
|
|
6524
|
-
if (changed) totals.changed += 1;
|
|
6525
|
-
totals.nodesRemoved += stats.nodesRemoved;
|
|
6526
|
-
totals.classesSaved += stats.classesSaved;
|
|
6527
|
-
totals.bytesSaved += stats.bytesSaved;
|
|
6528
|
-
}
|
|
6529
7334
|
function printReport(totals) {
|
|
6530
7335
|
console.log("");
|
|
6531
7336
|
console.log("domflax report");
|
|
@@ -6535,28 +7340,13 @@ function printReport(totals) {
|
|
|
6535
7340
|
console.log(` classes saved : ${totals.classesSaved}`);
|
|
6536
7341
|
console.log(` bytes saved : ${totals.bytesSaved}`);
|
|
6537
7342
|
}
|
|
6538
|
-
|
|
6539
|
-
const { files, inputRoot, warnings } = discoverInputs(options.paths);
|
|
6540
|
-
for (const w2 of warnings) console.error(`domflax: ${w2}`);
|
|
6541
|
-
if (files.length === 0) {
|
|
6542
|
-
console.error("domflax: no .jsx/.tsx files found for the given paths");
|
|
6543
|
-
return { exitCode: 1 };
|
|
6544
|
-
}
|
|
6545
|
-
const projectRoot = options.projectRoot ?? process.cwd();
|
|
6546
|
-
const gitClean = options.dangerouslyOverwriteSource && !options.noGitCheck ? isGitClean(projectRoot) : true;
|
|
6547
|
-
const planned = planWrites(options, gitClean);
|
|
6548
|
-
if (!planned.ok) {
|
|
6549
|
-
console.error(`domflax: ${planned.error}`);
|
|
6550
|
-
return { exitCode: 1 };
|
|
6551
|
-
}
|
|
6552
|
-
const plan = planned.value;
|
|
7343
|
+
function runInline(files, options, inputRoot, plan, totals) {
|
|
6553
7344
|
const transform = createTransform(options);
|
|
6554
|
-
const totals = { files: 0, changed: 0, nodesRemoved: 0, classesSaved: 0, bytesSaved: 0 };
|
|
6555
7345
|
let failures = 0;
|
|
6556
7346
|
for (const file of files) {
|
|
6557
7347
|
let code;
|
|
6558
7348
|
try {
|
|
6559
|
-
code = (0,
|
|
7349
|
+
code = (0, import_node_fs4.readFileSync)(file, "utf8");
|
|
6560
7350
|
} catch (err) {
|
|
6561
7351
|
console.error(`domflax: cannot read ${file}: ${String(err?.message ?? err)}`);
|
|
6562
7352
|
failures += 1;
|
|
@@ -6565,7 +7355,7 @@ async function execute(options) {
|
|
|
6565
7355
|
const result = transform.transformFile(code, file);
|
|
6566
7356
|
addStats(totals, result.stats, result.changed);
|
|
6567
7357
|
if (options.dryRun) {
|
|
6568
|
-
const rel =
|
|
7358
|
+
const rel = path9.relative(inputRoot, file) || path9.basename(file);
|
|
6569
7359
|
if (result.changed) console.log(unifiedDiff(code, result.code, rel));
|
|
6570
7360
|
else if (!options.report) console.log(` (unchanged) ${rel}`);
|
|
6571
7361
|
continue;
|
|
@@ -6578,14 +7368,53 @@ async function execute(options) {
|
|
|
6578
7368
|
continue;
|
|
6579
7369
|
}
|
|
6580
7370
|
try {
|
|
6581
|
-
(0,
|
|
6582
|
-
(0,
|
|
6583
|
-
console.log(`domflax: wrote ${
|
|
7371
|
+
(0, import_node_fs4.mkdirSync)(path9.dirname(target.value), { recursive: true });
|
|
7372
|
+
(0, import_node_fs4.writeFileSync)(target.value, result.code, "utf8");
|
|
7373
|
+
console.log(`domflax: wrote ${path9.relative(process.cwd(), target.value) || target.value}`);
|
|
6584
7374
|
} catch (err) {
|
|
6585
7375
|
console.error(`domflax: cannot write ${target.value}: ${String(err?.message ?? err)}`);
|
|
6586
7376
|
failures += 1;
|
|
6587
7377
|
}
|
|
6588
7378
|
}
|
|
7379
|
+
return failures;
|
|
7380
|
+
}
|
|
7381
|
+
async function execute(options) {
|
|
7382
|
+
const { files, inputRoot, warnings } = discoverInputs(options.paths);
|
|
7383
|
+
for (const w2 of warnings) console.error(`domflax: ${w2}`);
|
|
7384
|
+
if (files.length === 0) {
|
|
7385
|
+
console.error("domflax: no .jsx/.tsx files found for the given paths");
|
|
7386
|
+
return { exitCode: 1 };
|
|
7387
|
+
}
|
|
7388
|
+
const projectRoot = options.projectRoot ?? process.cwd();
|
|
7389
|
+
const gitClean = options.dangerouslyOverwriteSource && !options.noGitCheck ? isGitClean(projectRoot) : true;
|
|
7390
|
+
const planned = planWrites(options, gitClean);
|
|
7391
|
+
if (!planned.ok) {
|
|
7392
|
+
console.error(`domflax: ${planned.error}`);
|
|
7393
|
+
return { exitCode: 1 };
|
|
7394
|
+
}
|
|
7395
|
+
const plan = planned.value;
|
|
7396
|
+
const poolPlan = computeWorkerCount(options);
|
|
7397
|
+
const usePool = !options.dryRun && shouldUsePool(files.length, poolPlan);
|
|
7398
|
+
const totals = emptyTotals();
|
|
7399
|
+
let failures = 0;
|
|
7400
|
+
if (usePool) {
|
|
7401
|
+
const outcome = await runPool(
|
|
7402
|
+
files,
|
|
7403
|
+
{ options, inputRoot, plan },
|
|
7404
|
+
poolPlan
|
|
7405
|
+
// Per-file "wrote" lines are collected and printed in deterministic (sorted) order below.
|
|
7406
|
+
);
|
|
7407
|
+
Object.assign(totals, outcome.totals);
|
|
7408
|
+
failures = outcome.failures;
|
|
7409
|
+
for (const { path: p2, error } of outcome.errors) {
|
|
7410
|
+
console.error(`domflax: failed ${path9.relative(process.cwd(), p2) || p2}: ${error}`);
|
|
7411
|
+
}
|
|
7412
|
+
for (const dest of [...outcome.wrote].sort()) {
|
|
7413
|
+
console.log(`domflax: wrote ${path9.relative(process.cwd(), dest) || dest}`);
|
|
7414
|
+
}
|
|
7415
|
+
} else {
|
|
7416
|
+
failures += runInline(files, options, inputRoot, plan, totals);
|
|
7417
|
+
}
|
|
6589
7418
|
if (options.dryRun) {
|
|
6590
7419
|
console.log("\ndomflax: dry run \u2014 no files were written.");
|
|
6591
7420
|
} else if (totals.changed === 0) {
|