@nipe-solutions/flex-layout-codemod 2.0.0-beta.3 → 2.0.0-beta.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/CHANGELOG.md +14 -0
- package/README.md +5 -3
- package/dist/cli.js +1204 -568
- package/dist/cli.js.map +1 -1
- package/package.json +5 -4
package/dist/cli.js
CHANGED
|
@@ -1,17 +1,788 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
+
// src/migrator/migration-path.validator.ts
|
|
4
|
+
import { lstat, stat } from "fs/promises";
|
|
5
|
+
import * as path from "path";
|
|
6
|
+
|
|
7
|
+
// src/migrator/migration-application.error.ts
|
|
8
|
+
var MigrationApplicationError = class extends Error {
|
|
9
|
+
constructor(code, message, paths = [], options) {
|
|
10
|
+
super(message, options);
|
|
11
|
+
this.code = code;
|
|
12
|
+
this.paths = paths;
|
|
13
|
+
this.name = "MigrationApplicationError";
|
|
14
|
+
this.paths = Object.freeze([...paths]);
|
|
15
|
+
this.recoveryFailures = Object.freeze([...options?.recoveryFailures ?? []]);
|
|
16
|
+
}
|
|
17
|
+
recoveryFailures;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
// src/migrator/migration-path.validator.ts
|
|
21
|
+
async function validateMigrationPaths(request, pathApi = path) {
|
|
22
|
+
const claims = normalizedClaims(request, pathApi);
|
|
23
|
+
await validateCollisions(claims, pathApi);
|
|
24
|
+
const destinations = claims.filter((claim) => claim.kind !== "template-input");
|
|
25
|
+
for (const destination of destinations) {
|
|
26
|
+
await validateDestination(destination.path);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
async function validateStylesheetRootTopology(request, pathApi = path) {
|
|
30
|
+
if (request.stylesheetPath === void 0) return;
|
|
31
|
+
const stylesheetPath = pathApi.resolve(request.stylesheetPath);
|
|
32
|
+
const templateRoots = [request.inputPath, request.outputPath].map((claim) => pathApi.resolve(claim));
|
|
33
|
+
const reportPath = request.reportPath === void 0 ? void 0 : pathApi.resolve(request.reportPath);
|
|
34
|
+
const exactCollision = (await Promise.all(
|
|
35
|
+
[...templateRoots, reportPath].map(
|
|
36
|
+
(claim) => claim === void 0 ? Promise.resolve(false) : pathsEquivalentOnFileSystem(stylesheetPath, claim, pathApi)
|
|
37
|
+
)
|
|
38
|
+
)).some(Boolean);
|
|
39
|
+
const reportHierarchyCollision = reportPath !== void 0 && await pathsOverlapOnFileSystem(stylesheetPath, reportPath, pathApi);
|
|
40
|
+
if (exactCollision || reportHierarchyCollision) {
|
|
41
|
+
const collisionPaths = reportHierarchyCollision && reportPath !== void 0 && !await pathsEquivalentOnFileSystem(stylesheetPath, reportPath, pathApi) ? [stylesheetPath, reportPath] : [stylesheetPath];
|
|
42
|
+
throw new MigrationApplicationError(
|
|
43
|
+
"path-collision",
|
|
44
|
+
`Stylesheet path collides with another migration path: ${request.stylesheetPathInput ?? request.stylesheetPath}`,
|
|
45
|
+
collisionPaths
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
let stylesheetStat;
|
|
49
|
+
try {
|
|
50
|
+
stylesheetStat = await lstat(stylesheetPath);
|
|
51
|
+
} catch (error) {
|
|
52
|
+
if (isEnoent(error)) return;
|
|
53
|
+
throw error;
|
|
54
|
+
}
|
|
55
|
+
const sourcePath = request.stylesheetPathInput ?? request.stylesheetPath;
|
|
56
|
+
if (stylesheetStat.isSymbolicLink()) {
|
|
57
|
+
throw new MigrationApplicationError(
|
|
58
|
+
"unsupported-path-type",
|
|
59
|
+
`Stylesheet path must not be a symbolic link: ${sourcePath}`,
|
|
60
|
+
[stylesheetPath]
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
if (!stylesheetStat.isFile()) {
|
|
64
|
+
throw new MigrationApplicationError(
|
|
65
|
+
"unsupported-path-type",
|
|
66
|
+
`Stylesheet path must be a regular file: ${sourcePath}`,
|
|
67
|
+
[stylesheetPath]
|
|
68
|
+
);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
function normalizedClaims(request, pathApi) {
|
|
72
|
+
return [
|
|
73
|
+
...request.templates.flatMap((template, templateIndex) => [
|
|
74
|
+
{ path: pathApi.resolve(template.inputPath), kind: "template-input", templateIndex },
|
|
75
|
+
{ path: pathApi.resolve(template.outputPath), kind: "template-output", templateIndex }
|
|
76
|
+
]),
|
|
77
|
+
...request.stylesheetPath ? [{ path: pathApi.resolve(request.stylesheetPath), kind: "stylesheet" }] : [],
|
|
78
|
+
...request.reportPath ? [{ path: pathApi.resolve(request.reportPath), kind: "report" }] : []
|
|
79
|
+
];
|
|
80
|
+
}
|
|
81
|
+
async function validateCollisions(claims, pathApi) {
|
|
82
|
+
const observations = /* @__PURE__ */ new Map();
|
|
83
|
+
const observe = (candidate) => {
|
|
84
|
+
const normalized = pathApi.resolve(candidate);
|
|
85
|
+
const existing = observations.get(normalized);
|
|
86
|
+
if (existing) return existing;
|
|
87
|
+
const pending = observePath(normalized, pathApi);
|
|
88
|
+
observations.set(normalized, pending);
|
|
89
|
+
return pending;
|
|
90
|
+
};
|
|
91
|
+
for (let leftIndex = 0; leftIndex < claims.length; leftIndex++) {
|
|
92
|
+
const left = claims[leftIndex];
|
|
93
|
+
if (!left) continue;
|
|
94
|
+
for (let rightIndex = leftIndex + 1; rightIndex < claims.length; rightIndex++) {
|
|
95
|
+
const right = claims[rightIndex];
|
|
96
|
+
if (!right) continue;
|
|
97
|
+
const relationship = await fileSystemPathRelationship(left.path, right.path, pathApi, observe);
|
|
98
|
+
if (relationship === "distinct" || isIntentionalInPlacePair(left, right, pathApi)) continue;
|
|
99
|
+
const collisionPaths = relationship === "equivalent" ? [left.path] : [left.path, right.path];
|
|
100
|
+
throw new MigrationApplicationError(
|
|
101
|
+
"path-collision",
|
|
102
|
+
`Migration paths collide: ${collisionPaths.join(" and ")}`,
|
|
103
|
+
collisionPaths
|
|
104
|
+
);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
function isIntentionalInPlacePair(left, right, pathApi) {
|
|
109
|
+
return pathsEquivalent(left.path, right.path, pathApi) && left.templateIndex !== void 0 && left.templateIndex === right.templateIndex && left.kind !== right.kind && left.kind.startsWith("template-") && right.kind.startsWith("template-");
|
|
110
|
+
}
|
|
111
|
+
function pathsEquivalent(left, right, pathApi = path) {
|
|
112
|
+
return normalizedPathsEquivalent(pathApi, pathApi.resolve(left), pathApi.resolve(right));
|
|
113
|
+
}
|
|
114
|
+
async function pathsEquivalentOnFileSystem(left, right, pathApi = path) {
|
|
115
|
+
return await fileSystemPathRelationship(left, right, pathApi) === "equivalent";
|
|
116
|
+
}
|
|
117
|
+
async function pathsOverlapOnFileSystem(left, right, pathApi = path) {
|
|
118
|
+
return await fileSystemPathRelationship(left, right, pathApi) !== "distinct";
|
|
119
|
+
}
|
|
120
|
+
function normalizedPathsEquivalent(pathApi, left, right) {
|
|
121
|
+
return pathApi.relative(left, right) === "";
|
|
122
|
+
}
|
|
123
|
+
function isAncestor(pathApi, ancestor, descendant) {
|
|
124
|
+
const relative3 = pathApi.relative(ancestor, descendant);
|
|
125
|
+
return relative3 !== "" && relative3 !== ".." && !relative3.startsWith(`..${pathApi.sep}`) && !pathApi.isAbsolute(relative3);
|
|
126
|
+
}
|
|
127
|
+
async function fileSystemPathRelationship(left, right, pathApi, observe = (candidate) => observePath(candidate, pathApi)) {
|
|
128
|
+
const normalizedLeft = pathApi.resolve(left);
|
|
129
|
+
const normalizedRight = pathApi.resolve(right);
|
|
130
|
+
if (normalizedPathsEquivalent(pathApi, normalizedLeft, normalizedRight)) return "equivalent";
|
|
131
|
+
if (isAncestor(pathApi, normalizedLeft, normalizedRight)) return "ancestor";
|
|
132
|
+
if (isAncestor(pathApi, normalizedRight, normalizedLeft)) return "descendant";
|
|
133
|
+
const [observedLeft, observedRight] = await Promise.all([observe(normalizedLeft), observe(normalizedRight)]);
|
|
134
|
+
if (observedLeft.exactIdentity && observedRight.exactIdentity) {
|
|
135
|
+
if (sameIdentity(observedLeft.exactIdentity, observedRight.exactIdentity)) return "equivalent";
|
|
136
|
+
if (hasIdentityBelow(observedRight, observedLeft.exactIdentity)) return "ancestor";
|
|
137
|
+
if (hasIdentityBelow(observedLeft, observedRight.exactIdentity)) return "descendant";
|
|
138
|
+
return "distinct";
|
|
139
|
+
}
|
|
140
|
+
return relationshipThroughExistingPrefixes(observedLeft, observedRight);
|
|
141
|
+
}
|
|
142
|
+
async function observePath(candidate, pathApi) {
|
|
143
|
+
const prefixes = [];
|
|
144
|
+
const suffix = [];
|
|
145
|
+
let current = candidate;
|
|
146
|
+
let exactIdentity;
|
|
147
|
+
while (true) {
|
|
148
|
+
try {
|
|
149
|
+
const currentStat = await stat(current, { bigint: true });
|
|
150
|
+
const currentIdentity = identity(currentStat);
|
|
151
|
+
if (suffix.length === 0) exactIdentity = currentIdentity;
|
|
152
|
+
prefixes.push({ identity: currentIdentity, suffix: [...suffix] });
|
|
153
|
+
} catch (error) {
|
|
154
|
+
if (!isMissingPath(error)) throw error;
|
|
155
|
+
}
|
|
156
|
+
const parent = pathApi.dirname(current);
|
|
157
|
+
if (parent === current) break;
|
|
158
|
+
suffix.unshift(pathApi.basename(current));
|
|
159
|
+
current = parent;
|
|
160
|
+
}
|
|
161
|
+
return { ...exactIdentity ? { exactIdentity } : {}, prefixes };
|
|
162
|
+
}
|
|
163
|
+
function relationshipThroughExistingPrefixes(left, right) {
|
|
164
|
+
for (const leftPrefix of left.prefixes) {
|
|
165
|
+
for (const rightPrefix of right.prefixes) {
|
|
166
|
+
if (!sameIdentity(leftPrefix.identity, rightPrefix.identity)) continue;
|
|
167
|
+
const relationship = suffixRelationship(leftPrefix.suffix, rightPrefix.suffix);
|
|
168
|
+
if (relationship !== "distinct") return relationship;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
return "distinct";
|
|
172
|
+
}
|
|
173
|
+
function hasIdentityBelow(observed, candidate) {
|
|
174
|
+
return observed.prefixes.some((prefix) => prefix.suffix.length > 0 && sameIdentity(prefix.identity, candidate));
|
|
175
|
+
}
|
|
176
|
+
function suffixRelationship(left, right) {
|
|
177
|
+
const normalizedLeft = left.map(portablePathSegment);
|
|
178
|
+
const normalizedRight = right.map(portablePathSegment);
|
|
179
|
+
const sharedLength = Math.min(normalizedLeft.length, normalizedRight.length);
|
|
180
|
+
for (let index = 0; index < sharedLength; index++) {
|
|
181
|
+
if (normalizedLeft[index] !== normalizedRight[index]) return "distinct";
|
|
182
|
+
}
|
|
183
|
+
if (normalizedLeft.length === normalizedRight.length) return "equivalent";
|
|
184
|
+
return normalizedLeft.length < normalizedRight.length ? "ancestor" : "descendant";
|
|
185
|
+
}
|
|
186
|
+
function portablePathSegment(value) {
|
|
187
|
+
return value.normalize("NFC").toLowerCase();
|
|
188
|
+
}
|
|
189
|
+
function identity(value) {
|
|
190
|
+
return { device: String(value.dev), inode: String(value.ino) };
|
|
191
|
+
}
|
|
192
|
+
function sameIdentity(left, right) {
|
|
193
|
+
return left.device === right.device && left.inode === right.inode;
|
|
194
|
+
}
|
|
195
|
+
async function validateDestination(destination) {
|
|
196
|
+
let stat4;
|
|
197
|
+
try {
|
|
198
|
+
stat4 = await lstat(destination);
|
|
199
|
+
} catch (error) {
|
|
200
|
+
if (isEnoent(error)) return;
|
|
201
|
+
throw error;
|
|
202
|
+
}
|
|
203
|
+
if (stat4.isSymbolicLink()) {
|
|
204
|
+
throw new MigrationApplicationError(
|
|
205
|
+
"unsupported-path-type",
|
|
206
|
+
`Migration destination must not be a symbolic link: ${destination}`,
|
|
207
|
+
[destination]
|
|
208
|
+
);
|
|
209
|
+
}
|
|
210
|
+
if (!stat4.isFile()) {
|
|
211
|
+
throw new MigrationApplicationError(
|
|
212
|
+
"unsupported-path-type",
|
|
213
|
+
`Migration destination must be a regular file: ${destination}`,
|
|
214
|
+
[destination]
|
|
215
|
+
);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
function isEnoent(error) {
|
|
219
|
+
return typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT";
|
|
220
|
+
}
|
|
221
|
+
function isMissingPath(error) {
|
|
222
|
+
return typeof error === "object" && error !== null && "code" in error && (error.code === "ENOENT" || error.code === "ENOTDIR");
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
// src/config/migration-config.ts
|
|
226
|
+
import { readFile, realpath } from "fs/promises";
|
|
227
|
+
import path2 from "path";
|
|
228
|
+
import { createHash } from "crypto";
|
|
229
|
+
import postcss2 from "postcss";
|
|
230
|
+
|
|
231
|
+
// src/util/sha-256.ts
|
|
232
|
+
var ROUND_CONSTANTS = Object.freeze([
|
|
233
|
+
1116352408,
|
|
234
|
+
1899447441,
|
|
235
|
+
3049323471,
|
|
236
|
+
3921009573,
|
|
237
|
+
961987163,
|
|
238
|
+
1508970993,
|
|
239
|
+
2453635748,
|
|
240
|
+
2870763221,
|
|
241
|
+
3624381080,
|
|
242
|
+
310598401,
|
|
243
|
+
607225278,
|
|
244
|
+
1426881987,
|
|
245
|
+
1925078388,
|
|
246
|
+
2162078206,
|
|
247
|
+
2614888103,
|
|
248
|
+
3248222580,
|
|
249
|
+
3835390401,
|
|
250
|
+
4022224774,
|
|
251
|
+
264347078,
|
|
252
|
+
604807628,
|
|
253
|
+
770255983,
|
|
254
|
+
1249150122,
|
|
255
|
+
1555081692,
|
|
256
|
+
1996064986,
|
|
257
|
+
2554220882,
|
|
258
|
+
2821834349,
|
|
259
|
+
2952996808,
|
|
260
|
+
3210313671,
|
|
261
|
+
3336571891,
|
|
262
|
+
3584528711,
|
|
263
|
+
113926993,
|
|
264
|
+
338241895,
|
|
265
|
+
666307205,
|
|
266
|
+
773529912,
|
|
267
|
+
1294757372,
|
|
268
|
+
1396182291,
|
|
269
|
+
1695183700,
|
|
270
|
+
1986661051,
|
|
271
|
+
2177026350,
|
|
272
|
+
2456956037,
|
|
273
|
+
2730485921,
|
|
274
|
+
2820302411,
|
|
275
|
+
3259730800,
|
|
276
|
+
3345764771,
|
|
277
|
+
3516065817,
|
|
278
|
+
3600352804,
|
|
279
|
+
4094571909,
|
|
280
|
+
275423344,
|
|
281
|
+
430227734,
|
|
282
|
+
506948616,
|
|
283
|
+
659060556,
|
|
284
|
+
883997877,
|
|
285
|
+
958139571,
|
|
286
|
+
1322822218,
|
|
287
|
+
1537002063,
|
|
288
|
+
1747873779,
|
|
289
|
+
1955562222,
|
|
290
|
+
2024104815,
|
|
291
|
+
2227730452,
|
|
292
|
+
2361852424,
|
|
293
|
+
2428436474,
|
|
294
|
+
2756734187,
|
|
295
|
+
3204031479,
|
|
296
|
+
3329325298
|
|
297
|
+
]);
|
|
298
|
+
var INITIAL_HASH = Object.freeze([
|
|
299
|
+
1779033703,
|
|
300
|
+
3144134277,
|
|
301
|
+
1013904242,
|
|
302
|
+
2773480762,
|
|
303
|
+
1359893119,
|
|
304
|
+
2600822924,
|
|
305
|
+
528734635,
|
|
306
|
+
1541459225
|
|
307
|
+
]);
|
|
308
|
+
function sha256(value) {
|
|
309
|
+
const source = new TextEncoder().encode(value);
|
|
310
|
+
const paddedLength = Math.ceil((source.length + 9) / 64) * 64;
|
|
311
|
+
const bytes = new Uint8Array(paddedLength);
|
|
312
|
+
bytes.set(source);
|
|
313
|
+
bytes[source.length] = 128;
|
|
314
|
+
const bitLength = source.length * 8;
|
|
315
|
+
const view = new DataView(bytes.buffer);
|
|
316
|
+
view.setUint32(paddedLength - 8, Math.floor(bitLength / 4294967296));
|
|
317
|
+
view.setUint32(paddedLength - 4, bitLength >>> 0);
|
|
318
|
+
const hash = [...INITIAL_HASH];
|
|
319
|
+
const schedule = new Uint32Array(64);
|
|
320
|
+
for (let offset = 0; offset < bytes.length; offset += 64) {
|
|
321
|
+
for (let index = 0; index < 16; index += 1) schedule[index] = view.getUint32(offset + index * 4);
|
|
322
|
+
for (let index = 16; index < schedule.length; index += 1) {
|
|
323
|
+
const earlier = schedule[index - 15];
|
|
324
|
+
const recent = schedule[index - 2];
|
|
325
|
+
const sigma0 = rotateRight(earlier, 7) ^ rotateRight(earlier, 18) ^ earlier >>> 3;
|
|
326
|
+
const sigma1 = rotateRight(recent, 17) ^ rotateRight(recent, 19) ^ recent >>> 10;
|
|
327
|
+
schedule[index] = schedule[index - 16] + sigma0 + schedule[index - 7] + sigma1 >>> 0;
|
|
328
|
+
}
|
|
329
|
+
let [a, b, c, d, e, f, g, h] = hash;
|
|
330
|
+
for (let index = 0; index < schedule.length; index += 1) {
|
|
331
|
+
const sum1 = rotateRight(e, 6) ^ rotateRight(e, 11) ^ rotateRight(e, 25);
|
|
332
|
+
const choice = e & f ^ ~e & g;
|
|
333
|
+
const temporary1 = h + sum1 + choice + ROUND_CONSTANTS[index] + schedule[index] >>> 0;
|
|
334
|
+
const sum0 = rotateRight(a, 2) ^ rotateRight(a, 13) ^ rotateRight(a, 22);
|
|
335
|
+
const majority = a & b ^ a & c ^ b & c;
|
|
336
|
+
const temporary2 = sum0 + majority >>> 0;
|
|
337
|
+
h = g;
|
|
338
|
+
g = f;
|
|
339
|
+
f = e;
|
|
340
|
+
e = d + temporary1 >>> 0;
|
|
341
|
+
d = c;
|
|
342
|
+
c = b;
|
|
343
|
+
b = a;
|
|
344
|
+
a = temporary1 + temporary2 >>> 0;
|
|
345
|
+
}
|
|
346
|
+
const round = [a, b, c, d, e, f, g, h];
|
|
347
|
+
for (let index = 0; index < hash.length; index += 1) hash[index] = hash[index] + round[index] >>> 0;
|
|
348
|
+
}
|
|
349
|
+
return hash.map((word) => word.toString(16).padStart(8, "0")).join("");
|
|
350
|
+
}
|
|
351
|
+
function rotateRight(value, count) {
|
|
352
|
+
return value >>> count | value << 32 - count;
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
// src/config/tailwind-target-profile.ts
|
|
356
|
+
import postcss from "postcss";
|
|
357
|
+
var defaults = { sm: "40rem", md: "48rem", lg: "64rem", xl: "80rem", "2xl": "96rem" };
|
|
358
|
+
function validBreakpoint(value) {
|
|
359
|
+
return /^(?:0|[1-9]\d*)(?:\.\d+)?(?:px|rem|em)$/.test(value) && Number.parseFloat(value) < 1e7;
|
|
360
|
+
}
|
|
361
|
+
function validPrefix(value) {
|
|
362
|
+
return /^[a-z]+$/.test(value);
|
|
363
|
+
}
|
|
364
|
+
function analyzeTailwindStylesheet(css, source = "pasted stylesheet") {
|
|
365
|
+
const operations = [];
|
|
366
|
+
const diagnostics = [];
|
|
367
|
+
const imports = [];
|
|
368
|
+
let tailwind = false;
|
|
369
|
+
let defaultTheme = false;
|
|
370
|
+
let utilities = false;
|
|
371
|
+
const warn = (code, message) => diagnostics.push({ code, message: `${source}: ${message}` });
|
|
372
|
+
if (css.length > 2e6) throw new Error("Stylesheet exceeds the 2 MB static analysis limit.");
|
|
373
|
+
const root = postcss.parse(css, { from: void 0 });
|
|
374
|
+
root.walkAtRules((rule) => {
|
|
375
|
+
if (rule.name === "custom-variant" || rule.name === "utility")
|
|
376
|
+
warn("tailwind-target-unknown", `@${rule.name} may change generated utility semantics and is not evaluated.`);
|
|
377
|
+
if (rule.name === "config" || rule.name === "plugin") {
|
|
378
|
+
warn(
|
|
379
|
+
rule.name === "config" ? "tailwind-config-external" : "tailwind-plugin-external",
|
|
380
|
+
`@${rule.name} ${rule.params} was not executed; additional configuration is unknown.`
|
|
381
|
+
);
|
|
382
|
+
}
|
|
383
|
+
if (rule.name === "source" && /^not\b/.test(rule.params)) {
|
|
384
|
+
warn("tailwind-source-excluded", `Source exclusion ${rule.params} may exclude migrated templates.`);
|
|
385
|
+
}
|
|
386
|
+
if (rule.name === "import") {
|
|
387
|
+
const match = /^(["'])([^"']+)\1(.*)$/.exec(rule.params);
|
|
388
|
+
if (!match) {
|
|
389
|
+
warn("tailwind-import-unresolved", `Import ${rule.params} was not loaded.`);
|
|
390
|
+
return;
|
|
391
|
+
}
|
|
392
|
+
const imported = match[2];
|
|
393
|
+
const modifiers = match[3];
|
|
394
|
+
if (/^tailwindcss(?:\/(?:theme|utilities|preflight)\.css)?$/.test(imported)) {
|
|
395
|
+
tailwind = true;
|
|
396
|
+
if (rule.parent?.type !== "root") {
|
|
397
|
+
warn("tailwind-target-unknown", "Conditional Tailwind import is unresolved.");
|
|
398
|
+
return;
|
|
399
|
+
}
|
|
400
|
+
let remaining = modifiers.trim();
|
|
401
|
+
let prefix = null;
|
|
402
|
+
let important = false;
|
|
403
|
+
const seen = /* @__PURE__ */ new Set();
|
|
404
|
+
while (remaining) {
|
|
405
|
+
const modifier = /^(prefix\(([^)]*)\)|important|source\((?:none|"[^"]*"|'[^']*')\)|layer\([a-zA-Z0-9_.-]+\))(?=\s|$)/.exec(
|
|
406
|
+
remaining
|
|
407
|
+
);
|
|
408
|
+
if (!modifier) {
|
|
409
|
+
warn("tailwind-target-unknown", `Unsupported Tailwind import modifiers: ${remaining}`);
|
|
410
|
+
break;
|
|
411
|
+
}
|
|
412
|
+
const name = modifier[1].split("(")[0];
|
|
413
|
+
if (seen.has(name)) warn("tailwind-target-unknown", `Repeated Tailwind import modifier ${name}.`);
|
|
414
|
+
seen.add(name);
|
|
415
|
+
if (name === "prefix") {
|
|
416
|
+
if (!validPrefix(modifier[2])) warn("tailwind-target-unknown", "Invalid Tailwind v4 prefix.");
|
|
417
|
+
else prefix = modifier[2];
|
|
418
|
+
}
|
|
419
|
+
if (name === "important") important = true;
|
|
420
|
+
if (modifier[1] === "source(none)")
|
|
421
|
+
warn("tailwind-source-excluded", "source(none) disables automatic template discovery.");
|
|
422
|
+
remaining = remaining.slice(modifier[0].length).trim();
|
|
423
|
+
}
|
|
424
|
+
if (imported === "tailwindcss" || imported === "tailwindcss/theme.css") defaultTheme = true;
|
|
425
|
+
if (imported !== "tailwindcss/preflight.css") operations.push({ kind: "prefix", value: prefix, source });
|
|
426
|
+
if (imported === "tailwindcss" || imported === "tailwindcss/utilities.css") {
|
|
427
|
+
utilities = true;
|
|
428
|
+
operations.push({ kind: "important", value: important ? "important" : "normal", source });
|
|
429
|
+
}
|
|
430
|
+
} else if (imported.startsWith("./") || imported.startsWith("../")) {
|
|
431
|
+
if (rule.parent?.type !== "root" || modifiers.trim())
|
|
432
|
+
warn("tailwind-import-unresolved", `Conditional import ${imported} was not loaded.`);
|
|
433
|
+
else imports.push(imported);
|
|
434
|
+
} else warn("tailwind-import-unresolved", `External import ${imported} was not loaded.`);
|
|
435
|
+
}
|
|
436
|
+
if (rule.name !== "theme") return;
|
|
437
|
+
if (rule.parent?.type !== "root" || rule.params.trim() && !/^(?:inline|static)(?:\s+(?:inline|static))*$/.test(rule.params.trim())) {
|
|
438
|
+
warn("tailwind-target-unknown", "Conditional or unsupported @theme block was not resolved.");
|
|
439
|
+
return;
|
|
440
|
+
}
|
|
441
|
+
rule.each((node) => {
|
|
442
|
+
if (node.type !== "decl") return;
|
|
443
|
+
if (node.prop === "--*") {
|
|
444
|
+
if (node.value.trim() === "initial" && !node.important) {
|
|
445
|
+
operations.push({ kind: "breakpoint", name: "*", value: null, source });
|
|
446
|
+
} else warn("tailwind-target-unknown", "Cannot resolve global theme reset.");
|
|
447
|
+
return;
|
|
448
|
+
}
|
|
449
|
+
if (!node.prop.startsWith("--breakpoint-")) return;
|
|
450
|
+
const name = node.prop.slice("--breakpoint-".length);
|
|
451
|
+
const value = node.value.trim();
|
|
452
|
+
if (!/^(?:\*|[a-zA-Z0-9][a-zA-Z0-9_-]*)$/.test(name) || node.important || value !== "initial" && (name === "*" || !validBreakpoint(value))) {
|
|
453
|
+
warn("tailwind-breakpoint-unknown", `Cannot resolve ${node.prop}: ${value}.`);
|
|
454
|
+
if (/^(?:\*|[a-zA-Z0-9][a-zA-Z0-9_-]*)$/.test(name))
|
|
455
|
+
operations.push({ kind: "breakpoint", name, value: null, source });
|
|
456
|
+
return;
|
|
457
|
+
}
|
|
458
|
+
operations.push({ kind: "breakpoint", name, value: value === "initial" ? null : value, source });
|
|
459
|
+
});
|
|
460
|
+
});
|
|
461
|
+
return { operations, diagnostics, imports, tailwind, defaultTheme, utilities, source };
|
|
462
|
+
}
|
|
463
|
+
function resolveTailwindTargetProfile(input = {}) {
|
|
464
|
+
let coreUtilities = {
|
|
465
|
+
value: "standard",
|
|
466
|
+
source: input.detected?.source ?? "default",
|
|
467
|
+
confidence: input.detected ? "detected" : "defaulted"
|
|
468
|
+
};
|
|
469
|
+
let prefix = { value: null, source: "default", confidence: "defaulted" };
|
|
470
|
+
let important = { value: "normal", source: "default", confidence: "defaulted" };
|
|
471
|
+
let breakpoints = Object.fromEntries(
|
|
472
|
+
Object.entries(input.detected && !input.detected.defaultTheme ? {} : defaults).map(([name, value]) => [
|
|
473
|
+
name,
|
|
474
|
+
{ value, source: "default", confidence: "defaulted" }
|
|
475
|
+
])
|
|
476
|
+
);
|
|
477
|
+
const diagnostics = [
|
|
478
|
+
...input.detected?.diagnostics ?? [],
|
|
479
|
+
...(input.detected?.imports ?? []).map((imported) => ({
|
|
480
|
+
code: "tailwind-import-unresolved",
|
|
481
|
+
message: `${input.detected.source}: Local import ${imported} was not loaded in this analysis.`
|
|
482
|
+
}))
|
|
483
|
+
];
|
|
484
|
+
function apply(operation, confidence) {
|
|
485
|
+
const { value, source } = operation;
|
|
486
|
+
if (operation.kind === "prefix") {
|
|
487
|
+
if (value !== null && !validPrefix(value))
|
|
488
|
+
throw new Error("Tailwind v4 prefix must contain only lowercase letters.");
|
|
489
|
+
if (prefix.confidence !== "defaulted" && prefix.value !== value)
|
|
490
|
+
diagnostics.push({
|
|
491
|
+
code: "tailwind-prefix-conflict",
|
|
492
|
+
message: `Using prefix ${String(value)} from ${source}; ${prefix.source} declared ${String(prefix.value)}.`
|
|
493
|
+
});
|
|
494
|
+
prefix = { value, source, confidence };
|
|
495
|
+
} else if (operation.kind === "important") important = { value: operation.value, source, confidence };
|
|
496
|
+
else if (operation.name === "*" && value === null) breakpoints = {};
|
|
497
|
+
else if (value === null) delete breakpoints[operation.name];
|
|
498
|
+
else {
|
|
499
|
+
if (!/^[a-zA-Z0-9][a-zA-Z0-9_-]*$/.test(operation.name) || !validBreakpoint(value))
|
|
500
|
+
throw new Error(`Invalid Tailwind breakpoint ${operation.name}: ${value}`);
|
|
501
|
+
breakpoints[operation.name] = { value, source, confidence };
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
input.detected?.operations.forEach((operation) => apply(operation, "detected"));
|
|
505
|
+
for (const [overrides, source] of [
|
|
506
|
+
[input.explicit, input.explicitSource ?? "migration profile"],
|
|
507
|
+
[input.cli, "CLI"]
|
|
508
|
+
]) {
|
|
509
|
+
if (!overrides) continue;
|
|
510
|
+
if (overrides.version !== void 0 && overrides.version !== 4)
|
|
511
|
+
throw new Error("Only Tailwind v4 targets are supported.");
|
|
512
|
+
if (overrides.coreUtilities !== void 0) {
|
|
513
|
+
if (overrides.coreUtilities !== "standard")
|
|
514
|
+
throw new Error("coreUtilities must be standard when explicitly asserted.");
|
|
515
|
+
coreUtilities = { value: "standard", source, confidence: "explicit" };
|
|
516
|
+
}
|
|
517
|
+
if (overrides.prefix !== void 0) apply({ kind: "prefix", value: overrides.prefix, source }, "explicit");
|
|
518
|
+
if (overrides.important !== void 0) {
|
|
519
|
+
if (!["normal", "important"].includes(overrides.important)) throw new Error("Invalid Tailwind important mode.");
|
|
520
|
+
apply({ kind: "important", value: overrides.important, source }, "explicit");
|
|
521
|
+
}
|
|
522
|
+
const entries = Object.entries(overrides.breakpoints ?? {}).sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0);
|
|
523
|
+
for (const [name, value] of entries)
|
|
524
|
+
apply({ kind: "breakpoint", name, value: value === "initial" ? null : value, source }, "explicit");
|
|
525
|
+
}
|
|
526
|
+
breakpoints = Object.fromEntries(Object.entries(breakpoints).sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0));
|
|
527
|
+
if (new Set(Object.values(breakpoints).map((setting) => setting.value.match(/[a-z]+$/)[0])).size > 1)
|
|
528
|
+
diagnostics.push({
|
|
529
|
+
code: "tailwind-mixed-breakpoint-units",
|
|
530
|
+
message: "Mixed breakpoint units may affect Tailwind variant ordering; units were preserved."
|
|
531
|
+
});
|
|
532
|
+
if (input.detected && !input.detected.utilities)
|
|
533
|
+
diagnostics.push({
|
|
534
|
+
code: "tailwind-target-unknown",
|
|
535
|
+
message: "The supplied stylesheet does not declare Tailwind utility generation."
|
|
536
|
+
});
|
|
537
|
+
if (input.detected && !input.detected.tailwind)
|
|
538
|
+
diagnostics.push({ code: "tailwind-target-unknown", message: "No supported Tailwind v4 import was detected." });
|
|
539
|
+
if (diagnostics.some(
|
|
540
|
+
(item) => [
|
|
541
|
+
"tailwind-config-external",
|
|
542
|
+
"tailwind-plugin-external",
|
|
543
|
+
"tailwind-import-unresolved",
|
|
544
|
+
"tailwind-target-unknown"
|
|
545
|
+
].includes(item.code)
|
|
546
|
+
)) {
|
|
547
|
+
if (coreUtilities.confidence !== "explicit")
|
|
548
|
+
coreUtilities = { ...coreUtilities, value: "unknown", confidence: "unknown" };
|
|
549
|
+
breakpoints = Object.fromEntries(
|
|
550
|
+
Object.entries(breakpoints).map(([name, setting]) => [
|
|
551
|
+
name,
|
|
552
|
+
setting.confidence === "explicit" ? setting : { ...setting, confidence: "unknown" }
|
|
553
|
+
])
|
|
554
|
+
);
|
|
555
|
+
if (prefix.confidence !== "explicit") prefix = { ...prefix, confidence: "unknown" };
|
|
556
|
+
if (important.confidence !== "explicit")
|
|
557
|
+
important = { value: "unknown", source: important.source, confidence: "unknown" };
|
|
558
|
+
}
|
|
559
|
+
const assumptions = [
|
|
560
|
+
"Custom application CSS is not globally analyzed.",
|
|
561
|
+
"Responsive source ranges are preserved, including screen and print conditions."
|
|
562
|
+
];
|
|
563
|
+
if (!input.detected && !input.explicit && !input.cli)
|
|
564
|
+
assumptions.push("Target profile uses Tailwind v4 defaults; project configuration was not discovered.");
|
|
565
|
+
if (diagnostics.some((d) => d.code === "tailwind-config-external" || d.code === "tailwind-plugin-external"))
|
|
566
|
+
assumptions.push("Legacy JavaScript configuration and plugins were not executed.");
|
|
567
|
+
if (coreUtilities.confidence === "explicit")
|
|
568
|
+
assumptions.push(
|
|
569
|
+
"The migration profile explicitly asserts standard Tailwind core utility semantics; this assertion was not verified by executing project code."
|
|
570
|
+
);
|
|
571
|
+
if (important.value === "important")
|
|
572
|
+
assumptions.push("Generated Tailwind utilities are globally important; existing styles still require review.");
|
|
573
|
+
const canonical = JSON.stringify({
|
|
574
|
+
version: 4,
|
|
575
|
+
prefix: prefix.value,
|
|
576
|
+
important: important.value,
|
|
577
|
+
coreUtilities: coreUtilities.value,
|
|
578
|
+
breakpoints: Object.fromEntries(Object.entries(breakpoints).map(([name, setting]) => [name, setting.value]))
|
|
579
|
+
});
|
|
580
|
+
return deepFreeze({
|
|
581
|
+
target: "tailwind",
|
|
582
|
+
version: 4,
|
|
583
|
+
prefix,
|
|
584
|
+
important,
|
|
585
|
+
coreUtilities,
|
|
586
|
+
breakpoints,
|
|
587
|
+
diagnostics,
|
|
588
|
+
assumptions,
|
|
589
|
+
fingerprint: `tw4-${sha256(canonical)}`,
|
|
590
|
+
...input.detected ? { stylesheet: input.detected.source } : {}
|
|
591
|
+
});
|
|
592
|
+
}
|
|
593
|
+
function deepFreeze(value) {
|
|
594
|
+
if (value && typeof value === "object") {
|
|
595
|
+
Object.values(value).forEach(deepFreeze);
|
|
596
|
+
Object.freeze(value);
|
|
597
|
+
}
|
|
598
|
+
return value;
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
// src/config/source-breakpoints.ts
|
|
602
|
+
function sourceBreakpointDefinition(alias, input) {
|
|
603
|
+
if (!/^[a-zA-Z][a-zA-Z0-9_.-]*$/.test(alias) || !Number.isSafeInteger(input.priority))
|
|
604
|
+
throw new Error(`Invalid source breakpoint ${alias}; an integer priority is required.`);
|
|
605
|
+
if (typeof input.mediaQuery !== "string") throw new Error(`Invalid source media query for ${alias}.`);
|
|
606
|
+
const parts = input.mediaQuery.trim().split(/\s+and\s+/);
|
|
607
|
+
if (parts.shift() !== "screen" || !parts.length)
|
|
608
|
+
throw new Error(`Source breakpoint ${alias} requires screen and explicit px width/orientation conditions.`);
|
|
609
|
+
const range2 = {};
|
|
610
|
+
for (const part of parts) {
|
|
611
|
+
const width = /^\((min|max)-width:\s*(\d+(?:\.\d+)?)px\)$/.exec(part);
|
|
612
|
+
const orientation = /^\(orientation:\s*(portrait|landscape)\)$/.exec(part);
|
|
613
|
+
if (width) {
|
|
614
|
+
const key = width[1];
|
|
615
|
+
if (range2[key] !== void 0 || !Number.isFinite(Number(width[2])))
|
|
616
|
+
throw new Error(`Duplicate or invalid source condition in ${alias}.`);
|
|
617
|
+
range2[key] = Number(width[2]);
|
|
618
|
+
} else if (orientation && range2.orientation === void 0)
|
|
619
|
+
range2.orientation = orientation[1];
|
|
620
|
+
else throw new Error(`Unsupported source media condition in ${alias}: ${part}`);
|
|
621
|
+
}
|
|
622
|
+
if ((range2.min ?? 0) > (range2.max ?? Infinity)) throw new Error(`Inverted source media range in ${alias}.`);
|
|
623
|
+
const clause = Object.freeze(range2);
|
|
624
|
+
return Object.freeze({
|
|
625
|
+
alias,
|
|
626
|
+
priority: input.priority,
|
|
627
|
+
range: clause,
|
|
628
|
+
media: Object.freeze({ type: "screen", clauses: Object.freeze([clause]) })
|
|
629
|
+
});
|
|
630
|
+
}
|
|
631
|
+
|
|
632
|
+
// src/config/migration-config.ts
|
|
633
|
+
function object(value, allowed, label) {
|
|
634
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) throw new Error(`${label} must be an object.`);
|
|
635
|
+
for (const key of Object.keys(value)) if (!allowed.includes(key)) throw new Error(`Unknown ${label} setting: ${key}`);
|
|
636
|
+
return value;
|
|
637
|
+
}
|
|
638
|
+
function parseConfig(contents) {
|
|
639
|
+
const config = object(JSON.parse(contents), ["target", "tailwind", "source"], "migration config");
|
|
640
|
+
if (config.target !== void 0 && config.target !== "tailwind" && config.target !== "css")
|
|
641
|
+
throw new Error("Invalid migration target.");
|
|
642
|
+
if (config.tailwind !== void 0) {
|
|
643
|
+
const tw = object(
|
|
644
|
+
config.tailwind,
|
|
645
|
+
["version", "stylesheet", "prefix", "breakpoints", "important", "coreUtilities"],
|
|
646
|
+
"tailwind"
|
|
647
|
+
);
|
|
648
|
+
if (tw.stylesheet !== void 0 && typeof tw.stylesheet !== "string")
|
|
649
|
+
throw new Error("Tailwind stylesheet must be a path.");
|
|
650
|
+
if (tw.prefix !== void 0 && tw.prefix !== null && typeof tw.prefix !== "string")
|
|
651
|
+
throw new Error("Tailwind prefix must be a string or null.");
|
|
652
|
+
if (tw.breakpoints !== void 0) {
|
|
653
|
+
if (!tw.breakpoints || typeof tw.breakpoints !== "object" || Array.isArray(tw.breakpoints))
|
|
654
|
+
throw new Error("Tailwind breakpoints must be an object.");
|
|
655
|
+
for (const value of Object.values(tw.breakpoints))
|
|
656
|
+
if (value !== null && typeof value !== "string")
|
|
657
|
+
throw new Error("Tailwind breakpoint values must be lengths or null.");
|
|
658
|
+
}
|
|
659
|
+
}
|
|
660
|
+
if (config.source !== void 0) {
|
|
661
|
+
const source = object(config.source, ["flexLayout"], "source");
|
|
662
|
+
if (source.flexLayout !== void 0) {
|
|
663
|
+
const flex = object(source.flexLayout, ["breakpoints"], "source.flexLayout");
|
|
664
|
+
if (flex.breakpoints !== void 0) {
|
|
665
|
+
if (!flex.breakpoints || typeof flex.breakpoints !== "object" || Array.isArray(flex.breakpoints))
|
|
666
|
+
throw new Error("Source breakpoints must be an object.");
|
|
667
|
+
for (const [alias, value] of Object.entries(flex.breakpoints)) {
|
|
668
|
+
object(value, ["mediaQuery", "priority"], `source breakpoint ${alias}`);
|
|
669
|
+
sourceBreakpointDefinition(alias, value);
|
|
670
|
+
}
|
|
671
|
+
}
|
|
672
|
+
}
|
|
673
|
+
}
|
|
674
|
+
return config;
|
|
675
|
+
}
|
|
676
|
+
var digest = (value) => createHash("sha256").update(value).digest("hex");
|
|
677
|
+
function inside(root, candidate) {
|
|
678
|
+
const relative3 = path2.relative(root, candidate);
|
|
679
|
+
return relative3 !== ".." && !relative3.startsWith(`..${path2.sep}`) && !path2.isAbsolute(relative3);
|
|
680
|
+
}
|
|
681
|
+
async function assertConfigurationUnchanged(snapshots) {
|
|
682
|
+
for (const snapshot of snapshots) {
|
|
683
|
+
let current;
|
|
684
|
+
try {
|
|
685
|
+
if (await realpath(snapshot.path) !== snapshot.canonicalPath) throw new Error("Configuration path changed.");
|
|
686
|
+
current = digest(await readFile(snapshot.path, "utf8"));
|
|
687
|
+
} catch {
|
|
688
|
+
throw new Error(`Target configuration changed or disappeared since planning: ${snapshot.path}`);
|
|
689
|
+
}
|
|
690
|
+
if (current !== snapshot.digest) throw new Error(`Target configuration changed since planning: ${snapshot.path}`);
|
|
691
|
+
}
|
|
692
|
+
}
|
|
693
|
+
async function loadMigrationConfig(options) {
|
|
694
|
+
const root = await realpath(options.cwd ?? process.cwd());
|
|
695
|
+
const snapshots = [];
|
|
696
|
+
const read = async (file) => {
|
|
697
|
+
const contents = await readFile(file, "utf8");
|
|
698
|
+
if (contents.length > 2e6) throw new Error("Configuration file exceeds the 2 MB static analysis limit.");
|
|
699
|
+
if (!snapshots.some((snapshot) => snapshot.path === file))
|
|
700
|
+
snapshots.push(Object.freeze({ path: file, canonicalPath: await realpath(file), digest: digest(contents) }));
|
|
701
|
+
return contents;
|
|
702
|
+
};
|
|
703
|
+
const configPath = path2.resolve(root, options.config ?? "flex-layout-migrator.config.json");
|
|
704
|
+
if (!configPath.endsWith(".json")) throw new Error("Migration configuration must be declarative JSON.");
|
|
705
|
+
let config = {};
|
|
706
|
+
try {
|
|
707
|
+
config = parseConfig(await read(configPath));
|
|
708
|
+
} catch (error) {
|
|
709
|
+
if (options.config !== void 0 || !(error && typeof error === "object" && "code" in error && error.code === "ENOENT"))
|
|
710
|
+
throw error;
|
|
711
|
+
}
|
|
712
|
+
const stylesheet = options.stylesheet === void 0 ? config.tailwind?.stylesheet === void 0 ? void 0 : path2.resolve(path2.dirname(configPath), config.tailwind.stylesheet) : path2.resolve(root, options.stylesheet);
|
|
713
|
+
let detected;
|
|
714
|
+
if (stylesheet) {
|
|
715
|
+
const operations = [];
|
|
716
|
+
const diagnostics = [];
|
|
717
|
+
let tailwind = false;
|
|
718
|
+
let defaultTheme = false;
|
|
719
|
+
let utilities = false;
|
|
720
|
+
let visited = 0;
|
|
721
|
+
const relative3 = (file) => path2.relative(root, file).split(path2.sep).join("/");
|
|
722
|
+
const visit = async (file, ancestors, depth) => {
|
|
723
|
+
if (++visited > 128 || depth > 16)
|
|
724
|
+
throw new Error("CSS import analysis limit exceeded (128 imports / depth 16).");
|
|
725
|
+
const canonical = await realpath(file);
|
|
726
|
+
if (!inside(root, canonical)) throw new Error("CSS import is outside the project root.");
|
|
727
|
+
if (ancestors.includes(canonical)) throw new Error("CSS import cycle detected.");
|
|
728
|
+
const contents = await read(file);
|
|
729
|
+
const parsed2 = postcss2.parse(contents, { from: void 0 });
|
|
730
|
+
for (const node of parsed2.nodes) {
|
|
731
|
+
const analysis = analyzeTailwindStylesheet(node.toString(), relative3(canonical));
|
|
732
|
+
operations.push(...analysis.operations);
|
|
733
|
+
diagnostics.push(...analysis.diagnostics);
|
|
734
|
+
tailwind ||= analysis.tailwind;
|
|
735
|
+
defaultTheme ||= analysis.defaultTheme;
|
|
736
|
+
utilities ||= analysis.utilities;
|
|
737
|
+
for (const imported of analysis.imports) {
|
|
738
|
+
try {
|
|
739
|
+
await visit(path2.resolve(path2.dirname(canonical), imported), [...ancestors, canonical], depth + 1);
|
|
740
|
+
} catch (error) {
|
|
741
|
+
diagnostics.push({
|
|
742
|
+
code: "tailwind-import-unresolved",
|
|
743
|
+
message: `${relative3(canonical)}: ${imported}: ${error instanceof Error ? error.message : "Import unresolved"}`
|
|
744
|
+
});
|
|
745
|
+
}
|
|
746
|
+
}
|
|
747
|
+
}
|
|
748
|
+
};
|
|
749
|
+
await visit(stylesheet, [], 0);
|
|
750
|
+
detected = {
|
|
751
|
+
source: relative3(stylesheet),
|
|
752
|
+
operations,
|
|
753
|
+
diagnostics,
|
|
754
|
+
imports: [],
|
|
755
|
+
defaultTheme,
|
|
756
|
+
utilities,
|
|
757
|
+
tailwind
|
|
758
|
+
};
|
|
759
|
+
}
|
|
760
|
+
const targetProfile = resolveTailwindTargetProfile({
|
|
761
|
+
detected,
|
|
762
|
+
explicit: config.tailwind,
|
|
763
|
+
explicitSource: path2.relative(root, configPath).split(path2.sep).join("/"),
|
|
764
|
+
...options.prefix !== void 0 ? { cli: { prefix: options.prefix || null } } : {}
|
|
765
|
+
});
|
|
766
|
+
return Object.freeze({
|
|
767
|
+
target: config.target,
|
|
768
|
+
targetProfile,
|
|
769
|
+
sourceBreakpoints: config.source?.flexLayout?.breakpoints,
|
|
770
|
+
snapshots: Object.freeze(snapshots)
|
|
771
|
+
});
|
|
772
|
+
}
|
|
773
|
+
|
|
3
774
|
// src/cli/run-cli.ts
|
|
4
775
|
import { Command, CommanderError, InvalidArgumentError, Option } from "commander";
|
|
5
|
-
import * as
|
|
776
|
+
import * as path18 from "path";
|
|
6
777
|
|
|
7
778
|
// package.json
|
|
8
779
|
var package_default = {
|
|
9
780
|
name: "@nipe-solutions/flex-layout-codemod",
|
|
10
|
-
version: "2.0.0-beta.
|
|
781
|
+
version: "2.0.0-beta.4",
|
|
11
782
|
description: "A safety-first codemod for migrating Angular Flex-Layout templates to native CSS or Tailwind CSS.",
|
|
12
783
|
type: "module",
|
|
13
784
|
engines: {
|
|
14
|
-
node: ">=
|
|
785
|
+
node: ">=22.12.0"
|
|
15
786
|
},
|
|
16
787
|
packageManager: "npm@11.19.0",
|
|
17
788
|
files: [
|
|
@@ -55,7 +826,8 @@ var package_default = {
|
|
|
55
826
|
"release:verify": "node scripts/release-artifact.mjs --verify-retained",
|
|
56
827
|
"verify:website-assets": "node scripts/verify-website-assets.mjs",
|
|
57
828
|
"release:version": "changeset version && npm install --package-lock-only --ignore-scripts --no-audit --no-fund",
|
|
58
|
-
prepare: "husky"
|
|
829
|
+
prepare: "husky",
|
|
830
|
+
check: "npm run verify && npm run verify:website"
|
|
59
831
|
},
|
|
60
832
|
repository: {
|
|
61
833
|
type: "git",
|
|
@@ -80,6 +852,7 @@ var package_default = {
|
|
|
80
852
|
commander: "^15.0.0",
|
|
81
853
|
"fs-extra": "^11.4.0",
|
|
82
854
|
ignore: "5.2.4",
|
|
855
|
+
postcss: "^8.5.26",
|
|
83
856
|
winston: "^3.19.0"
|
|
84
857
|
},
|
|
85
858
|
bin: {
|
|
@@ -107,7 +880,6 @@ var package_default = {
|
|
|
107
880
|
jsdom: "^30.0.1",
|
|
108
881
|
"lint-staged": "^17.4.1",
|
|
109
882
|
"mock-fs": "^5.5.0",
|
|
110
|
-
postcss: "^8.5.26",
|
|
111
883
|
prettier: "^3.9.6",
|
|
112
884
|
react: "^19.2.8",
|
|
113
885
|
"react-dom": "^19.2.8",
|
|
@@ -220,130 +992,6 @@ function isKnownBreakpoint(value) {
|
|
|
220
992
|
return breakpointNames.has(value);
|
|
221
993
|
}
|
|
222
994
|
|
|
223
|
-
// src/util/sha-256.ts
|
|
224
|
-
var ROUND_CONSTANTS = Object.freeze([
|
|
225
|
-
1116352408,
|
|
226
|
-
1899447441,
|
|
227
|
-
3049323471,
|
|
228
|
-
3921009573,
|
|
229
|
-
961987163,
|
|
230
|
-
1508970993,
|
|
231
|
-
2453635748,
|
|
232
|
-
2870763221,
|
|
233
|
-
3624381080,
|
|
234
|
-
310598401,
|
|
235
|
-
607225278,
|
|
236
|
-
1426881987,
|
|
237
|
-
1925078388,
|
|
238
|
-
2162078206,
|
|
239
|
-
2614888103,
|
|
240
|
-
3248222580,
|
|
241
|
-
3835390401,
|
|
242
|
-
4022224774,
|
|
243
|
-
264347078,
|
|
244
|
-
604807628,
|
|
245
|
-
770255983,
|
|
246
|
-
1249150122,
|
|
247
|
-
1555081692,
|
|
248
|
-
1996064986,
|
|
249
|
-
2554220882,
|
|
250
|
-
2821834349,
|
|
251
|
-
2952996808,
|
|
252
|
-
3210313671,
|
|
253
|
-
3336571891,
|
|
254
|
-
3584528711,
|
|
255
|
-
113926993,
|
|
256
|
-
338241895,
|
|
257
|
-
666307205,
|
|
258
|
-
773529912,
|
|
259
|
-
1294757372,
|
|
260
|
-
1396182291,
|
|
261
|
-
1695183700,
|
|
262
|
-
1986661051,
|
|
263
|
-
2177026350,
|
|
264
|
-
2456956037,
|
|
265
|
-
2730485921,
|
|
266
|
-
2820302411,
|
|
267
|
-
3259730800,
|
|
268
|
-
3345764771,
|
|
269
|
-
3516065817,
|
|
270
|
-
3600352804,
|
|
271
|
-
4094571909,
|
|
272
|
-
275423344,
|
|
273
|
-
430227734,
|
|
274
|
-
506948616,
|
|
275
|
-
659060556,
|
|
276
|
-
883997877,
|
|
277
|
-
958139571,
|
|
278
|
-
1322822218,
|
|
279
|
-
1537002063,
|
|
280
|
-
1747873779,
|
|
281
|
-
1955562222,
|
|
282
|
-
2024104815,
|
|
283
|
-
2227730452,
|
|
284
|
-
2361852424,
|
|
285
|
-
2428436474,
|
|
286
|
-
2756734187,
|
|
287
|
-
3204031479,
|
|
288
|
-
3329325298
|
|
289
|
-
]);
|
|
290
|
-
var INITIAL_HASH = Object.freeze([
|
|
291
|
-
1779033703,
|
|
292
|
-
3144134277,
|
|
293
|
-
1013904242,
|
|
294
|
-
2773480762,
|
|
295
|
-
1359893119,
|
|
296
|
-
2600822924,
|
|
297
|
-
528734635,
|
|
298
|
-
1541459225
|
|
299
|
-
]);
|
|
300
|
-
function sha256(value) {
|
|
301
|
-
const source = new TextEncoder().encode(value);
|
|
302
|
-
const paddedLength = Math.ceil((source.length + 9) / 64) * 64;
|
|
303
|
-
const bytes = new Uint8Array(paddedLength);
|
|
304
|
-
bytes.set(source);
|
|
305
|
-
bytes[source.length] = 128;
|
|
306
|
-
const bitLength = source.length * 8;
|
|
307
|
-
const view = new DataView(bytes.buffer);
|
|
308
|
-
view.setUint32(paddedLength - 8, Math.floor(bitLength / 4294967296));
|
|
309
|
-
view.setUint32(paddedLength - 4, bitLength >>> 0);
|
|
310
|
-
const hash = [...INITIAL_HASH];
|
|
311
|
-
const schedule = new Uint32Array(64);
|
|
312
|
-
for (let offset = 0; offset < bytes.length; offset += 64) {
|
|
313
|
-
for (let index = 0; index < 16; index += 1) schedule[index] = view.getUint32(offset + index * 4);
|
|
314
|
-
for (let index = 16; index < schedule.length; index += 1) {
|
|
315
|
-
const earlier = schedule[index - 15];
|
|
316
|
-
const recent = schedule[index - 2];
|
|
317
|
-
const sigma0 = rotateRight(earlier, 7) ^ rotateRight(earlier, 18) ^ earlier >>> 3;
|
|
318
|
-
const sigma1 = rotateRight(recent, 17) ^ rotateRight(recent, 19) ^ recent >>> 10;
|
|
319
|
-
schedule[index] = schedule[index - 16] + sigma0 + schedule[index - 7] + sigma1 >>> 0;
|
|
320
|
-
}
|
|
321
|
-
let [a, b, c, d, e, f, g, h] = hash;
|
|
322
|
-
for (let index = 0; index < schedule.length; index += 1) {
|
|
323
|
-
const sum1 = rotateRight(e, 6) ^ rotateRight(e, 11) ^ rotateRight(e, 25);
|
|
324
|
-
const choice = e & f ^ ~e & g;
|
|
325
|
-
const temporary1 = h + sum1 + choice + ROUND_CONSTANTS[index] + schedule[index] >>> 0;
|
|
326
|
-
const sum0 = rotateRight(a, 2) ^ rotateRight(a, 13) ^ rotateRight(a, 22);
|
|
327
|
-
const majority = a & b ^ a & c ^ b & c;
|
|
328
|
-
const temporary2 = sum0 + majority >>> 0;
|
|
329
|
-
h = g;
|
|
330
|
-
g = f;
|
|
331
|
-
f = e;
|
|
332
|
-
e = d + temporary1 >>> 0;
|
|
333
|
-
d = c;
|
|
334
|
-
c = b;
|
|
335
|
-
b = a;
|
|
336
|
-
a = temporary1 + temporary2 >>> 0;
|
|
337
|
-
}
|
|
338
|
-
const round = [a, b, c, d, e, f, g, h];
|
|
339
|
-
for (let index = 0; index < hash.length; index += 1) hash[index] = hash[index] + round[index] >>> 0;
|
|
340
|
-
}
|
|
341
|
-
return hash.map((word) => word.toString(16).padStart(8, "0")).join("");
|
|
342
|
-
}
|
|
343
|
-
function rotateRight(value, count) {
|
|
344
|
-
return value >>> count | value << 32 - count;
|
|
345
|
-
}
|
|
346
|
-
|
|
347
995
|
// src/adapter/css/css-invariant.error.ts
|
|
348
996
|
var CssInvariantError = class extends Error {
|
|
349
997
|
constructor(message) {
|
|
@@ -427,8 +1075,8 @@ function canonicalIdentity(family, declarations, context) {
|
|
|
427
1075
|
});
|
|
428
1076
|
}
|
|
429
1077
|
var CssArtifactRegistry = class {
|
|
430
|
-
constructor(
|
|
431
|
-
this.digest =
|
|
1078
|
+
constructor(digest2 = sha256) {
|
|
1079
|
+
this.digest = digest2;
|
|
432
1080
|
}
|
|
433
1081
|
rulesByCanonicalIdentity = /* @__PURE__ */ new Map();
|
|
434
1082
|
canonicalIdentityByDigest = /* @__PURE__ */ new Map();
|
|
@@ -650,7 +1298,8 @@ var CssRenderer = class {
|
|
|
650
1298
|
eligibility(input) {
|
|
651
1299
|
const family = this.cssFamily(input);
|
|
652
1300
|
if (family === void 0) return targetUnsupported(input);
|
|
653
|
-
if (input.breakpoint !== void 0 && !supportedBreakpoints.has(input.breakpoint)
|
|
1301
|
+
if (input.breakpoint !== void 0 && !supportedBreakpoints.has(input.breakpoint) && !Object.hasOwn(this.breakpointConfig.sourceBreakpoints ?? {}, input.breakpoint))
|
|
1302
|
+
return targetUnsupported(input);
|
|
654
1303
|
return void 0;
|
|
655
1304
|
}
|
|
656
1305
|
render(plan, _context) {
|
|
@@ -713,18 +1362,119 @@ var CssRenderer = class {
|
|
|
713
1362
|
}
|
|
714
1363
|
};
|
|
715
1364
|
|
|
716
|
-
// src/
|
|
717
|
-
var
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
1365
|
+
// src/config/tailwind-builtin-variants.ts
|
|
1366
|
+
var tailwindBuiltinVariants = Object.freeze([
|
|
1367
|
+
"*",
|
|
1368
|
+
"**",
|
|
1369
|
+
"@",
|
|
1370
|
+
"@max",
|
|
1371
|
+
"@min",
|
|
1372
|
+
"active",
|
|
1373
|
+
"after",
|
|
1374
|
+
"any-pointer-coarse",
|
|
1375
|
+
"any-pointer-fine",
|
|
1376
|
+
"any-pointer-none",
|
|
1377
|
+
"aria",
|
|
1378
|
+
"autofill",
|
|
1379
|
+
"backdrop",
|
|
1380
|
+
"before",
|
|
1381
|
+
"checked",
|
|
1382
|
+
"contrast-less",
|
|
1383
|
+
"contrast-more",
|
|
1384
|
+
"dark",
|
|
1385
|
+
"data",
|
|
1386
|
+
"default",
|
|
1387
|
+
"details-content",
|
|
1388
|
+
"disabled",
|
|
1389
|
+
"empty",
|
|
1390
|
+
"enabled",
|
|
1391
|
+
"even",
|
|
1392
|
+
"file",
|
|
1393
|
+
"first",
|
|
1394
|
+
"first-letter",
|
|
1395
|
+
"first-line",
|
|
1396
|
+
"first-of-type",
|
|
1397
|
+
"focus",
|
|
1398
|
+
"focus-visible",
|
|
1399
|
+
"focus-within",
|
|
1400
|
+
"forced-colors",
|
|
1401
|
+
"group",
|
|
1402
|
+
"has",
|
|
1403
|
+
"hover",
|
|
1404
|
+
"in",
|
|
1405
|
+
"in-range",
|
|
1406
|
+
"indeterminate",
|
|
1407
|
+
"inert",
|
|
1408
|
+
"invalid",
|
|
1409
|
+
"inverted-colors",
|
|
1410
|
+
"landscape",
|
|
1411
|
+
"last",
|
|
1412
|
+
"last-of-type",
|
|
1413
|
+
"ltr",
|
|
1414
|
+
"marker",
|
|
1415
|
+
"max",
|
|
1416
|
+
"min",
|
|
1417
|
+
"motion-reduce",
|
|
1418
|
+
"motion-safe",
|
|
1419
|
+
"noscript",
|
|
1420
|
+
"not",
|
|
1421
|
+
"nth",
|
|
1422
|
+
"nth-last",
|
|
1423
|
+
"nth-last-of-type",
|
|
1424
|
+
"nth-of-type",
|
|
1425
|
+
"odd",
|
|
1426
|
+
"only",
|
|
1427
|
+
"only-of-type",
|
|
1428
|
+
"open",
|
|
1429
|
+
"optional",
|
|
1430
|
+
"out-of-range",
|
|
1431
|
+
"peer",
|
|
1432
|
+
"placeholder",
|
|
1433
|
+
"placeholder-shown",
|
|
1434
|
+
"pointer-coarse",
|
|
1435
|
+
"pointer-fine",
|
|
1436
|
+
"pointer-none",
|
|
1437
|
+
"portrait",
|
|
1438
|
+
"print",
|
|
1439
|
+
"read-only",
|
|
1440
|
+
"required",
|
|
1441
|
+
"rtl",
|
|
1442
|
+
"selection",
|
|
1443
|
+
"starting",
|
|
1444
|
+
"supports",
|
|
1445
|
+
"target",
|
|
1446
|
+
"user-invalid",
|
|
1447
|
+
"user-valid",
|
|
1448
|
+
"valid",
|
|
1449
|
+
"visited"
|
|
1450
|
+
]);
|
|
1451
|
+
|
|
1452
|
+
// src/config/tailwind-candidate-profile.ts
|
|
1453
|
+
function renderTargetCandidate(candidate, profile) {
|
|
1454
|
+
const match = /^\[@media_screen_and_\(min-width:_(\d+(?:\.\d+)?)px\)\]:(.+)$/.exec(candidate);
|
|
1455
|
+
if (match) {
|
|
1456
|
+
const exact = Object.entries(profile.breakpoints).find(
|
|
1457
|
+
([name, setting]) => setting.confidence !== "unknown" && setting.value === `${match[1]}px` && isNamedBreakpoint(name)
|
|
1458
|
+
);
|
|
1459
|
+
if (exact) candidate = `[@media_screen]:${exact[0]}:${match[2]}`;
|
|
725
1460
|
}
|
|
726
|
-
|
|
727
|
-
}
|
|
1461
|
+
return profile.prefix.value ? `${profile.prefix.value}:${candidate}` : candidate;
|
|
1462
|
+
}
|
|
1463
|
+
function normalizeTargetCandidate(candidate, profile) {
|
|
1464
|
+
const prefix = profile.prefix.value;
|
|
1465
|
+
if (prefix && candidate.startsWith(`${prefix}:`)) candidate = candidate.slice(prefix.length + 1);
|
|
1466
|
+
const match = /^\[@media_screen\]:([^:]+):(.+)$/.exec(candidate);
|
|
1467
|
+
if (match) {
|
|
1468
|
+
const setting = profile.breakpoints[match[1]];
|
|
1469
|
+
const width = setting?.value;
|
|
1470
|
+
if (setting?.confidence !== "unknown" && isNamedBreakpoint(match[1]) && width?.endsWith("px"))
|
|
1471
|
+
return `[@media_screen_and_(min-width:_${width})]:${match[2]}`;
|
|
1472
|
+
}
|
|
1473
|
+
return candidate;
|
|
1474
|
+
}
|
|
1475
|
+
function isNamedBreakpoint(name) {
|
|
1476
|
+
return !tailwindBuiltinVariants.some((root) => name === root || name.startsWith(`${root}-`));
|
|
1477
|
+
}
|
|
728
1478
|
|
|
729
1479
|
// src/edit/html-attribute-value.ts
|
|
730
1480
|
var htmlSourceWhitespace = /[\t\n\f\r ]/u;
|
|
@@ -898,7 +1648,10 @@ var BreakpointCatalog = class {
|
|
|
898
1648
|
this.configuredDefinitions = new Map([
|
|
899
1649
|
...definitionsByAlias,
|
|
900
1650
|
...config.orientationBreakpoints ? orientations.map((definition) => [definition.alias, definition]) : [],
|
|
901
|
-
...config.printWithBreakpoints === void 0 ? [] : [[frozenPrintDefinition.alias, frozenPrintDefinition]]
|
|
1651
|
+
...config.printWithBreakpoints === void 0 ? [] : [[frozenPrintDefinition.alias, frozenPrintDefinition]],
|
|
1652
|
+
...Object.entries(config.sourceBreakpoints ?? {}).map(
|
|
1653
|
+
([alias, value]) => [alias, sourceBreakpointDefinition(alias, value)]
|
|
1654
|
+
)
|
|
902
1655
|
]);
|
|
903
1656
|
}
|
|
904
1657
|
classify(alias) {
|
|
@@ -2719,18 +3472,25 @@ var TailwindCandidateClassifier = class {
|
|
|
2719
3472
|
|
|
2720
3473
|
// src/evidence/tailwind-source-property.evidence.ts
|
|
2721
3474
|
var TailwindSourcePropertyEvidence = class {
|
|
3475
|
+
constructor(profile) {
|
|
3476
|
+
this.profile = profile;
|
|
3477
|
+
}
|
|
2722
3478
|
classifier = new TailwindCandidateClassifier();
|
|
2723
3479
|
styleEncoder = new TailwindArbitraryPropertyEncoder();
|
|
2724
3480
|
classifyClassToken(token) {
|
|
2725
|
-
const
|
|
3481
|
+
const prefix = this.profile?.prefix.value;
|
|
3482
|
+
if (prefix && !token.startsWith(`${prefix}:`))
|
|
3483
|
+
return { status: "unverified", reason: "Class is not a utility in the declared prefixed target." };
|
|
3484
|
+
const normalized = prefix ? token.slice(prefix.length + 1) : token;
|
|
3485
|
+
const classification = this.classifier.classify(normalized);
|
|
2726
3486
|
if (classification.status === "unverified") return classification;
|
|
2727
|
-
const display = describeTailwindDisplay(
|
|
3487
|
+
const display = describeTailwindDisplay(normalized);
|
|
2728
3488
|
return {
|
|
2729
3489
|
status: "verified",
|
|
2730
3490
|
evidence: {
|
|
2731
3491
|
source: token,
|
|
2732
3492
|
properties: classification.descriptor.cssProperties,
|
|
2733
|
-
important: classification.descriptor.important,
|
|
3493
|
+
important: classification.descriptor.important || this.profile?.important.value === "important",
|
|
2734
3494
|
activation: classification.descriptor.activation,
|
|
2735
3495
|
...display === void 0 ? {} : { display: display.utility }
|
|
2736
3496
|
}
|
|
@@ -3314,15 +4074,29 @@ function compatibleVisibilityClasses(plan, existingClassNames) {
|
|
|
3314
4074
|
var TailwindRenderer = class {
|
|
3315
4075
|
target = "tailwind";
|
|
3316
4076
|
breakpointConfig;
|
|
3317
|
-
sourcePropertyEvidence
|
|
4077
|
+
sourcePropertyEvidence;
|
|
4078
|
+
targetProfile;
|
|
3318
4079
|
responsiveEmitter = new ResponsiveVariantEmitter();
|
|
3319
4080
|
visibilityEmitter = new VisibilityEmitter();
|
|
3320
4081
|
extendedEmitter = new ExtendedResponsiveEmitter();
|
|
3321
4082
|
gridRenderer = new TailwindGridRenderer();
|
|
3322
4083
|
constructor(config = { orientationBreakpoints: false }) {
|
|
4084
|
+
this.targetProfile = config.targetProfile ?? resolveTailwindTargetProfile();
|
|
3323
4085
|
this.breakpointConfig = Object.freeze({ ...config });
|
|
4086
|
+
this.sourcePropertyEvidence = new TailwindSourcePropertyEvidence(this.targetProfile);
|
|
3324
4087
|
}
|
|
3325
4088
|
eligibility(input) {
|
|
4089
|
+
const unresolved2 = this.targetProfile.diagnostics.filter(
|
|
4090
|
+
(item) => item.code === "tailwind-prefix-conflict" || item.code === "tailwind-target-unknown" || ["tailwind-config-external", "tailwind-plugin-external", "tailwind-import-unresolved"].includes(item.code) && (this.targetProfile.coreUtilities.value === "unknown" || this.targetProfile.prefix.confidence !== "explicit" || this.targetProfile.important.confidence !== "explicit")
|
|
4091
|
+
);
|
|
4092
|
+
if (unresolved2.length)
|
|
4093
|
+
return {
|
|
4094
|
+
status: "review",
|
|
4095
|
+
input,
|
|
4096
|
+
code: "context-unverified",
|
|
4097
|
+
reason: `Target configuration is unresolved: ${unresolved2.map((item) => item.message).join(" ")}`,
|
|
4098
|
+
suggestion: "Resolve the target stylesheet or supply explicit migration profile settings before migrating."
|
|
4099
|
+
};
|
|
3326
4100
|
if (input.binding !== "property") {
|
|
3327
4101
|
if (!sharedDirectives.has(input.directive) && !visibilityDirectives.has(input.directive) && !extendedDirectives.has(input.directive) && !gridDirectives.has(input.directive)) {
|
|
3328
4102
|
return {
|
|
@@ -3336,7 +4110,12 @@ var TailwindRenderer = class {
|
|
|
3336
4110
|
}
|
|
3337
4111
|
return void 0;
|
|
3338
4112
|
}
|
|
3339
|
-
render(plan,
|
|
4113
|
+
render(plan, context) {
|
|
4114
|
+
const result2 = this.renderUnprefixed(plan, context);
|
|
4115
|
+
if (result2.status !== "converted") return result2;
|
|
4116
|
+
return { ...result2, classNames: result2.classNames.map((token) => renderTargetCandidate(token, this.targetProfile)) };
|
|
4117
|
+
}
|
|
4118
|
+
renderUnprefixed(plan, _context) {
|
|
3340
4119
|
const inputFamily = directiveFamily(plan.input.directive);
|
|
3341
4120
|
if (inputFamily !== plan.family) {
|
|
3342
4121
|
throw new MigrationApplicationError(
|
|
@@ -3414,7 +4193,15 @@ var TailwindRenderer = class {
|
|
|
3414
4193
|
};
|
|
3415
4194
|
}
|
|
3416
4195
|
resolveConflicts(plans, context) {
|
|
3417
|
-
|
|
4196
|
+
const normalize8 = (token) => normalizeTargetCandidate(token, this.targetProfile);
|
|
4197
|
+
const normalized = plans.map(
|
|
4198
|
+
(plan) => plan.status === "converted" ? { ...plan, classNames: plan.classNames.map((token) => normalize8(token)) } : plan
|
|
4199
|
+
);
|
|
4200
|
+
const resolved2 = this.resolveClassConflicts(
|
|
4201
|
+
normalized,
|
|
4202
|
+
context.existingClassNames.map((token) => normalize8(token))
|
|
4203
|
+
);
|
|
4204
|
+
return resolved2.map((plan, index) => plan.status === "converted" ? plans[index] : plan);
|
|
3418
4205
|
}
|
|
3419
4206
|
record(_plans) {
|
|
3420
4207
|
}
|
|
@@ -3448,6 +4235,10 @@ var TailwindRenderer = class {
|
|
|
3448
4235
|
} : plan
|
|
3449
4236
|
);
|
|
3450
4237
|
}
|
|
4238
|
+
unprefix(token) {
|
|
4239
|
+
const prefix = this.targetProfile.prefix.value;
|
|
4240
|
+
return prefix && token.startsWith(`${prefix}:`) ? token.slice(prefix.length + 1) : token;
|
|
4241
|
+
}
|
|
3451
4242
|
decorate(classNames, plan) {
|
|
3452
4243
|
return plan.activations.flatMap(
|
|
3453
4244
|
(planActivation) => planActivation.kind === "base" ? classNames : classNames.flatMap((className) => this.responsiveEmitter.emit(planActivation.definition, className))
|
|
@@ -3490,7 +4281,7 @@ var TailwindRenderer = class {
|
|
|
3490
4281
|
return this.extendedEmitter.emitClass({
|
|
3491
4282
|
input: plan.input,
|
|
3492
4283
|
activation: itemActivation,
|
|
3493
|
-
value: { tokens: state.tokens.map((token) => token.source) }
|
|
4284
|
+
value: { tokens: state.tokens.map((token) => this.unprefix(token.source)) }
|
|
3494
4285
|
});
|
|
3495
4286
|
})
|
|
3496
4287
|
)
|
|
@@ -3616,7 +4407,7 @@ var AdapterFactory = class {
|
|
|
3616
4407
|
};
|
|
3617
4408
|
|
|
3618
4409
|
// src/pipeline/analyze/analyze-project.stage.ts
|
|
3619
|
-
import { readFile } from "fs/promises";
|
|
4410
|
+
import { readFile as readFile2 } from "fs/promises";
|
|
3620
4411
|
|
|
3621
4412
|
// src/analyzer/flex-layout-attribute.analyzer.ts
|
|
3622
4413
|
var responsiveOnlyDirectives = /* @__PURE__ */ new Set(["class", "ngClass", "style", "ngStyle"]);
|
|
@@ -3802,10 +4593,10 @@ var AngularTemplateParser = class {
|
|
|
3802
4593
|
};
|
|
3803
4594
|
|
|
3804
4595
|
// src/pipeline/analyzed-project.ts
|
|
3805
|
-
import * as
|
|
4596
|
+
import * as path4 from "path";
|
|
3806
4597
|
|
|
3807
4598
|
// src/pipeline/project-manifest.ts
|
|
3808
|
-
import * as
|
|
4599
|
+
import * as path3 from "path";
|
|
3809
4600
|
function migrationInvocation(invocation) {
|
|
3810
4601
|
return freezeMigrationInvocation({
|
|
3811
4602
|
inputPath: invocation.inputPath,
|
|
@@ -3841,7 +4632,7 @@ function freezeMigrationInvocation(invocation) {
|
|
|
3841
4632
|
});
|
|
3842
4633
|
}
|
|
3843
4634
|
function normalizedAbsolutePath(value) {
|
|
3844
|
-
return
|
|
4635
|
+
return path3.normalize(path3.resolve(value));
|
|
3845
4636
|
}
|
|
3846
4637
|
|
|
3847
4638
|
// src/pipeline/analyzed-project.ts
|
|
@@ -3936,7 +4727,7 @@ function freezeLocatedInput(input) {
|
|
|
3936
4727
|
});
|
|
3937
4728
|
}
|
|
3938
4729
|
function normalizedAbsolutePath2(value) {
|
|
3939
|
-
return
|
|
4730
|
+
return path4.normalize(path4.resolve(value));
|
|
3940
4731
|
}
|
|
3941
4732
|
function sequenceInvariant(paths = []) {
|
|
3942
4733
|
return internalInvariant(
|
|
@@ -3950,7 +4741,7 @@ function internalInvariant(message, paths = []) {
|
|
|
3950
4741
|
|
|
3951
4742
|
// src/pipeline/analyze/analyze-project.stage.ts
|
|
3952
4743
|
var nodeSourceReader = Object.freeze({
|
|
3953
|
-
read: (
|
|
4744
|
+
read: (path19) => readFile2(path19, "utf8")
|
|
3954
4745
|
});
|
|
3955
4746
|
var AnalyzeProjectStage = class {
|
|
3956
4747
|
constructor(sourceReader = nodeSourceReader, parser = new AngularTemplateParser(), analyzer = new TemplateAnalyzer()) {
|
|
@@ -3997,13 +4788,13 @@ function runtimeArtifact(context, artifact) {
|
|
|
3997
4788
|
[artifact.path]
|
|
3998
4789
|
);
|
|
3999
4790
|
}
|
|
4000
|
-
function
|
|
4791
|
+
function identity2(stat4) {
|
|
4001
4792
|
return { dev: String(stat4.dev), ino: String(stat4.ino) };
|
|
4002
4793
|
}
|
|
4003
4794
|
function fileMode(stat4) {
|
|
4004
4795
|
return Number(stat4.mode) & 4095;
|
|
4005
4796
|
}
|
|
4006
|
-
function
|
|
4797
|
+
function sameIdentity2(left, right) {
|
|
4007
4798
|
return left.dev === right.dev && left.ino === right.ino;
|
|
4008
4799
|
}
|
|
4009
4800
|
function sameArtifactState(left, right) {
|
|
@@ -4015,14 +4806,14 @@ function required(value) {
|
|
|
4015
4806
|
if (value === void 0) throw new Error("Missing transaction state.");
|
|
4016
4807
|
return value;
|
|
4017
4808
|
}
|
|
4018
|
-
function
|
|
4809
|
+
function isEnoent2(error) {
|
|
4019
4810
|
return typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT";
|
|
4020
4811
|
}
|
|
4021
4812
|
function isDirectoryNotEmpty(error) {
|
|
4022
4813
|
return typeof error === "object" && error !== null && "code" in error && (error.code === "ENOTEMPTY" || error.code === "EEXIST");
|
|
4023
4814
|
}
|
|
4024
|
-
function pathDepth(
|
|
4025
|
-
return
|
|
4815
|
+
function pathDepth(path19) {
|
|
4816
|
+
return path19.split(/[\\/]/u).filter(Boolean).length;
|
|
4026
4817
|
}
|
|
4027
4818
|
function recoveryOutcome(paths, failures) {
|
|
4028
4819
|
return { paths: sortedUnique(paths), failures: Object.freeze([...failures]) };
|
|
@@ -4082,13 +4873,13 @@ var FileSystemCleanupUnit = class {
|
|
|
4082
4873
|
try {
|
|
4083
4874
|
await this.port.assertNamespace(item);
|
|
4084
4875
|
const before = await this.port.lstat(owned.path);
|
|
4085
|
-
if (!
|
|
4876
|
+
if (!sameIdentity2(identity2(before), owned.identity) || before.isSymbolicLink() || !before.isFile()) {
|
|
4086
4877
|
paths.add(owned.publicPath);
|
|
4087
4878
|
failures.push(new Error("Invocation-owned file identity could not be confirmed."));
|
|
4088
4879
|
return;
|
|
4089
4880
|
}
|
|
4090
4881
|
} catch (error) {
|
|
4091
|
-
if (
|
|
4882
|
+
if (isEnoent2(error)) {
|
|
4092
4883
|
this.port.journal.markOwnedFileAbsent(item, owned.path);
|
|
4093
4884
|
return;
|
|
4094
4885
|
}
|
|
@@ -4099,13 +4890,13 @@ var FileSystemCleanupUnit = class {
|
|
|
4099
4890
|
try {
|
|
4100
4891
|
await this.port.unlink(owned.path);
|
|
4101
4892
|
} catch (error) {
|
|
4102
|
-
if (!
|
|
4893
|
+
if (!isEnoent2(error)) failures.push(error);
|
|
4103
4894
|
}
|
|
4104
4895
|
try {
|
|
4105
4896
|
await this.port.lstat(owned.path);
|
|
4106
4897
|
paths.add(owned.publicPath);
|
|
4107
4898
|
} catch (error) {
|
|
4108
|
-
if (
|
|
4899
|
+
if (isEnoent2(error)) this.port.journal.markOwnedFileAbsent(item, owned.path);
|
|
4109
4900
|
else {
|
|
4110
4901
|
paths.add(owned.publicPath);
|
|
4111
4902
|
failures.push(error);
|
|
@@ -4121,13 +4912,13 @@ var FileSystemCleanupUnit = class {
|
|
|
4121
4912
|
}
|
|
4122
4913
|
try {
|
|
4123
4914
|
const namespaceStat = await this.port.lstat(namespace.path);
|
|
4124
|
-
if (!
|
|
4915
|
+
if (!sameIdentity2(identity2(namespaceStat), namespace.identity) || namespaceStat.isSymbolicLink() || !namespaceStat.isDirectory()) {
|
|
4125
4916
|
paths.add(namespace.publicPath);
|
|
4126
4917
|
failures.push(new Error("Invocation namespace identity could not be confirmed."));
|
|
4127
4918
|
return;
|
|
4128
4919
|
}
|
|
4129
4920
|
} catch (error) {
|
|
4130
|
-
if (
|
|
4921
|
+
if (isEnoent2(error)) {
|
|
4131
4922
|
this.port.journal.markNamespaceAbsent(item);
|
|
4132
4923
|
return;
|
|
4133
4924
|
}
|
|
@@ -4138,13 +4929,13 @@ var FileSystemCleanupUnit = class {
|
|
|
4138
4929
|
try {
|
|
4139
4930
|
await this.port.rmdir(namespace.path);
|
|
4140
4931
|
} catch (error) {
|
|
4141
|
-
if (!isDirectoryNotEmpty(error) && !
|
|
4932
|
+
if (!isDirectoryNotEmpty(error) && !isEnoent2(error)) failures.push(error);
|
|
4142
4933
|
}
|
|
4143
4934
|
try {
|
|
4144
4935
|
await this.port.lstat(namespace.path);
|
|
4145
4936
|
paths.add(namespace.publicPath);
|
|
4146
4937
|
} catch (error) {
|
|
4147
|
-
if (
|
|
4938
|
+
if (isEnoent2(error)) this.port.journal.markNamespaceAbsent(item);
|
|
4148
4939
|
else {
|
|
4149
4940
|
paths.add(namespace.publicPath);
|
|
4150
4941
|
failures.push(error);
|
|
@@ -4170,7 +4961,7 @@ var FileSystemCleanupUnit = class {
|
|
|
4170
4961
|
try {
|
|
4171
4962
|
before = await this.port.lstat(directory.path);
|
|
4172
4963
|
} catch (error) {
|
|
4173
|
-
if (
|
|
4964
|
+
if (isEnoent2(error)) {
|
|
4174
4965
|
this.port.journal.markCreatedDirectoryAbsent(directory.path);
|
|
4175
4966
|
continue;
|
|
4176
4967
|
}
|
|
@@ -4178,7 +4969,7 @@ var FileSystemCleanupUnit = class {
|
|
|
4178
4969
|
failures.push(error);
|
|
4179
4970
|
continue;
|
|
4180
4971
|
}
|
|
4181
|
-
if (!
|
|
4972
|
+
if (!sameIdentity2(identity2(before), directory.identity) || before.isSymbolicLink() || !before.isDirectory()) {
|
|
4182
4973
|
for (const publicPath of directory.publicPaths) paths.add(publicPath);
|
|
4183
4974
|
continue;
|
|
4184
4975
|
}
|
|
@@ -4193,17 +4984,17 @@ var FileSystemCleanupUnit = class {
|
|
|
4193
4984
|
after = await this.port.lstatOrAbsent(directory.path);
|
|
4194
4985
|
} catch (error) {
|
|
4195
4986
|
for (const publicPath of directory.publicPaths) paths.add(publicPath);
|
|
4196
|
-
if (removalFailure !== void 0 && !
|
|
4987
|
+
if (removalFailure !== void 0 && !isEnoent2(removalFailure)) failures.push(removalFailure);
|
|
4197
4988
|
failures.push(error);
|
|
4198
4989
|
continue;
|
|
4199
4990
|
}
|
|
4200
4991
|
if (after === "absent") {
|
|
4201
4992
|
this.port.journal.markCreatedDirectoryAbsent(directory.path);
|
|
4202
|
-
if (removalFailure !== void 0 && !
|
|
4993
|
+
if (removalFailure !== void 0 && !isEnoent2(removalFailure)) failures.push(removalFailure);
|
|
4203
4994
|
continue;
|
|
4204
4995
|
}
|
|
4205
4996
|
for (const publicPath of directory.publicPaths) paths.add(publicPath);
|
|
4206
|
-
if (removalFailure !== void 0 && !
|
|
4997
|
+
if (removalFailure !== void 0 && !isEnoent2(removalFailure)) failures.push(removalFailure);
|
|
4207
4998
|
}
|
|
4208
4999
|
}
|
|
4209
5000
|
async collectUnconfirmedPaths(paths, failures) {
|
|
@@ -4211,7 +5002,7 @@ var FileSystemCleanupUnit = class {
|
|
|
4211
5002
|
try {
|
|
4212
5003
|
await this.port.lstat(candidate);
|
|
4213
5004
|
} catch (error) {
|
|
4214
|
-
if (
|
|
5005
|
+
if (isEnoent2(error)) continue;
|
|
4215
5006
|
failures.push(error);
|
|
4216
5007
|
}
|
|
4217
5008
|
for (const publicPath of publicPaths) paths.add(publicPath);
|
|
@@ -4229,7 +5020,7 @@ var FileSystemCleanupUnit = class {
|
|
|
4229
5020
|
if (!sameArtifactState(observed, item.artifact.original)) return false;
|
|
4230
5021
|
if (observed.status === "absent") return true;
|
|
4231
5022
|
return [item.originalIdentity, item.restoredIdentity].some(
|
|
4232
|
-
(expected) => expected !== void 0 &&
|
|
5023
|
+
(expected) => expected !== void 0 && sameIdentity2(observed.identity, expected)
|
|
4233
5024
|
);
|
|
4234
5025
|
}
|
|
4235
5026
|
};
|
|
@@ -4282,7 +5073,7 @@ var FileSystemCommitUnit = class {
|
|
|
4282
5073
|
}
|
|
4283
5074
|
async captureOriginal(item, signal) {
|
|
4284
5075
|
const firstCapture = await this.port.observePublic(item);
|
|
4285
|
-
if (!sameArtifactState(firstCapture, item.artifact.original) || firstCapture.status !== "present" || !item.originalIdentity || !
|
|
5076
|
+
if (!sameArtifactState(firstCapture, item.artifact.original) || firstCapture.status !== "present" || !item.originalIdentity || !sameIdentity2(firstCapture.identity, item.originalIdentity)) {
|
|
4286
5077
|
throw this.port.concurrentModification(item.artifact.path);
|
|
4287
5078
|
}
|
|
4288
5079
|
const backup = await this.port.createBackupFile(item, firstCapture.contents, signal, firstCapture.mode);
|
|
@@ -4290,7 +5081,7 @@ var FileSystemCommitUnit = class {
|
|
|
4290
5081
|
throw this.port.ownershipFailure(item.artifact.path);
|
|
4291
5082
|
}
|
|
4292
5083
|
const secondCapture = await this.port.observePublic(item);
|
|
4293
|
-
if (secondCapture.status !== "present" || !
|
|
5084
|
+
if (secondCapture.status !== "present" || !sameIdentity2(secondCapture.identity, firstCapture.identity) || secondCapture.contents !== firstCapture.contents) {
|
|
4294
5085
|
throw this.port.concurrentModification(item.artifact.path);
|
|
4295
5086
|
}
|
|
4296
5087
|
await this.quarantineOriginal(item, firstCapture);
|
|
@@ -4299,7 +5090,7 @@ var FileSystemCommitUnit = class {
|
|
|
4299
5090
|
await this.port.assertParentChain(item);
|
|
4300
5091
|
await this.port.assertNamespace(item);
|
|
4301
5092
|
const immediatelyBefore = await this.port.observePublic(item);
|
|
4302
|
-
if (immediatelyBefore.status !== "present" || !
|
|
5093
|
+
if (immediatelyBefore.status !== "present" || !sameIdentity2(immediatelyBefore.identity, captured.identity) || immediatelyBefore.contents !== captured.contents) {
|
|
4303
5094
|
throw this.port.concurrentModification(item.artifact.path);
|
|
4304
5095
|
}
|
|
4305
5096
|
let quarantine = this.port.journal.addQuarantine(
|
|
@@ -4315,9 +5106,9 @@ var FileSystemCommitUnit = class {
|
|
|
4315
5106
|
}
|
|
4316
5107
|
const quarantinedStat = await this.port.lstatOrAbsent(quarantine.path);
|
|
4317
5108
|
if (quarantinedStat !== "absent") {
|
|
4318
|
-
quarantine = this.port.journal.confirmOwnedFile(item, quarantine.path,
|
|
5109
|
+
quarantine = this.port.journal.confirmOwnedFile(item, quarantine.path, identity2(quarantinedStat));
|
|
4319
5110
|
const quarantinedContents = await this.port.readOwnedFile(item, quarantine.path);
|
|
4320
|
-
if (!
|
|
5111
|
+
if (!sameIdentity2(required(quarantine.identity), captured.identity) || quarantinedContents !== captured.contents) {
|
|
4321
5112
|
this.port.journal.setOwnedFilePreserved(item, quarantine.path, true);
|
|
4322
5113
|
await this.restorePreservedQuarantine(item, quarantine);
|
|
4323
5114
|
throw this.port.concurrentModification(item.artifact.path, renameFailure);
|
|
@@ -4329,7 +5120,7 @@ var FileSystemCommitUnit = class {
|
|
|
4329
5120
|
return;
|
|
4330
5121
|
}
|
|
4331
5122
|
const destination = await this.port.lstatOrAbsent(item.artifact.path);
|
|
4332
|
-
if (renameFailure !== void 0 && destination !== "absent" &&
|
|
5123
|
+
if (renameFailure !== void 0 && destination !== "absent" && sameIdentity2(identity2(destination), captured.identity)) {
|
|
4333
5124
|
throw renameFailure;
|
|
4334
5125
|
}
|
|
4335
5126
|
throw this.port.concurrentModification(item.artifact.path, renameFailure);
|
|
@@ -4346,7 +5137,7 @@ var FileSystemCommitUnit = class {
|
|
|
4346
5137
|
linkFailure = error;
|
|
4347
5138
|
}
|
|
4348
5139
|
const destination = await this.port.lstatOrAbsent(item.artifact.path);
|
|
4349
|
-
if (destination !== "absent" && stage.identity &&
|
|
5140
|
+
if (destination !== "absent" && stage.identity && sameIdentity2(identity2(destination), stage.identity)) {
|
|
4350
5141
|
this.port.journal.recordInstalledIdentity(item, stage.identity);
|
|
4351
5142
|
await this.port.assertParentChain(item);
|
|
4352
5143
|
if (linkFailure !== void 0) throw linkFailure;
|
|
@@ -4365,7 +5156,7 @@ var FileSystemCommitUnit = class {
|
|
|
4365
5156
|
this.port.journal.recordRecoveryFailure(error);
|
|
4366
5157
|
}
|
|
4367
5158
|
const destination = await this.port.lstatOrAbsent(item.artifact.path);
|
|
4368
|
-
if (destination !== "absent" &&
|
|
5159
|
+
if (destination !== "absent" && sameIdentity2(identity2(destination), quarantineIdentity)) {
|
|
4369
5160
|
this.port.journal.setOwnedFilePreserved(item, quarantine.path, false);
|
|
4370
5161
|
}
|
|
4371
5162
|
}
|
|
@@ -4427,8 +5218,8 @@ var FileSystemRollbackUnit = class {
|
|
|
4427
5218
|
}
|
|
4428
5219
|
if (current !== "unknown" && this.isConfirmedOriginal(item, current)) return;
|
|
4429
5220
|
if (current !== "unknown" && current.status === "present") {
|
|
4430
|
-
if (!item.installedIdentity || !
|
|
4431
|
-
if (item.stage && item.installedIdentity &&
|
|
5221
|
+
if (!item.installedIdentity || !sameIdentity2(current.identity, item.installedIdentity) || item.artifact.proposed.status !== "present" || current.contents !== item.artifact.proposed.contents) {
|
|
5222
|
+
if (item.stage && item.installedIdentity && sameIdentity2(current.identity, item.installedIdentity)) {
|
|
4432
5223
|
this.port.journal.setOwnedFilePreserved(item, item.stage.path, true);
|
|
4433
5224
|
}
|
|
4434
5225
|
return;
|
|
@@ -4450,7 +5241,7 @@ var FileSystemRollbackUnit = class {
|
|
|
4450
5241
|
failures.push(error);
|
|
4451
5242
|
}
|
|
4452
5243
|
const restored = await this.port.lstatOrAbsent(item.artifact.path);
|
|
4453
|
-
if (restored !== "absent" && !restored.isSymbolicLink() && restored.isFile() && backup.identity &&
|
|
5244
|
+
if (restored !== "absent" && !restored.isSymbolicLink() && restored.isFile() && backup.identity && sameIdentity2(identity2(restored), backup.identity)) {
|
|
4454
5245
|
this.port.journal.recordRestoredIdentity(item, backup.identity);
|
|
4455
5246
|
}
|
|
4456
5247
|
} catch (error) {
|
|
@@ -4466,7 +5257,7 @@ var FileSystemRollbackUnit = class {
|
|
|
4466
5257
|
await this.port.assertParentChain(item);
|
|
4467
5258
|
await this.port.assertNamespace(item);
|
|
4468
5259
|
const before = await this.port.observePublic(item);
|
|
4469
|
-
if (before.status !== "present" || !
|
|
5260
|
+
if (before.status !== "present" || !sameIdentity2(before.identity, current.identity) || before.contents !== current.contents) {
|
|
4470
5261
|
return false;
|
|
4471
5262
|
}
|
|
4472
5263
|
await this.port.assertExpectedAbsent(quarantine.path, item.artifact.path);
|
|
@@ -4477,9 +5268,9 @@ var FileSystemRollbackUnit = class {
|
|
|
4477
5268
|
}
|
|
4478
5269
|
const quarantined = await this.port.lstatOrAbsent(quarantine.path);
|
|
4479
5270
|
if (quarantined === "absent") return false;
|
|
4480
|
-
quarantine = this.port.journal.confirmOwnedFile(item, quarantine.path,
|
|
5271
|
+
quarantine = this.port.journal.confirmOwnedFile(item, quarantine.path, identity2(quarantined));
|
|
4481
5272
|
this.port.journal.setOwnedFilePreserved(item, quarantine.path, true);
|
|
4482
|
-
if (!
|
|
5273
|
+
if (!sameIdentity2(required(quarantine.identity), current.identity)) {
|
|
4483
5274
|
await this.restorePreservedQuarantine(item, quarantine, failures);
|
|
4484
5275
|
return false;
|
|
4485
5276
|
}
|
|
@@ -4503,7 +5294,7 @@ var FileSystemRollbackUnit = class {
|
|
|
4503
5294
|
failures.push(error);
|
|
4504
5295
|
}
|
|
4505
5296
|
const destination = await this.port.lstatOrAbsent(item.artifact.path);
|
|
4506
|
-
if (destination !== "absent" &&
|
|
5297
|
+
if (destination !== "absent" && sameIdentity2(identity2(destination), quarantineIdentity)) {
|
|
4507
5298
|
this.port.journal.setOwnedFilePreserved(item, quarantine.path, false);
|
|
4508
5299
|
}
|
|
4509
5300
|
}
|
|
@@ -4519,7 +5310,7 @@ var FileSystemRollbackUnit = class {
|
|
|
4519
5310
|
if (!sameArtifactState(observed, item.artifact.original)) return false;
|
|
4520
5311
|
if (observed.status === "absent") return true;
|
|
4521
5312
|
return [item.originalIdentity, item.restoredIdentity].some(
|
|
4522
|
-
(expected) => expected !== void 0 &&
|
|
5313
|
+
(expected) => expected !== void 0 && sameIdentity2(observed.identity, expected)
|
|
4523
5314
|
);
|
|
4524
5315
|
}
|
|
4525
5316
|
};
|
|
@@ -4594,7 +5385,7 @@ var FileSystemStagingUnit = class {
|
|
|
4594
5385
|
if (createdStat.isSymbolicLink() || !createdStat.isDirectory()) {
|
|
4595
5386
|
throw this.port.concurrentModification(item.artifact.path);
|
|
4596
5387
|
}
|
|
4597
|
-
this.port.journal.confirmCreatedDirectory(expectation.path,
|
|
5388
|
+
this.port.journal.confirmCreatedDirectory(expectation.path, identity2(createdStat));
|
|
4598
5389
|
if (parentExpectation) await this.port.assertExpectedDirectory(parentExpectation, item);
|
|
4599
5390
|
}
|
|
4600
5391
|
await this.port.assertParentChain(item);
|
|
@@ -4614,7 +5405,7 @@ var FileSystemStagingUnit = class {
|
|
|
4614
5405
|
if (namespaceStat.isSymbolicLink() || !namespaceStat.isDirectory()) {
|
|
4615
5406
|
throw this.port.concurrentModification(item.artifact.path);
|
|
4616
5407
|
}
|
|
4617
|
-
this.port.journal.confirmNamespace(item,
|
|
5408
|
+
this.port.journal.confirmNamespace(item, identity2(namespaceStat));
|
|
4618
5409
|
await this.port.assertParentChain(item);
|
|
4619
5410
|
}
|
|
4620
5411
|
};
|
|
@@ -4647,17 +5438,17 @@ var TransactionSignalRegistrar = class {
|
|
|
4647
5438
|
|
|
4648
5439
|
// src/transaction/transaction-unit.session.ts
|
|
4649
5440
|
import { constants } from "fs";
|
|
4650
|
-
import { access, link, lstat, mkdir, open, rename, rmdir, stat, unlink } from "fs/promises";
|
|
5441
|
+
import { access, link, lstat as lstat2, mkdir, open, rename, rmdir, stat as stat2, unlink } from "fs/promises";
|
|
4651
5442
|
import { dirname as dirname2, join as join4, resolve as resolve3 } from "path";
|
|
4652
5443
|
var nodeTransactionOperations = {
|
|
4653
5444
|
access,
|
|
4654
5445
|
link,
|
|
4655
|
-
lstat,
|
|
5446
|
+
lstat: lstat2,
|
|
4656
5447
|
mkdir,
|
|
4657
5448
|
open: (target, flags) => open(target, flags),
|
|
4658
5449
|
rename,
|
|
4659
5450
|
rmdir,
|
|
4660
|
-
stat,
|
|
5451
|
+
stat: stat2,
|
|
4661
5452
|
unlink
|
|
4662
5453
|
};
|
|
4663
5454
|
var TransactionUnitSession = class {
|
|
@@ -4678,30 +5469,30 @@ var TransactionUnitSession = class {
|
|
|
4678
5469
|
const journal = Object.freeze({
|
|
4679
5470
|
prepare: (artifacts) => this.prepare(artifacts),
|
|
4680
5471
|
artifacts: () => Object.freeze(this.context.items.map(stagingArtifactView)),
|
|
4681
|
-
createdDirectory: (
|
|
4682
|
-
addCreatedDirectoryPublicPath: (
|
|
4683
|
-
recordUnconfirmedEntry: (
|
|
4684
|
-
recordCreatedDirectory: (
|
|
4685
|
-
confirmCreatedDirectory: (
|
|
4686
|
-
required(this.context.createdDirectories.get(
|
|
5472
|
+
createdDirectory: (path19) => createdDirectoryView(this.context.createdDirectories.get(path19)),
|
|
5473
|
+
addCreatedDirectoryPublicPath: (path19, publicPath) => required(this.context.createdDirectories.get(path19)).publicPaths.add(publicPath),
|
|
5474
|
+
recordUnconfirmedEntry: (path19, publicPath) => this.recordUnconfirmedEntry(path19, publicPath),
|
|
5475
|
+
recordCreatedDirectory: (path19, publicPath) => this.recordCreatedDirectory(path19, publicPath),
|
|
5476
|
+
confirmCreatedDirectory: (path19, expected) => {
|
|
5477
|
+
required(this.context.createdDirectories.get(path19)).identity = expected;
|
|
4687
5478
|
},
|
|
4688
|
-
recordNamespace: (item,
|
|
5479
|
+
recordNamespace: (item, path19) => this.recordNamespace(item.artifact, path19),
|
|
4689
5480
|
confirmNamespace: (item, expected) => {
|
|
4690
5481
|
required(this.runtimeArtifact(item.artifact).namespace).identity = expected;
|
|
4691
5482
|
}
|
|
4692
5483
|
});
|
|
4693
5484
|
return Object.freeze({
|
|
4694
5485
|
journal,
|
|
4695
|
-
assertDirectoryExpectation: (
|
|
4696
|
-
assertDirectoryIdentity: (
|
|
4697
|
-
assertExpectedAbsent: (
|
|
5486
|
+
assertDirectoryExpectation: (path19, expected, publicPath) => this.assertDirectoryExpectation(path19, expected, publicPath),
|
|
5487
|
+
assertDirectoryIdentity: (path19, expected, publicPath) => this.assertDirectoryIdentity(path19, expected, publicPath),
|
|
5488
|
+
assertExpectedAbsent: (path19, publicPath) => this.assertExpectedAbsent(path19, publicPath),
|
|
4698
5489
|
assertExpectedDirectory: (expectation, item) => this.assertExpectedDirectory(expectation, this.runtimeArtifact(item.artifact), this.context),
|
|
4699
5490
|
assertNotInterrupted: (signal) => this.assertNotInterrupted(signal),
|
|
4700
5491
|
assertParentChain: (item) => this.assertParentChain(this.runtimeArtifact(item.artifact), this.context),
|
|
4701
5492
|
concurrentModification: (publicPath, cause) => this.concurrentModification(publicPath, cause),
|
|
4702
5493
|
createStageFile: (item, contents, signal, mode) => this.createStageFile(this.runtimeArtifact(item.artifact), contents, signal, mode),
|
|
4703
|
-
lstat: (
|
|
4704
|
-
mkdir: (
|
|
5494
|
+
lstat: (path19) => this.operations.lstat(path19),
|
|
5495
|
+
mkdir: (path19, options) => this.operations.mkdir(path19, options),
|
|
4705
5496
|
readOwnedFile: (item, ownedPath) => {
|
|
4706
5497
|
const runtime = this.runtimeArtifact(item.artifact);
|
|
4707
5498
|
return this.readOwnedFile(runtime, this.ownedFile(runtime, ownedPath));
|
|
@@ -4713,7 +5504,7 @@ var TransactionUnitSession = class {
|
|
|
4713
5504
|
const journal = Object.freeze({
|
|
4714
5505
|
artifact: (artifact) => commitArtifactView(this.runtimeArtifact(artifact)),
|
|
4715
5506
|
artifacts: () => Object.freeze(this.context.items.map(commitArtifactView)),
|
|
4716
|
-
addQuarantine: (item,
|
|
5507
|
+
addQuarantine: (item, path19) => ownedFileView(this.addQuarantine(this.runtimeArtifact(item.artifact), path19)),
|
|
4717
5508
|
confirmOwnedFile: (item, ownedPath, expected) => ownedFileView(this.confirmOwnedFile(this.runtimeArtifact(item.artifact), ownedPath, expected)),
|
|
4718
5509
|
setOwnedFilePreserved: (item, ownedPath, preserve) => {
|
|
4719
5510
|
this.ownedFile(this.runtimeArtifact(item.artifact), ownedPath).preserve = preserve;
|
|
@@ -4725,7 +5516,7 @@ var TransactionUnitSession = class {
|
|
|
4725
5516
|
});
|
|
4726
5517
|
return Object.freeze({
|
|
4727
5518
|
journal,
|
|
4728
|
-
assertExpectedAbsent: (
|
|
5519
|
+
assertExpectedAbsent: (path19, publicPath) => this.assertExpectedAbsent(path19, publicPath),
|
|
4729
5520
|
assertNamespace: (item) => this.assertNamespace(this.runtimeArtifact(item.artifact)),
|
|
4730
5521
|
assertNotInterrupted: (signal) => this.assertNotInterrupted(signal),
|
|
4731
5522
|
assertOwnedIdentity: (item, ownedPath) => {
|
|
@@ -4736,7 +5527,7 @@ var TransactionUnitSession = class {
|
|
|
4736
5527
|
concurrentModification: (publicPath, cause) => this.concurrentModification(publicPath, cause),
|
|
4737
5528
|
createBackupFile: (item, contents, signal, mode) => this.createBackupFile(this.runtimeArtifact(item.artifact), contents, signal, mode),
|
|
4738
5529
|
link: (existingPath, newPath) => this.operations.link(existingPath, newPath),
|
|
4739
|
-
lstatOrAbsent: (
|
|
5530
|
+
lstatOrAbsent: (path19) => this.lstatOrAbsent(path19),
|
|
4740
5531
|
observePublic: (item) => this.observePublic(this.runtimeArtifact(item.artifact), this.context),
|
|
4741
5532
|
ownershipFailure: (publicPath) => this.ownershipFailure(publicPath),
|
|
4742
5533
|
readOwnedFile: (item, ownedPath) => {
|
|
@@ -4751,7 +5542,7 @@ var TransactionUnitSession = class {
|
|
|
4751
5542
|
artifact: (artifact) => rollbackArtifactView(this.runtimeArtifact(artifact)),
|
|
4752
5543
|
artifacts: () => Object.freeze(this.context.items.map(rollbackArtifactView)),
|
|
4753
5544
|
recoveryFailures: () => Object.freeze([...this.context.recoveryFailures]),
|
|
4754
|
-
addQuarantine: (item,
|
|
5545
|
+
addQuarantine: (item, path19) => ownedFileView(this.addQuarantine(this.runtimeArtifact(item.artifact), path19)),
|
|
4755
5546
|
confirmOwnedFile: (item, ownedPath, expected) => ownedFileView(this.confirmOwnedFile(this.runtimeArtifact(item.artifact), ownedPath, expected)),
|
|
4756
5547
|
setOwnedFilePreserved: (item, ownedPath, preserve) => {
|
|
4757
5548
|
this.ownedFile(this.runtimeArtifact(item.artifact), ownedPath).preserve = preserve;
|
|
@@ -4765,11 +5556,11 @@ var TransactionUnitSession = class {
|
|
|
4765
5556
|
});
|
|
4766
5557
|
return Object.freeze({
|
|
4767
5558
|
journal,
|
|
4768
|
-
assertExpectedAbsent: (
|
|
5559
|
+
assertExpectedAbsent: (path19, publicPath) => this.assertExpectedAbsent(path19, publicPath),
|
|
4769
5560
|
assertNamespace: (item) => this.assertNamespace(this.runtimeArtifact(item.artifact)),
|
|
4770
5561
|
assertParentChain: (item) => this.assertParentChain(this.runtimeArtifact(item.artifact), this.context),
|
|
4771
5562
|
link: (existingPath, newPath) => this.operations.link(existingPath, newPath),
|
|
4772
|
-
lstatOrAbsent: (
|
|
5563
|
+
lstatOrAbsent: (path19) => this.lstatOrAbsent(path19),
|
|
4773
5564
|
observePublic: (item) => this.observePublic(this.runtimeArtifact(item.artifact), this.context),
|
|
4774
5565
|
readOwnedFile: (item, ownedPath) => {
|
|
4775
5566
|
const runtime = this.runtimeArtifact(item.artifact);
|
|
@@ -4791,8 +5582,8 @@ var TransactionUnitSession = class {
|
|
|
4791
5582
|
markNamespaceAbsent: (item) => {
|
|
4792
5583
|
required(this.runtimeArtifact(item.artifact).namespace).exists = false;
|
|
4793
5584
|
},
|
|
4794
|
-
markCreatedDirectoryAbsent: (
|
|
4795
|
-
required(this.context.createdDirectories.get(
|
|
5585
|
+
markCreatedDirectoryAbsent: (path19) => {
|
|
5586
|
+
required(this.context.createdDirectories.get(path19)).exists = false;
|
|
4796
5587
|
this.context.ownershipChanged();
|
|
4797
5588
|
},
|
|
4798
5589
|
finishArtifactCleanup: () => this.context.ownershipChanged()
|
|
@@ -4802,11 +5593,11 @@ var TransactionUnitSession = class {
|
|
|
4802
5593
|
assertNamespace: (item) => this.assertNamespace(this.runtimeArtifact(item.artifact)),
|
|
4803
5594
|
closeReadHandles: (item, failures) => this.closeReadHandles(this.runtimeArtifact(item.artifact), failures),
|
|
4804
5595
|
closeOpenHandle: (item, failures) => this.closeOpenHandle(this.runtimeArtifact(item.artifact), failures),
|
|
4805
|
-
lstat: (
|
|
4806
|
-
lstatOrAbsent: (
|
|
5596
|
+
lstat: (path19) => this.operations.lstat(path19),
|
|
5597
|
+
lstatOrAbsent: (path19) => this.lstatOrAbsent(path19),
|
|
4807
5598
|
observePublic: (item) => this.observePublic(this.runtimeArtifact(item.artifact), this.context),
|
|
4808
|
-
rmdir: (
|
|
4809
|
-
unlink: (
|
|
5599
|
+
rmdir: (path19) => this.operations.rmdir(path19),
|
|
5600
|
+
unlink: (path19) => this.operations.unlink(path19)
|
|
4810
5601
|
});
|
|
4811
5602
|
}
|
|
4812
5603
|
async prepareForPreflight(artifacts) {
|
|
@@ -4881,16 +5672,16 @@ var TransactionUnitSession = class {
|
|
|
4881
5672
|
result2.push({
|
|
4882
5673
|
path: candidate,
|
|
4883
5674
|
original: {
|
|
4884
|
-
identity:
|
|
5675
|
+
identity: identity2(candidateStat),
|
|
4885
5676
|
kind: "symbolic-link",
|
|
4886
|
-
followedIdentity:
|
|
5677
|
+
followedIdentity: identity2(followed)
|
|
4887
5678
|
}
|
|
4888
5679
|
});
|
|
4889
5680
|
} else {
|
|
4890
|
-
result2.push({ path: candidate, original: { identity:
|
|
5681
|
+
result2.push({ path: candidate, original: { identity: identity2(candidateStat), kind: "directory" } });
|
|
4891
5682
|
}
|
|
4892
5683
|
} catch (error) {
|
|
4893
|
-
if (!
|
|
5684
|
+
if (!isEnoent2(error)) throw error;
|
|
4894
5685
|
missing = true;
|
|
4895
5686
|
result2.push({ path: candidate, original: "absent" });
|
|
4896
5687
|
}
|
|
@@ -4915,9 +5706,9 @@ var TransactionUnitSession = class {
|
|
|
4915
5706
|
await this.writeOwnedFile(item, owned, contents, signal, mode);
|
|
4916
5707
|
return ownedFileView(owned);
|
|
4917
5708
|
}
|
|
4918
|
-
registerOwnedFile(item,
|
|
5709
|
+
registerOwnedFile(item, path19) {
|
|
4919
5710
|
const owned = {
|
|
4920
|
-
path:
|
|
5711
|
+
path: path19,
|
|
4921
5712
|
publicPath: item.artifact.path,
|
|
4922
5713
|
exists: false,
|
|
4923
5714
|
preserve: false
|
|
@@ -4932,7 +5723,7 @@ var TransactionUnitSession = class {
|
|
|
4932
5723
|
item.openHandle = handle;
|
|
4933
5724
|
this.context.ownershipChanged();
|
|
4934
5725
|
if (mode !== void 0) await handle.chmod(mode);
|
|
4935
|
-
owned.identity =
|
|
5726
|
+
owned.identity = identity2(await handle.stat());
|
|
4936
5727
|
this.assertNotInterrupted(signal);
|
|
4937
5728
|
await handle.writeFile(contents, "utf8");
|
|
4938
5729
|
this.assertNotInterrupted(signal);
|
|
@@ -4946,48 +5737,48 @@ var TransactionUnitSession = class {
|
|
|
4946
5737
|
runtimeArtifact(artifact) {
|
|
4947
5738
|
return runtimeArtifact(this.context, artifact);
|
|
4948
5739
|
}
|
|
4949
|
-
ownedFile(item,
|
|
4950
|
-
const owned = item.ownedFiles.find((candidate) => candidate.path ===
|
|
5740
|
+
ownedFile(item, path19) {
|
|
5741
|
+
const owned = item.ownedFiles.find((candidate) => candidate.path === path19);
|
|
4951
5742
|
if (owned !== void 0) return owned;
|
|
4952
5743
|
throw new MigrationApplicationError(
|
|
4953
5744
|
"internal-invariant",
|
|
4954
|
-
`Migration transaction journal contains an unknown invocation-owned file: ${
|
|
5745
|
+
`Migration transaction journal contains an unknown invocation-owned file: ${path19}`,
|
|
4955
5746
|
[item.artifact.path]
|
|
4956
5747
|
);
|
|
4957
5748
|
}
|
|
4958
|
-
addQuarantine(item,
|
|
4959
|
-
const quarantine = this.registerOwnedFile(item,
|
|
5749
|
+
addQuarantine(item, path19) {
|
|
5750
|
+
const quarantine = this.registerOwnedFile(item, path19);
|
|
4960
5751
|
item.quarantines.push(quarantine);
|
|
4961
5752
|
return quarantine;
|
|
4962
5753
|
}
|
|
4963
|
-
confirmOwnedFile(item,
|
|
4964
|
-
const owned = this.ownedFile(item,
|
|
5754
|
+
confirmOwnedFile(item, path19, expected) {
|
|
5755
|
+
const owned = this.ownedFile(item, path19);
|
|
4965
5756
|
owned.exists = true;
|
|
4966
5757
|
owned.identity = expected;
|
|
4967
5758
|
return owned;
|
|
4968
5759
|
}
|
|
4969
|
-
recordNamespace(artifact,
|
|
5760
|
+
recordNamespace(artifact, path19) {
|
|
4970
5761
|
const item = this.runtimeArtifact(artifact);
|
|
4971
|
-
item.namespace = { path:
|
|
5762
|
+
item.namespace = { path: path19, publicPath: item.artifact.path, exists: true };
|
|
4972
5763
|
this.context.ownershipChanged();
|
|
4973
5764
|
}
|
|
4974
|
-
recordCreatedDirectory(
|
|
4975
|
-
this.context.createdDirectories.set(
|
|
4976
|
-
path:
|
|
5765
|
+
recordCreatedDirectory(path19, publicPath) {
|
|
5766
|
+
this.context.createdDirectories.set(path19, {
|
|
5767
|
+
path: path19,
|
|
4977
5768
|
publicPaths: /* @__PURE__ */ new Set([publicPath]),
|
|
4978
5769
|
exists: true
|
|
4979
5770
|
});
|
|
4980
5771
|
this.context.ownershipChanged();
|
|
4981
5772
|
}
|
|
4982
|
-
recordUnconfirmedEntry(
|
|
4983
|
-
const publicPaths = this.context.unconfirmedEntries.get(
|
|
5773
|
+
recordUnconfirmedEntry(path19, publicPath) {
|
|
5774
|
+
const publicPaths = this.context.unconfirmedEntries.get(path19) ?? /* @__PURE__ */ new Set();
|
|
4984
5775
|
publicPaths.add(publicPath);
|
|
4985
|
-
this.context.unconfirmedEntries.set(
|
|
5776
|
+
this.context.unconfirmedEntries.set(path19, publicPaths);
|
|
4986
5777
|
}
|
|
4987
5778
|
unconfirmedEntryViews() {
|
|
4988
5779
|
return Object.freeze(
|
|
4989
5780
|
[...this.context.unconfirmedEntries].map(
|
|
4990
|
-
([
|
|
5781
|
+
([path19, publicPaths]) => Object.freeze({ path: path19, publicPaths: Object.freeze([...publicPaths]) })
|
|
4991
5782
|
)
|
|
4992
5783
|
);
|
|
4993
5784
|
}
|
|
@@ -5019,18 +5810,18 @@ var TransactionUnitSession = class {
|
|
|
5019
5810
|
[item.artifact.path]
|
|
5020
5811
|
);
|
|
5021
5812
|
}
|
|
5022
|
-
const beforeIdentity =
|
|
5813
|
+
const beforeIdentity = identity2(before);
|
|
5023
5814
|
const handle = await this.operations.open(item.artifact.path, "r");
|
|
5024
5815
|
const contents = await this.readThroughHandle(item, handle, async () => {
|
|
5025
|
-
const handleBefore =
|
|
5026
|
-
if (!
|
|
5816
|
+
const handleBefore = identity2(await handle.stat());
|
|
5817
|
+
if (!sameIdentity2(beforeIdentity, handleBefore)) throw this.concurrentModification(item.artifact.path);
|
|
5027
5818
|
const read = await handle.readFile({ encoding: "utf8" });
|
|
5028
|
-
const handleAfter =
|
|
5029
|
-
if (!
|
|
5819
|
+
const handleAfter = identity2(await handle.stat());
|
|
5820
|
+
if (!sameIdentity2(handleBefore, handleAfter)) throw this.concurrentModification(item.artifact.path);
|
|
5030
5821
|
return read;
|
|
5031
5822
|
});
|
|
5032
5823
|
const after = await this.lstatOrAbsent(item.artifact.path);
|
|
5033
|
-
if (after === "absent" || after.isSymbolicLink() || !after.isFile() || !
|
|
5824
|
+
if (after === "absent" || after.isSymbolicLink() || !after.isFile() || !sameIdentity2(beforeIdentity, identity2(after))) {
|
|
5034
5825
|
throw this.concurrentModification(item.artifact.path);
|
|
5035
5826
|
}
|
|
5036
5827
|
await this.assertParentChain(item, context);
|
|
@@ -5041,11 +5832,11 @@ var TransactionUnitSession = class {
|
|
|
5041
5832
|
const expected = required(owned.identity);
|
|
5042
5833
|
const handle = await this.operations.open(owned.path, "r");
|
|
5043
5834
|
const contents = await this.readThroughHandle(item, handle, async () => {
|
|
5044
|
-
const before =
|
|
5045
|
-
if (!
|
|
5835
|
+
const before = identity2(await handle.stat());
|
|
5836
|
+
if (!sameIdentity2(before, expected)) throw this.ownershipFailure(owned.publicPath);
|
|
5046
5837
|
const read = await handle.readFile({ encoding: "utf8" });
|
|
5047
|
-
const after =
|
|
5048
|
-
if (!
|
|
5838
|
+
const after = identity2(await handle.stat());
|
|
5839
|
+
if (!sameIdentity2(after, expected)) throw this.ownershipFailure(owned.publicPath);
|
|
5049
5840
|
return read;
|
|
5050
5841
|
});
|
|
5051
5842
|
await this.assertOwnedIdentity(item, owned);
|
|
@@ -5104,7 +5895,7 @@ var TransactionUnitSession = class {
|
|
|
5104
5895
|
await this.assertNamespace(item);
|
|
5105
5896
|
if (!owned.identity) throw this.ownershipFailure(owned.publicPath);
|
|
5106
5897
|
const ownedStat = await this.operations.lstat(owned.path);
|
|
5107
|
-
if (ownedStat.isSymbolicLink() || !ownedStat.isFile() || !
|
|
5898
|
+
if (ownedStat.isSymbolicLink() || !ownedStat.isFile() || !sameIdentity2(identity2(ownedStat), owned.identity)) {
|
|
5108
5899
|
throw this.ownershipFailure(owned.publicPath);
|
|
5109
5900
|
}
|
|
5110
5901
|
await this.assertNamespace(item);
|
|
@@ -5113,7 +5904,7 @@ var TransactionUnitSession = class {
|
|
|
5113
5904
|
const namespace = required(item.namespace);
|
|
5114
5905
|
const expectedIdentity = required(namespace.identity);
|
|
5115
5906
|
const namespaceStat = await this.operations.lstat(namespace.path);
|
|
5116
|
-
if (namespaceStat.isSymbolicLink() || !namespaceStat.isDirectory() || !
|
|
5907
|
+
if (namespaceStat.isSymbolicLink() || !namespaceStat.isDirectory() || !sameIdentity2(identity2(namespaceStat), expectedIdentity)) {
|
|
5117
5908
|
throw this.ownershipFailure(namespace.publicPath);
|
|
5118
5909
|
}
|
|
5119
5910
|
}
|
|
@@ -5132,54 +5923,54 @@ var TransactionUnitSession = class {
|
|
|
5132
5923
|
}
|
|
5133
5924
|
await this.assertDirectoryExpectation(expectation.path, expectation.original, item.artifact.path);
|
|
5134
5925
|
}
|
|
5135
|
-
async assertDirectoryExpectation(
|
|
5926
|
+
async assertDirectoryExpectation(path19, expected, publicPath) {
|
|
5136
5927
|
let pathStat;
|
|
5137
5928
|
try {
|
|
5138
|
-
pathStat = await this.operations.lstat(
|
|
5929
|
+
pathStat = await this.operations.lstat(path19);
|
|
5139
5930
|
} catch (error) {
|
|
5140
5931
|
throw this.concurrentModification(publicPath, error);
|
|
5141
5932
|
}
|
|
5142
5933
|
const kind = pathStat.isSymbolicLink() ? "symbolic-link" : pathStat.isDirectory() ? "directory" : void 0;
|
|
5143
|
-
if (kind !== expected.kind || !
|
|
5934
|
+
if (kind !== expected.kind || !sameIdentity2(identity2(pathStat), expected.identity)) {
|
|
5144
5935
|
throw this.concurrentModification(publicPath);
|
|
5145
5936
|
}
|
|
5146
5937
|
if (expected.kind === "symbolic-link") {
|
|
5147
5938
|
let followed;
|
|
5148
5939
|
try {
|
|
5149
|
-
followed = await this.operations.stat(
|
|
5940
|
+
followed = await this.operations.stat(path19);
|
|
5150
5941
|
} catch (error) {
|
|
5151
5942
|
throw this.concurrentModification(publicPath, error);
|
|
5152
5943
|
}
|
|
5153
|
-
if (!followed.isDirectory() || !
|
|
5944
|
+
if (!followed.isDirectory() || !sameIdentity2(identity2(followed), expected.followedIdentity)) {
|
|
5154
5945
|
throw this.concurrentModification(publicPath);
|
|
5155
5946
|
}
|
|
5156
5947
|
}
|
|
5157
5948
|
}
|
|
5158
|
-
async assertDirectoryIdentity(
|
|
5949
|
+
async assertDirectoryIdentity(path19, expected, publicPath) {
|
|
5159
5950
|
let pathStat;
|
|
5160
5951
|
try {
|
|
5161
|
-
pathStat = await this.operations.lstat(
|
|
5952
|
+
pathStat = await this.operations.lstat(path19);
|
|
5162
5953
|
} catch (error) {
|
|
5163
5954
|
throw this.concurrentModification(publicPath, error);
|
|
5164
5955
|
}
|
|
5165
|
-
if (pathStat.isSymbolicLink() || !pathStat.isDirectory() || !
|
|
5956
|
+
if (pathStat.isSymbolicLink() || !pathStat.isDirectory() || !sameIdentity2(identity2(pathStat), expected)) {
|
|
5166
5957
|
throw this.concurrentModification(publicPath);
|
|
5167
5958
|
}
|
|
5168
5959
|
}
|
|
5169
|
-
async assertExpectedAbsent(
|
|
5960
|
+
async assertExpectedAbsent(path19, publicPath) {
|
|
5170
5961
|
try {
|
|
5171
|
-
await this.operations.lstat(
|
|
5962
|
+
await this.operations.lstat(path19);
|
|
5172
5963
|
} catch (error) {
|
|
5173
|
-
if (
|
|
5964
|
+
if (isEnoent2(error)) return;
|
|
5174
5965
|
throw error;
|
|
5175
5966
|
}
|
|
5176
5967
|
throw this.concurrentModification(publicPath);
|
|
5177
5968
|
}
|
|
5178
|
-
async lstatOrAbsent(
|
|
5969
|
+
async lstatOrAbsent(path19) {
|
|
5179
5970
|
try {
|
|
5180
|
-
return await this.operations.lstat(
|
|
5971
|
+
return await this.operations.lstat(path19);
|
|
5181
5972
|
} catch (error) {
|
|
5182
|
-
if (
|
|
5973
|
+
if (isEnoent2(error)) return "absent";
|
|
5183
5974
|
throw error;
|
|
5184
5975
|
}
|
|
5185
5976
|
}
|
|
@@ -5213,9 +6004,9 @@ var TransactionUnitSession = class {
|
|
|
5213
6004
|
);
|
|
5214
6005
|
}
|
|
5215
6006
|
};
|
|
5216
|
-
function directoryChain(
|
|
6007
|
+
function directoryChain(path19) {
|
|
5217
6008
|
const result2 = [];
|
|
5218
|
-
let current = resolve3(
|
|
6009
|
+
let current = resolve3(path19);
|
|
5219
6010
|
while (true) {
|
|
5220
6011
|
result2.unshift(current);
|
|
5221
6012
|
const parent = dirname2(current);
|
|
@@ -5402,7 +6193,7 @@ var MigrationTransaction = class {
|
|
|
5402
6193
|
}
|
|
5403
6194
|
}
|
|
5404
6195
|
rejectParseErrors(plan) {
|
|
5405
|
-
const paths = plan.files.flatMap((file) => file.results.filter((result2) => result2.status === "parse-error").map((result2) => result2.fileName)).filter((
|
|
6196
|
+
const paths = plan.files.flatMap((file) => file.results.filter((result2) => result2.status === "parse-error").map((result2) => result2.fileName)).filter((path19, index, all) => all.indexOf(path19) === index).sort(compareCodeUnits);
|
|
5406
6197
|
if (paths.length === 0) return;
|
|
5407
6198
|
throw new MigrationApplicationError(
|
|
5408
6199
|
"internal-invariant",
|
|
@@ -5521,6 +6312,13 @@ var ApplyProjectStage = class {
|
|
|
5521
6312
|
);
|
|
5522
6313
|
}
|
|
5523
6314
|
const plan = validated.plan;
|
|
6315
|
+
const snapshots = validated.rendered.analyzed.manifest.invocation.options.configurationSnapshots ?? [];
|
|
6316
|
+
await assertConfigurationUnchanged(snapshots);
|
|
6317
|
+
for (const artifact of plan.artifacts)
|
|
6318
|
+
for (const snapshot of snapshots) {
|
|
6319
|
+
if (await pathsOverlapOnFileSystem(artifact.path, snapshot.path))
|
|
6320
|
+
throw new Error(`Migration output collides with target configuration: ${artifact.path}`);
|
|
6321
|
+
}
|
|
5524
6322
|
const hasParseError = plan.files.some((file) => file.results.some((result2) => result2.status === "parse-error"));
|
|
5525
6323
|
if (this.mode === "plan") {
|
|
5526
6324
|
if (!hasParseError) await this.transaction.preflight(plan);
|
|
@@ -5530,27 +6328,28 @@ var ApplyProjectStage = class {
|
|
|
5530
6328
|
return appliedProject({ validated, application: { status: "skipped", reason: "parse-errors" } });
|
|
5531
6329
|
}
|
|
5532
6330
|
await this.transaction.preflight(plan);
|
|
6331
|
+
await assertConfigurationUnchanged(snapshots);
|
|
5533
6332
|
if (plan.artifacts.length > 0) await this.transaction.apply(plan);
|
|
5534
6333
|
return appliedProject({ validated, application: { status: "applied" } });
|
|
5535
6334
|
}
|
|
5536
6335
|
};
|
|
5537
6336
|
|
|
5538
6337
|
// src/pipeline/discover/discover-project.stage.ts
|
|
5539
|
-
import { readdir, stat as
|
|
5540
|
-
import * as
|
|
6338
|
+
import { readdir, stat as stat3 } from "fs/promises";
|
|
6339
|
+
import * as path6 from "path";
|
|
5541
6340
|
|
|
5542
6341
|
// src/lib/gitignore.helper.ts
|
|
5543
6342
|
import fs from "fs-extra";
|
|
5544
6343
|
import ignore from "ignore";
|
|
5545
|
-
import
|
|
6344
|
+
import path5 from "path";
|
|
5546
6345
|
async function createGitIgnoreMatcher(root, displayRoot = root) {
|
|
5547
6346
|
const matcher = ignore();
|
|
5548
|
-
const gitignorePath =
|
|
6347
|
+
const gitignorePath = path5.join(root, ".gitignore");
|
|
5549
6348
|
if (await fs.pathExists(gitignorePath)) {
|
|
5550
6349
|
matcher.add(await fs.readFile(gitignorePath, "utf8"));
|
|
5551
|
-
logger.debug(`Loaded .gitignore file from ${
|
|
6350
|
+
logger.debug(`Loaded .gitignore file from ${path5.join(displayRoot, ".gitignore")}`);
|
|
5552
6351
|
}
|
|
5553
|
-
const relativeIgnorePath = (candidate) =>
|
|
6352
|
+
const relativeIgnorePath = (candidate) => path5.relative(root, candidate).split(path5.sep).join("/");
|
|
5554
6353
|
return Object.freeze({
|
|
5555
6354
|
ignores: (candidate) => matcher.ignores(relativeIgnorePath(candidate)),
|
|
5556
6355
|
ignoresDirectory: (candidate) => matcher.ignores(`${relativeIgnorePath(candidate)}/`)
|
|
@@ -5560,7 +6359,7 @@ async function createGitIgnoreMatcher(root, displayRoot = root) {
|
|
|
5560
6359
|
// src/pipeline/discover/discover-project.stage.ts
|
|
5561
6360
|
var nodeFileSystem = Object.freeze({
|
|
5562
6361
|
async kind(candidate) {
|
|
5563
|
-
const candidateStat = await
|
|
6362
|
+
const candidateStat = await stat3(candidate);
|
|
5564
6363
|
if (candidateStat.isFile()) return "file";
|
|
5565
6364
|
if (candidateStat.isDirectory()) return "directory";
|
|
5566
6365
|
return "other";
|
|
@@ -5595,10 +6394,10 @@ var DiscoverProjectStage = class {
|
|
|
5595
6394
|
return projectManifest({ invocation, templates });
|
|
5596
6395
|
}
|
|
5597
6396
|
singleFile(invocation) {
|
|
5598
|
-
if (
|
|
6397
|
+
if (path6.extname(invocation.canonicalInputPath).toLowerCase() !== ".html") {
|
|
5599
6398
|
throw new Error(`Unsupported file type: ${invocation.inputPath}`);
|
|
5600
6399
|
}
|
|
5601
|
-
if (
|
|
6400
|
+
if (path6.extname(invocation.canonicalOutputPath).toLowerCase() !== ".html") {
|
|
5602
6401
|
throw new Error("Single-file output path must have a .html extension.");
|
|
5603
6402
|
}
|
|
5604
6403
|
return [{ inputPath: invocation.canonicalInputPath, outputPath: invocation.canonicalOutputPath }];
|
|
@@ -5611,7 +6410,7 @@ var DiscoverProjectStage = class {
|
|
|
5611
6410
|
inputs.sort(compareCodeUnits);
|
|
5612
6411
|
return inputs.map((inputPath) => ({
|
|
5613
6412
|
inputPath,
|
|
5614
|
-
outputPath:
|
|
6413
|
+
outputPath: path6.join(invocation.canonicalOutputPath, path6.relative(root, inputPath))
|
|
5615
6414
|
}));
|
|
5616
6415
|
}
|
|
5617
6416
|
async collectInputs(directory, displayDirectory, matcher, exclusions) {
|
|
@@ -5620,30 +6419,30 @@ var DiscoverProjectStage = class {
|
|
|
5620
6419
|
);
|
|
5621
6420
|
const inputs = [];
|
|
5622
6421
|
for (const entry of entries) {
|
|
5623
|
-
const candidate =
|
|
5624
|
-
const displayCandidate =
|
|
6422
|
+
const candidate = path6.join(directory, entry.name);
|
|
6423
|
+
const displayCandidate = path6.join(displayDirectory, entry.name);
|
|
5625
6424
|
logger.debug(`Processing ${displayCandidate}`);
|
|
5626
6425
|
const ignored = entry.kind === "directory" ? matcher.ignoresDirectory(candidate) : matcher.ignores(candidate);
|
|
5627
|
-
if (ignored || exclusions.has(
|
|
6426
|
+
if (ignored || exclusions.has(path6.normalize(candidate))) continue;
|
|
5628
6427
|
const kind = entry.kind === "other" ? await this.fileSystem.kind(candidate) : entry.kind;
|
|
5629
6428
|
if (entry.kind === "other" && kind === "directory" && matcher.ignoresDirectory(candidate)) continue;
|
|
5630
6429
|
if (kind === "directory") {
|
|
5631
6430
|
inputs.push(...await this.collectInputs(candidate, displayCandidate, matcher, exclusions));
|
|
5632
|
-
} else if (kind === "file" &&
|
|
5633
|
-
inputs.push(
|
|
6431
|
+
} else if (kind === "file" && path6.extname(entry.name).toLowerCase() === ".html") {
|
|
6432
|
+
inputs.push(path6.normalize(path6.resolve(candidate)));
|
|
5634
6433
|
}
|
|
5635
6434
|
}
|
|
5636
6435
|
return inputs;
|
|
5637
6436
|
}
|
|
5638
6437
|
excludedPaths(invocation) {
|
|
5639
|
-
const candidates = [invocation.options.stylesheetPath, invocation.options.reportPath].filter((candidate) => candidate !== void 0).map((candidate) =>
|
|
6438
|
+
const candidates = [invocation.options.stylesheetPath, invocation.options.reportPath].filter((candidate) => candidate !== void 0).map((candidate) => path6.normalize(path6.resolve(candidate)));
|
|
5640
6439
|
const outputRoot = invocation.canonicalOutputPath;
|
|
5641
|
-
if (
|
|
6440
|
+
if (path6.relative(invocation.canonicalInputPath, outputRoot) !== "") candidates.push(outputRoot);
|
|
5642
6441
|
return new Set(candidates);
|
|
5643
6442
|
}
|
|
5644
6443
|
};
|
|
5645
6444
|
function preserveTrailingSeparator(canonicalPath, rawPath) {
|
|
5646
|
-
return /[\\/]$/u.test(rawPath) && !/[\\/]$/u.test(canonicalPath) ? `${canonicalPath}${
|
|
6445
|
+
return /[\\/]$/u.test(rawPath) && !/[\\/]$/u.test(canonicalPath) ? `${canonicalPath}${path6.sep}` : canonicalPath;
|
|
5647
6446
|
}
|
|
5648
6447
|
|
|
5649
6448
|
// src/pipeline/pipeline-stage.error.ts
|
|
@@ -5685,7 +6484,7 @@ async function runStage(stage, action) {
|
|
|
5685
6484
|
}
|
|
5686
6485
|
|
|
5687
6486
|
// src/report/migration-report.builder.ts
|
|
5688
|
-
import
|
|
6487
|
+
import path7 from "path";
|
|
5689
6488
|
var MigrationReportBuilder = class {
|
|
5690
6489
|
build(inputRoot, outputRoot, target, mode, application, durationMs, files, stylesheet) {
|
|
5691
6490
|
const pathApi = this.pathApi(
|
|
@@ -5719,9 +6518,9 @@ var MigrationReportBuilder = class {
|
|
|
5719
6518
|
return { path: this.forwardSlashes(pathApi, displayPath), change: stylesheet.change };
|
|
5720
6519
|
}
|
|
5721
6520
|
pathApi(...values) {
|
|
5722
|
-
if (values.some((value) => /^[A-Za-z]:[\\/]/.test(value) || value.includes("\\"))) return
|
|
5723
|
-
if (values.some((value) => value.includes("/"))) return
|
|
5724
|
-
return
|
|
6521
|
+
if (values.some((value) => /^[A-Za-z]:[\\/]/.test(value) || value.includes("\\"))) return path7.win32;
|
|
6522
|
+
if (values.some((value) => value.includes("/"))) return path7.posix;
|
|
6523
|
+
return path7;
|
|
5725
6524
|
}
|
|
5726
6525
|
samePath(pathApi, left, right) {
|
|
5727
6526
|
return this.absolutePath(pathApi, left) === this.absolutePath(pathApi, right);
|
|
@@ -5798,9 +6597,16 @@ var MigrationReportBuilder = class {
|
|
|
5798
6597
|
};
|
|
5799
6598
|
}
|
|
5800
6599
|
};
|
|
6600
|
+
function withReportEnvironment(report, options) {
|
|
6601
|
+
return {
|
|
6602
|
+
...report,
|
|
6603
|
+
...options.targetProfile ? { targetProfile: options.targetProfile } : {},
|
|
6604
|
+
...options.sourceBreakpoints ? { sourceBreakpoints: options.sourceBreakpoints } : {}
|
|
6605
|
+
};
|
|
6606
|
+
}
|
|
5801
6607
|
|
|
5802
6608
|
// src/pipeline/invocation-error-path.mapper.ts
|
|
5803
|
-
import * as
|
|
6609
|
+
import * as path8 from "path";
|
|
5804
6610
|
function remapInvocationErrorPaths(error, invocation) {
|
|
5805
6611
|
if (!(error instanceof Error)) return error;
|
|
5806
6612
|
const roots = invocationRoots(invocation);
|
|
@@ -5824,12 +6630,12 @@ function remapErrorPath(error, field, roots) {
|
|
|
5824
6630
|
error[field] = mapped;
|
|
5825
6631
|
}
|
|
5826
6632
|
function mappedInvocationPath(candidate, roots) {
|
|
5827
|
-
if (!
|
|
6633
|
+
if (!path8.isAbsolute(candidate)) return candidate;
|
|
5828
6634
|
for (const root of roots) {
|
|
5829
|
-
const relativePath =
|
|
6635
|
+
const relativePath = path8.relative(root.canonical, candidate);
|
|
5830
6636
|
if (relativePath === "") return root.raw;
|
|
5831
|
-
if (relativePath === ".." || relativePath.startsWith(`..${
|
|
5832
|
-
return
|
|
6637
|
+
if (relativePath === ".." || relativePath.startsWith(`..${path8.sep}`) || path8.isAbsolute(relativePath)) continue;
|
|
6638
|
+
return path8.join(root.raw, relativePath);
|
|
5833
6639
|
}
|
|
5834
6640
|
return candidate;
|
|
5835
6641
|
}
|
|
@@ -5847,7 +6653,7 @@ var MigrationRunner = class {
|
|
|
5847
6653
|
const durationMs = this.now() - startedAt;
|
|
5848
6654
|
const { validated, application } = applied;
|
|
5849
6655
|
const { plan, rendered, stylesheet } = validated;
|
|
5850
|
-
|
|
6656
|
+
const report = this.reports.build(
|
|
5851
6657
|
rendered.analyzed.manifest.invocation.inputPath,
|
|
5852
6658
|
rendered.analyzed.manifest.invocation.outputPath,
|
|
5853
6659
|
plan.target,
|
|
@@ -5857,6 +6663,7 @@ var MigrationRunner = class {
|
|
|
5857
6663
|
plan.files,
|
|
5858
6664
|
stylesheet
|
|
5859
6665
|
);
|
|
6666
|
+
return withReportEnvironment(report, invocation.options);
|
|
5860
6667
|
}
|
|
5861
6668
|
async execute(invocation) {
|
|
5862
6669
|
try {
|
|
@@ -8899,7 +9706,7 @@ var ConversionPlanner = class {
|
|
|
8899
9706
|
};
|
|
8900
9707
|
|
|
8901
9708
|
// src/pipeline/rendered-project.ts
|
|
8902
|
-
import * as
|
|
9709
|
+
import * as path9 from "path";
|
|
8903
9710
|
function renderedProject(project) {
|
|
8904
9711
|
const analyzed = analyzedProject(project.analyzed);
|
|
8905
9712
|
if (project.files.length !== analyzed.templates.length) throw sequenceInvariant2();
|
|
@@ -9026,7 +9833,7 @@ function samePathPair2(left, right) {
|
|
|
9026
9833
|
return normalizedAbsolutePath3(left.inputPath) === normalizedAbsolutePath3(right.inputPath) && normalizedAbsolutePath3(left.outputPath) === normalizedAbsolutePath3(right.outputPath);
|
|
9027
9834
|
}
|
|
9028
9835
|
function normalizedAbsolutePath3(value) {
|
|
9029
|
-
return
|
|
9836
|
+
return path9.normalize(path9.resolve(value));
|
|
9030
9837
|
}
|
|
9031
9838
|
function sameOwnedValue(left, right) {
|
|
9032
9839
|
if (Object.is(left, right)) return true;
|
|
@@ -9115,10 +9922,10 @@ function parseErrorPlan(template) {
|
|
|
9115
9922
|
}
|
|
9116
9923
|
|
|
9117
9924
|
// src/pipeline/validate/validate-project.stage.ts
|
|
9118
|
-
import * as
|
|
9925
|
+
import * as path15 from "path";
|
|
9119
9926
|
|
|
9120
9927
|
// src/migrator/migration-plan.ts
|
|
9121
|
-
import * as
|
|
9928
|
+
import * as path10 from "path";
|
|
9122
9929
|
|
|
9123
9930
|
// src/migrator/file-migration-result.ts
|
|
9124
9931
|
function fileMigrationResult(result2) {
|
|
@@ -9141,7 +9948,7 @@ function freezeValue2(value) {
|
|
|
9141
9948
|
|
|
9142
9949
|
// src/migrator/migration-plan.ts
|
|
9143
9950
|
function plannedOutputArtifact(artifact) {
|
|
9144
|
-
if (!
|
|
9951
|
+
if (!path10.isAbsolute(artifact.path)) {
|
|
9145
9952
|
throw new Error(`Planned artifact paths must be absolute: ${artifact.path}`);
|
|
9146
9953
|
}
|
|
9147
9954
|
if (artifact.kind === "template" && artifact.proposed.status === "absent") {
|
|
@@ -9152,7 +9959,7 @@ function plannedOutputArtifact(artifact) {
|
|
|
9152
9959
|
}
|
|
9153
9960
|
return Object.freeze({
|
|
9154
9961
|
kind: artifact.kind,
|
|
9155
|
-
path:
|
|
9962
|
+
path: path10.resolve(artifact.path),
|
|
9156
9963
|
original: artifactState(artifact.original),
|
|
9157
9964
|
proposed: artifactState(artifact.proposed)
|
|
9158
9965
|
});
|
|
@@ -9179,216 +9986,9 @@ function sameState(left, right) {
|
|
|
9179
9986
|
return right.status === "present" && left.contents === right.contents;
|
|
9180
9987
|
}
|
|
9181
9988
|
|
|
9182
|
-
// src/migrator/migration-path.validator.ts
|
|
9183
|
-
import { lstat as lstat2, stat as stat3 } from "fs/promises";
|
|
9184
|
-
import * as path9 from "path";
|
|
9185
|
-
async function validateMigrationPaths(request, pathApi = path9) {
|
|
9186
|
-
const claims = normalizedClaims(request, pathApi);
|
|
9187
|
-
await validateCollisions(claims, pathApi);
|
|
9188
|
-
const destinations = claims.filter((claim) => claim.kind !== "template-input");
|
|
9189
|
-
for (const destination of destinations) {
|
|
9190
|
-
await validateDestination(destination.path);
|
|
9191
|
-
}
|
|
9192
|
-
}
|
|
9193
|
-
async function validateStylesheetRootTopology(request, pathApi = path9) {
|
|
9194
|
-
if (request.stylesheetPath === void 0) return;
|
|
9195
|
-
const stylesheetPath = pathApi.resolve(request.stylesheetPath);
|
|
9196
|
-
const templateRoots = [request.inputPath, request.outputPath].map((claim) => pathApi.resolve(claim));
|
|
9197
|
-
const reportPath = request.reportPath === void 0 ? void 0 : pathApi.resolve(request.reportPath);
|
|
9198
|
-
const exactCollision = (await Promise.all(
|
|
9199
|
-
[...templateRoots, reportPath].map(
|
|
9200
|
-
(claim) => claim === void 0 ? Promise.resolve(false) : pathsEquivalentOnFileSystem(stylesheetPath, claim, pathApi)
|
|
9201
|
-
)
|
|
9202
|
-
)).some(Boolean);
|
|
9203
|
-
const reportHierarchyCollision = reportPath !== void 0 && await pathsOverlapOnFileSystem(stylesheetPath, reportPath, pathApi);
|
|
9204
|
-
if (exactCollision || reportHierarchyCollision) {
|
|
9205
|
-
const collisionPaths = reportHierarchyCollision && reportPath !== void 0 && !await pathsEquivalentOnFileSystem(stylesheetPath, reportPath, pathApi) ? [stylesheetPath, reportPath] : [stylesheetPath];
|
|
9206
|
-
throw new MigrationApplicationError(
|
|
9207
|
-
"path-collision",
|
|
9208
|
-
`Stylesheet path collides with another migration path: ${request.stylesheetPathInput ?? request.stylesheetPath}`,
|
|
9209
|
-
collisionPaths
|
|
9210
|
-
);
|
|
9211
|
-
}
|
|
9212
|
-
let stylesheetStat;
|
|
9213
|
-
try {
|
|
9214
|
-
stylesheetStat = await lstat2(stylesheetPath);
|
|
9215
|
-
} catch (error) {
|
|
9216
|
-
if (isEnoent2(error)) return;
|
|
9217
|
-
throw error;
|
|
9218
|
-
}
|
|
9219
|
-
const sourcePath = request.stylesheetPathInput ?? request.stylesheetPath;
|
|
9220
|
-
if (stylesheetStat.isSymbolicLink()) {
|
|
9221
|
-
throw new MigrationApplicationError(
|
|
9222
|
-
"unsupported-path-type",
|
|
9223
|
-
`Stylesheet path must not be a symbolic link: ${sourcePath}`,
|
|
9224
|
-
[stylesheetPath]
|
|
9225
|
-
);
|
|
9226
|
-
}
|
|
9227
|
-
if (!stylesheetStat.isFile()) {
|
|
9228
|
-
throw new MigrationApplicationError(
|
|
9229
|
-
"unsupported-path-type",
|
|
9230
|
-
`Stylesheet path must be a regular file: ${sourcePath}`,
|
|
9231
|
-
[stylesheetPath]
|
|
9232
|
-
);
|
|
9233
|
-
}
|
|
9234
|
-
}
|
|
9235
|
-
function normalizedClaims(request, pathApi) {
|
|
9236
|
-
return [
|
|
9237
|
-
...request.templates.flatMap((template, templateIndex) => [
|
|
9238
|
-
{ path: pathApi.resolve(template.inputPath), kind: "template-input", templateIndex },
|
|
9239
|
-
{ path: pathApi.resolve(template.outputPath), kind: "template-output", templateIndex }
|
|
9240
|
-
]),
|
|
9241
|
-
...request.stylesheetPath ? [{ path: pathApi.resolve(request.stylesheetPath), kind: "stylesheet" }] : [],
|
|
9242
|
-
...request.reportPath ? [{ path: pathApi.resolve(request.reportPath), kind: "report" }] : []
|
|
9243
|
-
];
|
|
9244
|
-
}
|
|
9245
|
-
async function validateCollisions(claims, pathApi) {
|
|
9246
|
-
const observations = /* @__PURE__ */ new Map();
|
|
9247
|
-
const observe = (candidate) => {
|
|
9248
|
-
const normalized = pathApi.resolve(candidate);
|
|
9249
|
-
const existing = observations.get(normalized);
|
|
9250
|
-
if (existing) return existing;
|
|
9251
|
-
const pending = observePath(normalized, pathApi);
|
|
9252
|
-
observations.set(normalized, pending);
|
|
9253
|
-
return pending;
|
|
9254
|
-
};
|
|
9255
|
-
for (let leftIndex = 0; leftIndex < claims.length; leftIndex++) {
|
|
9256
|
-
const left = claims[leftIndex];
|
|
9257
|
-
if (!left) continue;
|
|
9258
|
-
for (let rightIndex = leftIndex + 1; rightIndex < claims.length; rightIndex++) {
|
|
9259
|
-
const right = claims[rightIndex];
|
|
9260
|
-
if (!right) continue;
|
|
9261
|
-
const relationship = await fileSystemPathRelationship(left.path, right.path, pathApi, observe);
|
|
9262
|
-
if (relationship === "distinct" || isIntentionalInPlacePair(left, right, pathApi)) continue;
|
|
9263
|
-
const collisionPaths = relationship === "equivalent" ? [left.path] : [left.path, right.path];
|
|
9264
|
-
throw new MigrationApplicationError(
|
|
9265
|
-
"path-collision",
|
|
9266
|
-
`Migration paths collide: ${collisionPaths.join(" and ")}`,
|
|
9267
|
-
collisionPaths
|
|
9268
|
-
);
|
|
9269
|
-
}
|
|
9270
|
-
}
|
|
9271
|
-
}
|
|
9272
|
-
function isIntentionalInPlacePair(left, right, pathApi) {
|
|
9273
|
-
return pathsEquivalent(left.path, right.path, pathApi) && left.templateIndex !== void 0 && left.templateIndex === right.templateIndex && left.kind !== right.kind && left.kind.startsWith("template-") && right.kind.startsWith("template-");
|
|
9274
|
-
}
|
|
9275
|
-
function pathsEquivalent(left, right, pathApi = path9) {
|
|
9276
|
-
return normalizedPathsEquivalent(pathApi, pathApi.resolve(left), pathApi.resolve(right));
|
|
9277
|
-
}
|
|
9278
|
-
async function pathsEquivalentOnFileSystem(left, right, pathApi = path9) {
|
|
9279
|
-
return await fileSystemPathRelationship(left, right, pathApi) === "equivalent";
|
|
9280
|
-
}
|
|
9281
|
-
async function pathsOverlapOnFileSystem(left, right, pathApi = path9) {
|
|
9282
|
-
return await fileSystemPathRelationship(left, right, pathApi) !== "distinct";
|
|
9283
|
-
}
|
|
9284
|
-
function normalizedPathsEquivalent(pathApi, left, right) {
|
|
9285
|
-
return pathApi.relative(left, right) === "";
|
|
9286
|
-
}
|
|
9287
|
-
function isAncestor(pathApi, ancestor, descendant) {
|
|
9288
|
-
const relative3 = pathApi.relative(ancestor, descendant);
|
|
9289
|
-
return relative3 !== "" && relative3 !== ".." && !relative3.startsWith(`..${pathApi.sep}`) && !pathApi.isAbsolute(relative3);
|
|
9290
|
-
}
|
|
9291
|
-
async function fileSystemPathRelationship(left, right, pathApi, observe = (candidate) => observePath(candidate, pathApi)) {
|
|
9292
|
-
const normalizedLeft = pathApi.resolve(left);
|
|
9293
|
-
const normalizedRight = pathApi.resolve(right);
|
|
9294
|
-
if (normalizedPathsEquivalent(pathApi, normalizedLeft, normalizedRight)) return "equivalent";
|
|
9295
|
-
if (isAncestor(pathApi, normalizedLeft, normalizedRight)) return "ancestor";
|
|
9296
|
-
if (isAncestor(pathApi, normalizedRight, normalizedLeft)) return "descendant";
|
|
9297
|
-
const [observedLeft, observedRight] = await Promise.all([observe(normalizedLeft), observe(normalizedRight)]);
|
|
9298
|
-
if (observedLeft.exactIdentity && observedRight.exactIdentity) {
|
|
9299
|
-
if (sameIdentity2(observedLeft.exactIdentity, observedRight.exactIdentity)) return "equivalent";
|
|
9300
|
-
if (hasIdentityBelow(observedRight, observedLeft.exactIdentity)) return "ancestor";
|
|
9301
|
-
if (hasIdentityBelow(observedLeft, observedRight.exactIdentity)) return "descendant";
|
|
9302
|
-
return "distinct";
|
|
9303
|
-
}
|
|
9304
|
-
return relationshipThroughExistingPrefixes(observedLeft, observedRight);
|
|
9305
|
-
}
|
|
9306
|
-
async function observePath(candidate, pathApi) {
|
|
9307
|
-
const prefixes = [];
|
|
9308
|
-
const suffix = [];
|
|
9309
|
-
let current = candidate;
|
|
9310
|
-
let exactIdentity;
|
|
9311
|
-
while (true) {
|
|
9312
|
-
try {
|
|
9313
|
-
const currentStat = await stat3(current, { bigint: true });
|
|
9314
|
-
const currentIdentity = identity2(currentStat);
|
|
9315
|
-
if (suffix.length === 0) exactIdentity = currentIdentity;
|
|
9316
|
-
prefixes.push({ identity: currentIdentity, suffix: [...suffix] });
|
|
9317
|
-
} catch (error) {
|
|
9318
|
-
if (!isMissingPath(error)) throw error;
|
|
9319
|
-
}
|
|
9320
|
-
const parent = pathApi.dirname(current);
|
|
9321
|
-
if (parent === current) break;
|
|
9322
|
-
suffix.unshift(pathApi.basename(current));
|
|
9323
|
-
current = parent;
|
|
9324
|
-
}
|
|
9325
|
-
return { ...exactIdentity ? { exactIdentity } : {}, prefixes };
|
|
9326
|
-
}
|
|
9327
|
-
function relationshipThroughExistingPrefixes(left, right) {
|
|
9328
|
-
for (const leftPrefix of left.prefixes) {
|
|
9329
|
-
for (const rightPrefix of right.prefixes) {
|
|
9330
|
-
if (!sameIdentity2(leftPrefix.identity, rightPrefix.identity)) continue;
|
|
9331
|
-
const relationship = suffixRelationship(leftPrefix.suffix, rightPrefix.suffix);
|
|
9332
|
-
if (relationship !== "distinct") return relationship;
|
|
9333
|
-
}
|
|
9334
|
-
}
|
|
9335
|
-
return "distinct";
|
|
9336
|
-
}
|
|
9337
|
-
function hasIdentityBelow(observed, candidate) {
|
|
9338
|
-
return observed.prefixes.some((prefix) => prefix.suffix.length > 0 && sameIdentity2(prefix.identity, candidate));
|
|
9339
|
-
}
|
|
9340
|
-
function suffixRelationship(left, right) {
|
|
9341
|
-
const normalizedLeft = left.map(portablePathSegment);
|
|
9342
|
-
const normalizedRight = right.map(portablePathSegment);
|
|
9343
|
-
const sharedLength = Math.min(normalizedLeft.length, normalizedRight.length);
|
|
9344
|
-
for (let index = 0; index < sharedLength; index++) {
|
|
9345
|
-
if (normalizedLeft[index] !== normalizedRight[index]) return "distinct";
|
|
9346
|
-
}
|
|
9347
|
-
if (normalizedLeft.length === normalizedRight.length) return "equivalent";
|
|
9348
|
-
return normalizedLeft.length < normalizedRight.length ? "ancestor" : "descendant";
|
|
9349
|
-
}
|
|
9350
|
-
function portablePathSegment(value) {
|
|
9351
|
-
return value.normalize("NFC").toLowerCase();
|
|
9352
|
-
}
|
|
9353
|
-
function identity2(value) {
|
|
9354
|
-
return { device: String(value.dev), inode: String(value.ino) };
|
|
9355
|
-
}
|
|
9356
|
-
function sameIdentity2(left, right) {
|
|
9357
|
-
return left.device === right.device && left.inode === right.inode;
|
|
9358
|
-
}
|
|
9359
|
-
async function validateDestination(destination) {
|
|
9360
|
-
let stat4;
|
|
9361
|
-
try {
|
|
9362
|
-
stat4 = await lstat2(destination);
|
|
9363
|
-
} catch (error) {
|
|
9364
|
-
if (isEnoent2(error)) return;
|
|
9365
|
-
throw error;
|
|
9366
|
-
}
|
|
9367
|
-
if (stat4.isSymbolicLink()) {
|
|
9368
|
-
throw new MigrationApplicationError(
|
|
9369
|
-
"unsupported-path-type",
|
|
9370
|
-
`Migration destination must not be a symbolic link: ${destination}`,
|
|
9371
|
-
[destination]
|
|
9372
|
-
);
|
|
9373
|
-
}
|
|
9374
|
-
if (!stat4.isFile()) {
|
|
9375
|
-
throw new MigrationApplicationError(
|
|
9376
|
-
"unsupported-path-type",
|
|
9377
|
-
`Migration destination must be a regular file: ${destination}`,
|
|
9378
|
-
[destination]
|
|
9379
|
-
);
|
|
9380
|
-
}
|
|
9381
|
-
}
|
|
9382
|
-
function isEnoent2(error) {
|
|
9383
|
-
return typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT";
|
|
9384
|
-
}
|
|
9385
|
-
function isMissingPath(error) {
|
|
9386
|
-
return typeof error === "object" && error !== null && "code" in error && (error.code === "ENOENT" || error.code === "ENOTDIR");
|
|
9387
|
-
}
|
|
9388
|
-
|
|
9389
9989
|
// src/migrator/stylesheet.planner.ts
|
|
9390
|
-
import { lstat as lstat3, readFile as
|
|
9391
|
-
import * as
|
|
9990
|
+
import { lstat as lstat3, readFile as readFile3 } from "fs/promises";
|
|
9991
|
+
import * as path11 from "path";
|
|
9392
9992
|
|
|
9393
9993
|
// src/adapter/css/stylesheet/css-stylesheet.error.ts
|
|
9394
9994
|
var CssStylesheetError = class extends Error {
|
|
@@ -9917,7 +10517,7 @@ function mergeStylesheetContents(existing, rules, references = new Set(rules.map
|
|
|
9917
10517
|
|
|
9918
10518
|
// src/migrator/stylesheet.planner.ts
|
|
9919
10519
|
var nodeFileSystem2 = {
|
|
9920
|
-
readFile: (target) =>
|
|
10520
|
+
readFile: (target) => readFile3(target, "utf8"),
|
|
9921
10521
|
lstat: lstat3
|
|
9922
10522
|
};
|
|
9923
10523
|
var StylesheetPlanner = class {
|
|
@@ -9925,7 +10525,7 @@ var StylesheetPlanner = class {
|
|
|
9925
10525
|
this.fileSystem = fileSystem;
|
|
9926
10526
|
}
|
|
9927
10527
|
async plan(stylesheetPath, rules, references = new Set(rules.map((rule) => rule.className))) {
|
|
9928
|
-
const outputPath =
|
|
10528
|
+
const outputPath = path11.resolve(stylesheetPath);
|
|
9929
10529
|
const original = await this.originalState(outputPath);
|
|
9930
10530
|
const existing = original.status === "present" ? original.contents : "";
|
|
9931
10531
|
let merged;
|
|
@@ -9985,7 +10585,7 @@ function isEnoent3(error) {
|
|
|
9985
10585
|
}
|
|
9986
10586
|
|
|
9987
10587
|
// src/pipeline/validated-project-plan.ts
|
|
9988
|
-
import * as
|
|
10588
|
+
import * as path12 from "path";
|
|
9989
10589
|
function validatedProjectPlan(project) {
|
|
9990
10590
|
const rendered = renderedProject(project.rendered);
|
|
9991
10591
|
if (rendered.target !== rendered.session.target) {
|
|
@@ -10098,7 +10698,7 @@ function isPlainRecord2(value) {
|
|
|
10098
10698
|
return prototype === Object.prototype || prototype === null;
|
|
10099
10699
|
}
|
|
10100
10700
|
function normalizedAbsolutePath4(value) {
|
|
10101
|
-
return
|
|
10701
|
+
return path12.normalize(path12.resolve(value));
|
|
10102
10702
|
}
|
|
10103
10703
|
function fileCongruenceInvariant() {
|
|
10104
10704
|
return internalInvariant4(
|
|
@@ -10110,12 +10710,12 @@ function internalInvariant4(message) {
|
|
|
10110
10710
|
}
|
|
10111
10711
|
|
|
10112
10712
|
// src/pipeline/validate/css-reference.collector.ts
|
|
10113
|
-
import * as
|
|
10713
|
+
import * as path13 from "path";
|
|
10114
10714
|
|
|
10115
10715
|
// src/migrator/destination-template-source.ts
|
|
10116
|
-
import { readFile as
|
|
10716
|
+
import { readFile as readFile4 } from "fs/promises";
|
|
10117
10717
|
var nodeDestinationTemplateSource = Object.freeze({
|
|
10118
|
-
read: (
|
|
10718
|
+
read: (path19) => readFile4(path19, "utf8")
|
|
10119
10719
|
});
|
|
10120
10720
|
|
|
10121
10721
|
// src/pipeline/validate/css-reference.collector.ts
|
|
@@ -10134,10 +10734,10 @@ var CssReferenceCollector = class {
|
|
|
10134
10734
|
if (file.artifact?.kind === "template" && file.artifact.proposed.status === "present") {
|
|
10135
10735
|
return { contents: file.artifact.proposed.contents, complete: true };
|
|
10136
10736
|
}
|
|
10137
|
-
if (
|
|
10737
|
+
if (path13.resolve(file.file.inputPath) === path13.resolve(file.file.outputPath)) {
|
|
10138
10738
|
return { contents: analyzedTemplate.source, complete: true };
|
|
10139
10739
|
}
|
|
10140
|
-
const outputPath =
|
|
10740
|
+
const outputPath = path13.normalize(path13.resolve(file.file.outputPath));
|
|
10141
10741
|
const existing = destinationSources.get(outputPath);
|
|
10142
10742
|
if (existing !== void 0) return existing;
|
|
10143
10743
|
const pending = this.readDestination(outputPath);
|
|
@@ -10203,8 +10803,20 @@ function isEnoent4(error) {
|
|
|
10203
10803
|
return typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT";
|
|
10204
10804
|
}
|
|
10205
10805
|
|
|
10806
|
+
// src/template/generated-template-validation.ts
|
|
10807
|
+
function generatedTemplateErrors(source, fileName, parser = new AngularTemplateParser()) {
|
|
10808
|
+
const parsed2 = parser.parse(source, fileName);
|
|
10809
|
+
return parsed2.status === "parse-error" ? parsed2.diagnostics.map((diagnostic2) => ({
|
|
10810
|
+
status: "parse-error",
|
|
10811
|
+
fileName,
|
|
10812
|
+
code: "generated-template-parse-error",
|
|
10813
|
+
reason: diagnostic2.message,
|
|
10814
|
+
source: diagnostic2.source
|
|
10815
|
+
})) : [];
|
|
10816
|
+
}
|
|
10817
|
+
|
|
10206
10818
|
// src/pipeline/validate/template-proposal.validator.ts
|
|
10207
|
-
import * as
|
|
10819
|
+
import * as path14 from "path";
|
|
10208
10820
|
var TemplateProposalValidator = class {
|
|
10209
10821
|
constructor(validationParser = new AngularTemplateParser(), destinationTemplates = nodeDestinationTemplateSource) {
|
|
10210
10822
|
this.validationParser = validationParser;
|
|
@@ -10219,21 +10831,8 @@ var TemplateProposalValidator = class {
|
|
|
10219
10831
|
);
|
|
10220
10832
|
}
|
|
10221
10833
|
if (edited.output === template.source) return planResult(template, rendered, false, rendered.results);
|
|
10222
|
-
const
|
|
10223
|
-
if (
|
|
10224
|
-
return planResult(
|
|
10225
|
-
template,
|
|
10226
|
-
rendered,
|
|
10227
|
-
false,
|
|
10228
|
-
reparsed.diagnostics.map((diagnostic2) => ({
|
|
10229
|
-
status: "parse-error",
|
|
10230
|
-
fileName: template.file.outputPath,
|
|
10231
|
-
code: "generated-template-parse-error",
|
|
10232
|
-
reason: diagnostic2.message,
|
|
10233
|
-
source: diagnostic2.source
|
|
10234
|
-
}))
|
|
10235
|
-
);
|
|
10236
|
-
}
|
|
10834
|
+
const errors = generatedTemplateErrors(edited.output, template.file.outputPath, this.validationParser);
|
|
10835
|
+
if (errors.length) return planResult(template, rendered, false, errors);
|
|
10237
10836
|
const original = await originalState(template, this.destinationTemplates);
|
|
10238
10837
|
const proposed = { status: "present", contents: edited.output };
|
|
10239
10838
|
if (sameState3(original, proposed)) return planResult(template, rendered, false, rendered.results);
|
|
@@ -10241,7 +10840,7 @@ var TemplateProposalValidator = class {
|
|
|
10241
10840
|
file: result(template, rendered, true, rendered.results),
|
|
10242
10841
|
artifact: plannedOutputArtifact({
|
|
10243
10842
|
kind: "template",
|
|
10244
|
-
path:
|
|
10843
|
+
path: path14.normalize(path14.resolve(template.file.outputPath)),
|
|
10245
10844
|
original,
|
|
10246
10845
|
proposed
|
|
10247
10846
|
})
|
|
@@ -10249,7 +10848,7 @@ var TemplateProposalValidator = class {
|
|
|
10249
10848
|
}
|
|
10250
10849
|
};
|
|
10251
10850
|
async function originalState(template, destinationTemplates) {
|
|
10252
|
-
if (
|
|
10851
|
+
if (path14.resolve(template.file.inputPath) === path14.resolve(template.file.outputPath)) {
|
|
10253
10852
|
return { status: "present", contents: template.source };
|
|
10254
10853
|
}
|
|
10255
10854
|
try {
|
|
@@ -10317,7 +10916,7 @@ var ValidateProjectStage = class {
|
|
|
10317
10916
|
let stylesheetArtifact;
|
|
10318
10917
|
let stylesheet;
|
|
10319
10918
|
if (rendered.session.target === "css" && stylesheetPath !== void 0) {
|
|
10320
|
-
const canonicalStylesheetPath =
|
|
10919
|
+
const canonicalStylesheetPath = path15.resolve(stylesheetPath);
|
|
10321
10920
|
const references = await this.cssReferences.collect(rendered, files);
|
|
10322
10921
|
stylesheetArtifact = await this.stylesheetPlanner.plan(
|
|
10323
10922
|
canonicalStylesheetPath,
|
|
@@ -10403,19 +11002,19 @@ var AtomicFileWriter = class {
|
|
|
10403
11002
|
throw cleanupError(targetPath);
|
|
10404
11003
|
}
|
|
10405
11004
|
}
|
|
10406
|
-
async captureNamespaceIdentity(
|
|
10407
|
-
const stat4 = await this.operations.lstat(
|
|
11005
|
+
async captureNamespaceIdentity(path19, targetPath) {
|
|
11006
|
+
const stat4 = await this.operations.lstat(path19);
|
|
10408
11007
|
if (stat4.isSymbolicLink() || !stat4.isDirectory()) throw ownershipError(targetPath);
|
|
10409
11008
|
return identity3(stat4);
|
|
10410
11009
|
}
|
|
10411
|
-
async assertNamespaceIdentity(
|
|
10412
|
-
const stat4 = await this.operations.lstat(
|
|
11010
|
+
async assertNamespaceIdentity(path19, expected, targetPath) {
|
|
11011
|
+
const stat4 = await this.operations.lstat(path19);
|
|
10413
11012
|
if (stat4.isSymbolicLink() || !stat4.isDirectory() || !sameIdentity3(identity3(stat4), expected)) {
|
|
10414
11013
|
throw ownershipError(targetPath);
|
|
10415
11014
|
}
|
|
10416
11015
|
}
|
|
10417
|
-
async assertTemporaryIdentity(
|
|
10418
|
-
const stat4 = await this.operations.lstat(
|
|
11016
|
+
async assertTemporaryIdentity(path19, expected, targetPath) {
|
|
11017
|
+
const stat4 = await this.operations.lstat(path19);
|
|
10419
11018
|
if (stat4.isSymbolicLink() || !stat4.isFile() || !sameIdentity3(identity3(stat4), expected)) {
|
|
10420
11019
|
throw ownershipError(targetPath);
|
|
10421
11020
|
}
|
|
@@ -10479,19 +11078,19 @@ var JsonReportWriter = class {
|
|
|
10479
11078
|
constructor(writer = new AtomicFileWriter()) {
|
|
10480
11079
|
this.writer = writer;
|
|
10481
11080
|
}
|
|
10482
|
-
async write(
|
|
11081
|
+
async write(path19, report, options = {}) {
|
|
10483
11082
|
for (const protectedPath of options.protectedPaths ?? []) {
|
|
10484
|
-
if (!await pathsOverlapOnFileSystem(protectedPath,
|
|
10485
|
-
const collisionPaths = await pathsEquivalentOnFileSystem(protectedPath,
|
|
11083
|
+
if (!await pathsOverlapOnFileSystem(protectedPath, path19)) continue;
|
|
11084
|
+
const collisionPaths = await pathsEquivalentOnFileSystem(protectedPath, path19) ? [protectedPath] : [protectedPath, path19];
|
|
10486
11085
|
throw new MigrationApplicationError(
|
|
10487
11086
|
"path-collision",
|
|
10488
|
-
`Report path collides with a migration output: ${
|
|
11087
|
+
`Report path collides with a migration output: ${path19}`,
|
|
10489
11088
|
collisionPaths
|
|
10490
11089
|
);
|
|
10491
11090
|
}
|
|
10492
11091
|
const contents = `${JSON.stringify(report, null, 2)}
|
|
10493
11092
|
`;
|
|
10494
|
-
await this.writer.write(
|
|
11093
|
+
await this.writer.write(path19, contents);
|
|
10495
11094
|
}
|
|
10496
11095
|
};
|
|
10497
11096
|
|
|
@@ -10509,8 +11108,23 @@ var TerminalPresenter = class {
|
|
|
10509
11108
|
const diagnostics = report.files.flatMap(
|
|
10510
11109
|
(file) => file.results.filter((result2) => result2.status !== "converted").map((result2) => `${file.path}:${result2.offset} [${result2.code}] ${result2.reason}`)
|
|
10511
11110
|
);
|
|
11111
|
+
const profile = report.targetProfile;
|
|
11112
|
+
const environment = profile ? [
|
|
11113
|
+
"Target environment",
|
|
11114
|
+
`Tailwind: v${profile.version} (${profile.fingerprint})`,
|
|
11115
|
+
`Stylesheet: ${profile.stylesheet ?? "not supplied"}`,
|
|
11116
|
+
`Prefix: ${profile.prefix.value ?? "none"} (${profile.prefix.source}; ${profile.prefix.confidence})`,
|
|
11117
|
+
`Important utilities: ${profile.important.value} (${profile.important.source})`,
|
|
11118
|
+
`Core utilities: ${profile.coreUtilities.value} (${profile.coreUtilities.source}; ${profile.coreUtilities.confidence})`,
|
|
11119
|
+
...Object.entries(profile.breakpoints).map(
|
|
11120
|
+
([name, setting]) => `Breakpoint ${name}: ${setting.value} (${setting.source}; ${setting.confidence})`
|
|
11121
|
+
),
|
|
11122
|
+
...profile.diagnostics.map((item) => `[${item.code}] ${item.message}`),
|
|
11123
|
+
...profile.assumptions.map((item) => `Assumption: ${item}`),
|
|
11124
|
+
""
|
|
11125
|
+
] : [];
|
|
10512
11126
|
output.write(
|
|
10513
|
-
[presentation.outcome, totals, stylesheet, ...diagnostics, presentation.footer, ""].filter((line) => line !== void 0).join("\n")
|
|
11127
|
+
[...environment, presentation.outcome, totals, stylesheet, ...diagnostics, presentation.footer, ""].filter((line) => line !== void 0).join("\n")
|
|
10514
11128
|
);
|
|
10515
11129
|
}
|
|
10516
11130
|
applicationPresentation(report) {
|
|
@@ -10611,17 +11225,17 @@ function getErrorMessage(error) {
|
|
|
10611
11225
|
// src/cli/exit-policy.ts
|
|
10612
11226
|
function resolveExitCode(report, allowUnresolved) {
|
|
10613
11227
|
if (report.summary.parseErrors > 0) return 1;
|
|
10614
|
-
const hasUnresolved = report.summary.review > 0 || report.summary.unsupported > 0 || report.summary.invalid > 0;
|
|
11228
|
+
const hasUnresolved = (report.targetProfile?.diagnostics.length ?? 0) > 0 || report.summary.review > 0 || report.summary.unsupported > 0 || report.summary.invalid > 0;
|
|
10615
11229
|
return hasUnresolved && !allowUnresolved ? 2 : 0;
|
|
10616
11230
|
}
|
|
10617
11231
|
|
|
10618
11232
|
// src/cli/report-path.validator.ts
|
|
10619
|
-
import
|
|
11233
|
+
import path16 from "path";
|
|
10620
11234
|
function validateReportPath(reportPath) {
|
|
10621
11235
|
if (reportPath.trim().length === 0) {
|
|
10622
11236
|
throw new Error("Report path must not be empty.");
|
|
10623
11237
|
}
|
|
10624
|
-
if (
|
|
11238
|
+
if (path16.extname(reportPath).toLowerCase() !== ".json") {
|
|
10625
11239
|
throw new Error("Report path must have a .json extension.");
|
|
10626
11240
|
}
|
|
10627
11241
|
}
|
|
@@ -10654,8 +11268,8 @@ function parsePrintWithBreakpoints(value, orientationEnabled) {
|
|
|
10654
11268
|
}
|
|
10655
11269
|
|
|
10656
11270
|
// src/cli/stylesheet-path.validator.ts
|
|
10657
|
-
import * as
|
|
10658
|
-
async function validateStylesheetPath(request, pathApi =
|
|
11271
|
+
import * as path17 from "path";
|
|
11272
|
+
async function validateStylesheetPath(request, pathApi = path17) {
|
|
10659
11273
|
if (request.target !== "css") {
|
|
10660
11274
|
if (request.stylesheetPath !== void 0) {
|
|
10661
11275
|
throw new MigrationApplicationError("invalid-configuration", "--stylesheet can only be used with --target css.", [
|
|
@@ -10685,6 +11299,7 @@ function resolveMigrationMode(argv, write) {
|
|
|
10685
11299
|
if (optionArguments.filter((argument) => argument === "--write").length > 1) {
|
|
10686
11300
|
throw new Error("--write may only be specified once.");
|
|
10687
11301
|
}
|
|
11302
|
+
if (write && optionArguments.includes("--plan")) throw new Error("--plan and --write cannot be combined.");
|
|
10688
11303
|
return write ? "write" : "plan";
|
|
10689
11304
|
}
|
|
10690
11305
|
|
|
@@ -10713,7 +11328,7 @@ async function runCli(argv, output = processOutput, dependencies = {}) {
|
|
|
10713
11328
|
new Option("--stylesheet <path>", "companion stylesheet; required when --target css").argParser(
|
|
10714
11329
|
parseSingleStylesheet
|
|
10715
11330
|
)
|
|
10716
|
-
).option("--write", "apply the validated migration plan", false).option("--report <path>", "atomically write a JSON report; path must end in .json").option("--allow-unresolved", "return success when unresolved inputs remain", false).option("--orientation-breakpoints", "confirm the source enables the archived orientation breakpoints", false).option(
|
|
11331
|
+
).option("--config <path>", "declarative migration JSON configuration").option("--tailwind-stylesheet <path>", "statically analyze a Tailwind v4 target stylesheet").option("--tailwind-prefix <prefix>", "override Tailwind v4 prefix; empty string means none").option("--plan", "explicitly request the default review-only plan").option("--write", "apply the validated migration plan", false).option("--report <path>", "atomically write a JSON report; path must end in .json").option("--allow-unresolved", "return success when unresolved inputs remain", false).option("--orientation-breakpoints", "confirm the source enables the archived orientation breakpoints", false).option(
|
|
10717
11332
|
"--responsive-images",
|
|
10718
11333
|
"wrap eligible responsive images in picture elements; acknowledges selector and layout risk",
|
|
10719
11334
|
false
|
|
@@ -10724,23 +11339,38 @@ async function runCli(argv, output = processOutput, dependencies = {}) {
|
|
|
10724
11339
|
const mode = resolveMigrationMode(argv, options.write);
|
|
10725
11340
|
debug = options.debug;
|
|
10726
11341
|
logger.level = debug ? "debug" : "warn";
|
|
11342
|
+
const configuration = await loadMigrationConfig({
|
|
11343
|
+
config: options.config,
|
|
11344
|
+
stylesheet: options.tailwindStylesheet,
|
|
11345
|
+
prefix: options.tailwindPrefix
|
|
11346
|
+
});
|
|
11347
|
+
const target = program.getOptionValueSource("target") === "cli" ? options.target : configuration.target ?? options.target;
|
|
11348
|
+
if (target !== "tailwind" && (options.tailwindStylesheet !== void 0 || options.tailwindPrefix !== void 0))
|
|
11349
|
+
throw new Error("Tailwind target options require --target tailwind.");
|
|
10727
11350
|
const destination = options.output ?? input;
|
|
10728
11351
|
let reportPath;
|
|
10729
11352
|
if (options.report !== void 0) {
|
|
10730
11353
|
validateReportPath(options.report);
|
|
10731
|
-
reportPath =
|
|
11354
|
+
reportPath = path18.resolve(options.report);
|
|
10732
11355
|
}
|
|
11356
|
+
if (reportPath)
|
|
11357
|
+
for (const snapshot of configuration.snapshots) {
|
|
11358
|
+
if (await pathsOverlapOnFileSystem(reportPath, snapshot.path))
|
|
11359
|
+
throw new Error("Report path collides with a target configuration input.");
|
|
11360
|
+
}
|
|
10733
11361
|
const stylesheetPath = await validateStylesheetPath({
|
|
10734
|
-
target
|
|
11362
|
+
target,
|
|
10735
11363
|
stylesheetPath: options.stylesheet,
|
|
10736
11364
|
inputPath: input,
|
|
10737
11365
|
outputPath: destination,
|
|
10738
11366
|
reportPath
|
|
10739
11367
|
});
|
|
10740
11368
|
const printWithBreakpoints = options.printWithBreakpoints === void 0 ? void 0 : parsePrintWithBreakpoints(options.printWithBreakpoints, options.orientationBreakpoints);
|
|
10741
|
-
const session = AdapterFactory.createRenderSession(
|
|
11369
|
+
const session = AdapterFactory.createRenderSession(target, {
|
|
10742
11370
|
orientationBreakpoints: options.orientationBreakpoints,
|
|
10743
|
-
printWithBreakpoints
|
|
11371
|
+
printWithBreakpoints,
|
|
11372
|
+
targetProfile: target === "tailwind" ? configuration.targetProfile : void 0,
|
|
11373
|
+
sourceBreakpoints: configuration.sourceBreakpoints
|
|
10744
11374
|
});
|
|
10745
11375
|
const render = new RenderProjectStage(session);
|
|
10746
11376
|
const pipeline = new MigrationPipeline(
|
|
@@ -10757,6 +11387,9 @@ async function runCli(argv, output = processOutput, dependencies = {}) {
|
|
|
10757
11387
|
outputPath: destination,
|
|
10758
11388
|
options: {
|
|
10759
11389
|
mode,
|
|
11390
|
+
targetProfile: target === "tailwind" ? configuration.targetProfile : void 0,
|
|
11391
|
+
sourceBreakpoints: configuration.sourceBreakpoints,
|
|
11392
|
+
configurationSnapshots: configuration.snapshots,
|
|
10760
11393
|
responsiveImages: options.responsiveImages,
|
|
10761
11394
|
stylesheetPath,
|
|
10762
11395
|
stylesheetPathInput: options.stylesheet,
|
|
@@ -10768,7 +11401,10 @@ async function runCli(argv, output = processOutput, dependencies = {}) {
|
|
|
10768
11401
|
new TerminalPresenter().present(report, reportOutput);
|
|
10769
11402
|
if (reportPath !== void 0) {
|
|
10770
11403
|
await new JsonReportWriter().write(reportPath, report, {
|
|
10771
|
-
protectedPaths:
|
|
11404
|
+
protectedPaths: [
|
|
11405
|
+
...configuration.snapshots.map((snapshot) => snapshot.path),
|
|
11406
|
+
...stylesheetPath === void 0 ? [] : [stylesheetPath]
|
|
11407
|
+
]
|
|
10772
11408
|
});
|
|
10773
11409
|
}
|
|
10774
11410
|
exitCode = resolveExitCode(report, options.allowUnresolved);
|