openapi-typesafe-migrate 1.0.0-rc.11 → 1.0.0-rc.12
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 +46 -0
- package/README.md +8 -2
- package/dist/cli/main.mjs +508 -250
- package/dist/cli/main.mjs.map +1 -1
- package/package.json +1 -1
package/dist/cli/main.mjs
CHANGED
|
@@ -910,12 +910,19 @@ function optionsOf(argument, bindings) {
|
|
|
910
910
|
}
|
|
911
911
|
return ts.isIdentifier(value) ? constantOptions(value, bindings, types) : { kind: "unknown", expression: argument };
|
|
912
912
|
}
|
|
913
|
+
const UNDEFINED = "undefined";
|
|
914
|
+
function isNoValue(argument, bindings) {
|
|
915
|
+
const { value } = unwrapped(argument);
|
|
916
|
+
const isUndefined = ts.isIdentifier(value) && value.text === UNDEFINED && bindings.declarationOf(value) === void 0;
|
|
917
|
+
return isUndefined || ts.isVoidExpression(value);
|
|
918
|
+
}
|
|
913
919
|
function generatorCalls(file, bindings) {
|
|
914
920
|
const calls = [];
|
|
915
921
|
const visit = (node) => {
|
|
916
922
|
if (ts.isCallExpression(node) && isGenerator(node.expression, bindings)) {
|
|
917
923
|
const argument = node.arguments[1];
|
|
918
|
-
const
|
|
924
|
+
const isOmitted = argument === void 0 || isNoValue(argument, bindings);
|
|
925
|
+
const options = isOmitted ? void 0 : optionsOf(argument, bindings);
|
|
919
926
|
calls.push({ call: node, options });
|
|
920
927
|
}
|
|
921
928
|
ts.forEachChild(node, visit);
|
|
@@ -949,7 +956,7 @@ function importTypeName(node) {
|
|
|
949
956
|
const isOptions = !node.isTypeOf && qualifier !== void 0 && ts.isIdentifier(qualifier) && qualifier.text === TS_NODE_OPTIONS;
|
|
950
957
|
return isGeneratorModule && isOptions ? qualifier : void 0;
|
|
951
958
|
}
|
|
952
|
-
function referencedName$
|
|
959
|
+
function referencedName$2(node) {
|
|
953
960
|
if (ts.isTypeReferenceNode(node)) {
|
|
954
961
|
return node.typeName;
|
|
955
962
|
}
|
|
@@ -965,7 +972,7 @@ function optionsTypeName(node, bindings) {
|
|
|
965
972
|
if (ts.isImportTypeNode(node)) {
|
|
966
973
|
return importTypeName(node);
|
|
967
974
|
}
|
|
968
|
-
const name = referencedName$
|
|
975
|
+
const name = referencedName$2(node);
|
|
969
976
|
if (name !== void 0 && ts.isIdentifier(name)) {
|
|
970
977
|
const binding = bindings.bindingOf(name);
|
|
971
978
|
return binding?.kind === "helper-import" && binding.name === TS_NODE_OPTIONS ? name : void 0;
|
|
@@ -978,7 +985,7 @@ function optionsTypeName(node, bindings) {
|
|
|
978
985
|
return isGeneratorModule && parts.right.text === TS_NODE_OPTIONS ? parts.right : void 0;
|
|
979
986
|
}
|
|
980
987
|
function localTypeOf(node, bindings) {
|
|
981
|
-
const name = referencedName$
|
|
988
|
+
const name = referencedName$2(node);
|
|
982
989
|
const binding = name !== void 0 && ts.isIdentifier(name) ? bindings.bindingOf(name) : void 0;
|
|
983
990
|
return binding?.kind === "local-type" ? binding.declaration : void 0;
|
|
984
991
|
}
|
|
@@ -2072,10 +2079,10 @@ const PNPM_SETTINGS_FIELD = "pnpm";
|
|
|
2072
2079
|
const OLD_PEER_DEPENDENTS = /* @__PURE__ */ new Map([
|
|
2073
2080
|
["swr-openapi", { peer: "openapi-fetch", range: ">=0.15" }]
|
|
2074
2081
|
]);
|
|
2075
|
-
const PATH_SEPARATOR$
|
|
2082
|
+
const PATH_SEPARATOR$b = "/";
|
|
2076
2083
|
const QUERY_START = "?";
|
|
2077
2084
|
function renamedSpecifier(value) {
|
|
2078
|
-
const ends = [value.indexOf(PATH_SEPARATOR$
|
|
2085
|
+
const ends = [value.indexOf(PATH_SEPARATOR$b), value.indexOf(QUERY_START)].filter(
|
|
2079
2086
|
(at) => at !== -1
|
|
2080
2087
|
);
|
|
2081
2088
|
const name = value.slice(0, ends.length === 0 ? value.length : Math.min(...ends));
|
|
@@ -2085,12 +2092,12 @@ function renamedSpecifier(value) {
|
|
|
2085
2092
|
}
|
|
2086
2093
|
const rest = value.slice(name.length);
|
|
2087
2094
|
const subpath = rest.split(QUERY_START, 1)[0] ?? rest;
|
|
2088
|
-
return { to: `${renamed}${rest}`, isDeep: subpath !== "" && subpath !== PATH_SEPARATOR$
|
|
2095
|
+
return { to: `${renamed}${rest}`, isDeep: subpath !== "" && subpath !== PATH_SEPARATOR$b };
|
|
2089
2096
|
}
|
|
2090
2097
|
const NODE_MODULES_FOLDER = "node_modules/";
|
|
2091
2098
|
function oldPackageInNodeModules(path) {
|
|
2092
2099
|
return [...PACKAGE_RENAMES.keys()].find(
|
|
2093
|
-
(name) => path.includes(`${NODE_MODULES_FOLDER}${name}${PATH_SEPARATOR$
|
|
2100
|
+
(name) => path.includes(`${NODE_MODULES_FOLDER}${name}${PATH_SEPARATOR$b}`) || path.endsWith(`${NODE_MODULES_FOLDER}${name}`)
|
|
2094
2101
|
);
|
|
2095
2102
|
}
|
|
2096
2103
|
|
|
@@ -2311,6 +2318,14 @@ const LAUNCHERS = [
|
|
|
2311
2318
|
launcher(["xargs"], NONE, XARGS_OPTIONS),
|
|
2312
2319
|
launcher(["nohup"]),
|
|
2313
2320
|
launcher(["sudo"], NONE, /* @__PURE__ */ new Set(["-u", "-g"])),
|
|
2321
|
+
// The init programs of containers run their arguments as the container's command, so an
|
|
2322
|
+
// entrypoint `["tini", "--"]` gives the generator the command's flags.
|
|
2323
|
+
launcher(["tini"], NONE, /* @__PURE__ */ new Set(["-p", "-e"])),
|
|
2324
|
+
launcher(["docker-init"], NONE, /* @__PURE__ */ new Set(["-p", "-e"])),
|
|
2325
|
+
launcher(["dumb-init"], NONE, /* @__PURE__ */ new Set(["-r", "--rewrite"])),
|
|
2326
|
+
launcher(["catatonit"]),
|
|
2327
|
+
withOperands(["gosu"], 1),
|
|
2328
|
+
withOperands(["su-exec"], 1),
|
|
2314
2329
|
// The shell form of Dockerfile instructions runs the rest of the line in a shell.
|
|
2315
2330
|
launcher(["RUN"], NONE, /* @__PURE__ */ new Set(["--mount", "--network", "--security"])),
|
|
2316
2331
|
launcher(["CMD"]),
|
|
@@ -2341,7 +2356,7 @@ const EXPRESSION_CLOSE$1 = "}}";
|
|
|
2341
2356
|
const LITERAL_QUOTE = "'";
|
|
2342
2357
|
const SHELL_SINGLE_QUOTE = "'";
|
|
2343
2358
|
const BACKSLASH$3 = "\\";
|
|
2344
|
-
const DOUBLE_QUOTE$
|
|
2359
|
+
const DOUBLE_QUOTE$2 = '"';
|
|
2345
2360
|
function expressionEnd(text, start) {
|
|
2346
2361
|
for (let index = start + EXPRESSION_OPEN.length; index < text.length; ) {
|
|
2347
2362
|
if (text.startsWith(EXPRESSION_CLOSE$1, index)) {
|
|
@@ -2405,7 +2420,7 @@ function mapExpressions(text, map) {
|
|
|
2405
2420
|
return parts.join("");
|
|
2406
2421
|
}
|
|
2407
2422
|
function isWholeExpression(raw) {
|
|
2408
|
-
const isQuoted = raw.length > 1 && raw.startsWith(DOUBLE_QUOTE$
|
|
2423
|
+
const isQuoted = raw.length > 1 && raw.startsWith(DOUBLE_QUOTE$2) && raw.endsWith(DOUBLE_QUOTE$2);
|
|
2409
2424
|
const inner = isQuoted ? 1 : 0;
|
|
2410
2425
|
return raw.startsWith(EXPRESSION_OPEN, inner) && expressionEnd(raw, inner) === raw.length - inner;
|
|
2411
2426
|
}
|
|
@@ -2421,7 +2436,7 @@ const COMMAND_SEPARATORS = /* @__PURE__ */ new Set([
|
|
|
2421
2436
|
]);
|
|
2422
2437
|
const WORD_BREAKS = /* @__PURE__ */ new Set([" ", " ", "\r", "<", ">"]);
|
|
2423
2438
|
const BACKSLASH$2 = "\\";
|
|
2424
|
-
const DOUBLE_QUOTE_ESCAPES = /* @__PURE__ */ new Set(["$", "`", '"', BACKSLASH$2, "\n"]);
|
|
2439
|
+
const DOUBLE_QUOTE_ESCAPES$1 = /* @__PURE__ */ new Set(["$", "`", '"', BACKSLASH$2, "\n"]);
|
|
2425
2440
|
function singleQuoted(text, start) {
|
|
2426
2441
|
const close = text.indexOf("'", start + 1);
|
|
2427
2442
|
const end = close === -1 ? text.length : close + 1;
|
|
@@ -2432,7 +2447,7 @@ function doubleQuoted(text, start) {
|
|
|
2432
2447
|
let index = start + 1;
|
|
2433
2448
|
while (index < text.length && text[index] !== '"') {
|
|
2434
2449
|
const next = text[index + 1] ?? "";
|
|
2435
|
-
const isEscape = text[index] === BACKSLASH$2 && DOUBLE_QUOTE_ESCAPES.has(next);
|
|
2450
|
+
const isEscape = text[index] === BACKSLASH$2 && DOUBLE_QUOTE_ESCAPES$1.has(next);
|
|
2436
2451
|
value += isEscape ? next === "\n" ? "" : next : text[index];
|
|
2437
2452
|
index += isEscape ? 2 : 1;
|
|
2438
2453
|
}
|
|
@@ -2512,7 +2527,7 @@ function wordPart(text, index) {
|
|
|
2512
2527
|
function doubleQuotedOffsets(text, start, end) {
|
|
2513
2528
|
const offsets = [];
|
|
2514
2529
|
for (let index = start + 1; index < end && text[index] !== '"'; index++) {
|
|
2515
|
-
const isEscape = text[index] === BACKSLASH$2 && DOUBLE_QUOTE_ESCAPES.has(text[index + 1] ?? "");
|
|
2530
|
+
const isEscape = text[index] === BACKSLASH$2 && DOUBLE_QUOTE_ESCAPES$1.has(text[index + 1] ?? "");
|
|
2516
2531
|
index += isEscape ? 1 : 0;
|
|
2517
2532
|
if (text[index] !== "\n" || !isEscape) {
|
|
2518
2533
|
offsets.push(index);
|
|
@@ -2572,6 +2587,42 @@ function readWord(text, start) {
|
|
|
2572
2587
|
return { start, end: index, value, raw: text.slice(start, index) };
|
|
2573
2588
|
}
|
|
2574
2589
|
|
|
2590
|
+
const writtenOffset = (word, index) => word.written?.[index] ?? word.start + index;
|
|
2591
|
+
function rawText(word, from, text) {
|
|
2592
|
+
return { text, offsets: Array.from(text, (_, index) => writtenOffset(word, from + index)) };
|
|
2593
|
+
}
|
|
2594
|
+
function unquotedRawText(word, from) {
|
|
2595
|
+
const { value, offsets } = unquotedText(word.raw.slice(from));
|
|
2596
|
+
return { text: value, offsets: offsets.map((index) => writtenOffset(word, from + index)) };
|
|
2597
|
+
}
|
|
2598
|
+
function placedWord(word, { offsets }) {
|
|
2599
|
+
const written = Array.from(word.raw, (_, index) => {
|
|
2600
|
+
return offsets[writtenOffset(word, index)];
|
|
2601
|
+
});
|
|
2602
|
+
const start = written[0] ?? offsets[word.start];
|
|
2603
|
+
const end = (written.at(-1) ?? start - 1) + 1;
|
|
2604
|
+
const isInOnePiece = written.every((offset, index) => offset === start + index);
|
|
2605
|
+
const placed = { start, end, value: word.value, raw: word.raw };
|
|
2606
|
+
return isInOnePiece ? placed : { ...placed, written };
|
|
2607
|
+
}
|
|
2608
|
+
function movedWord(word, offset) {
|
|
2609
|
+
const moved = { ...word, start: word.start + offset, end: word.end + offset };
|
|
2610
|
+
return word.written === void 0 ? moved : { ...moved, written: word.written.map((at) => at + offset) };
|
|
2611
|
+
}
|
|
2612
|
+
function writtenSpan(word, from, length) {
|
|
2613
|
+
const first = writtenOffset(word, from);
|
|
2614
|
+
const last = writtenOffset(word, from + length - 1);
|
|
2615
|
+
return last - first === length - 1 ? { start: first, end: last + 1 } : void 0;
|
|
2616
|
+
}
|
|
2617
|
+
function placedSpan({ offsets }, length) {
|
|
2618
|
+
const first = offsets[0];
|
|
2619
|
+
const last = offsets[length - 1];
|
|
2620
|
+
if (first === void 0 || last === void 0 || last - first !== length - 1) {
|
|
2621
|
+
return void 0;
|
|
2622
|
+
}
|
|
2623
|
+
return { start: first, end: last + 1 };
|
|
2624
|
+
}
|
|
2625
|
+
|
|
2575
2626
|
const ASSIGNMENT_RE$2 = /^([A-Za-z_][A-Za-z0-9_]*)(\+?=)/;
|
|
2576
2627
|
const APPEND_OPERATOR$1 = "+=";
|
|
2577
2628
|
const DECLARATION_BUILTINS = /* @__PURE__ */ new Set([
|
|
@@ -2585,8 +2636,9 @@ function leadingAssignments(command) {
|
|
|
2585
2636
|
const index = command.findIndex((word) => !ASSIGNMENT_RE$2.test(word.raw));
|
|
2586
2637
|
return index === -1 ? command.length : index;
|
|
2587
2638
|
}
|
|
2588
|
-
|
|
2589
|
-
|
|
2639
|
+
const ARGUMENT_ASSIGNMENT_RE = /^([A-Za-z_][A-Za-z0-9_.-]*)(:::=|::=|:=|\?=|!=|\+?=)/;
|
|
2640
|
+
function assignmentOf(word, pattern = ASSIGNMENT_RE$2) {
|
|
2641
|
+
const match = pattern.exec(word.raw);
|
|
2590
2642
|
const name = match?.[1];
|
|
2591
2643
|
if (match === null || name === void 0) {
|
|
2592
2644
|
return [];
|
|
@@ -2599,42 +2651,22 @@ function shellAssignments(command) {
|
|
|
2599
2651
|
const count = leadingAssignments(command);
|
|
2600
2652
|
const isDeclaration = DECLARATION_BUILTINS.has(command[count]?.value ?? "");
|
|
2601
2653
|
const words = [...command.slice(0, count), ...isDeclaration ? command.slice(count + 1) : []];
|
|
2602
|
-
return words.flatMap(assignmentOf);
|
|
2654
|
+
return words.flatMap((word) => assignmentOf(word));
|
|
2603
2655
|
}
|
|
2604
2656
|
function argumentAssignments(command) {
|
|
2605
2657
|
const own = new Set(shellAssignments(command).map(({ word }) => word));
|
|
2606
|
-
return command.slice(leadingAssignments(command)).filter((word) => !own.has(word)).flatMap(assignmentOf);
|
|
2658
|
+
return command.slice(leadingAssignments(command)).filter((word) => !own.has(word)).flatMap((word) => assignmentOf(word, ARGUMENT_ASSIGNMENT_RE));
|
|
2607
2659
|
}
|
|
2608
2660
|
const COMMAND_LINE_RE = /[\s;&|()`]/;
|
|
2609
2661
|
const holdsCommandLine = (assignment) => COMMAND_LINE_RE.test(assignment.value);
|
|
2610
2662
|
const ARRAY_OPEN = "(";
|
|
2611
2663
|
const isArrayAssignment = (assignment) => assignment.word.raw.startsWith(ARRAY_OPEN, assignment.head);
|
|
2612
|
-
function arrayValue({ word, head }) {
|
|
2613
|
-
const start = word.start + head + 1;
|
|
2614
|
-
const place = (found) => ({
|
|
2615
|
-
...found,
|
|
2616
|
-
start: found.start + start,
|
|
2617
|
-
end: found.end + start
|
|
2618
|
-
});
|
|
2619
|
-
return { text: word.raw.slice(head + 1, -1), place };
|
|
2620
|
-
}
|
|
2621
2664
|
function assignmentValue(assignment) {
|
|
2622
|
-
if (isArrayAssignment(assignment)) {
|
|
2623
|
-
return arrayValue(assignment);
|
|
2624
|
-
}
|
|
2625
2665
|
const { word, head } = assignment;
|
|
2626
|
-
|
|
2627
|
-
const written = (index) => head + offsets[index];
|
|
2628
|
-
const place = (found) => {
|
|
2629
|
-
const first = written(found.start);
|
|
2630
|
-
const end = written(found.end - 1) + 1;
|
|
2631
|
-
const raw = word.raw.slice(first, end);
|
|
2632
|
-
return { ...found, start: word.start + first, end: word.start + end, raw };
|
|
2633
|
-
};
|
|
2634
|
-
return { text: value, place };
|
|
2666
|
+
return isArrayAssignment(assignment) ? rawText(word, head + 1, word.raw.slice(head + 1, -1)) : unquotedRawText(word, head);
|
|
2635
2667
|
}
|
|
2636
2668
|
|
|
2637
|
-
const END_OF_OPTIONS = "--";
|
|
2669
|
+
const END_OF_OPTIONS$1 = "--";
|
|
2638
2670
|
const isOption$1 = (word) => word.value.startsWith("-") && word.value.length > 1;
|
|
2639
2671
|
function skipAssignments(words, start) {
|
|
2640
2672
|
let index = start;
|
|
@@ -2646,7 +2678,8 @@ function skipAssignments(words, start) {
|
|
|
2646
2678
|
const WINDOWS_PROGRAM_SUFFIX_RE = /\.(?:cmd|exe|ps1)$/i;
|
|
2647
2679
|
const windowsSuffix = (value) => WINDOWS_PROGRAM_SUFFIX_RE.exec(value)?.[0] ?? "";
|
|
2648
2680
|
const withoutWindowsSuffix = (value) => value.slice(0, value.length - windowsSuffix(value).length);
|
|
2649
|
-
const
|
|
2681
|
+
const FOLDERS_RE = /^.*[/\\]/;
|
|
2682
|
+
const entryWord = (word) => word === void 0 ? void 0 : withoutWindowsSuffix(word.value.replace(FOLDERS_RE, ""));
|
|
2650
2683
|
function matchingPrefix(entries, words, index) {
|
|
2651
2684
|
return entries.find(
|
|
2652
2685
|
(entry) => entry.words.every((name, offset) => entryWord(words[index + offset]) === name)
|
|
@@ -2661,7 +2694,7 @@ function launchedProgram(words, start, launcher, packages) {
|
|
|
2661
2694
|
let index = start;
|
|
2662
2695
|
while (index < words.length && isOption$1(words[index])) {
|
|
2663
2696
|
const option = words[index++];
|
|
2664
|
-
if (option.value === END_OF_OPTIONS) {
|
|
2697
|
+
if (option.value === END_OF_OPTIONS$1) {
|
|
2665
2698
|
break;
|
|
2666
2699
|
}
|
|
2667
2700
|
const inline = option.value.includes("=") ? inlineOptionPackage(option, launcher) : void 0;
|
|
@@ -2712,13 +2745,28 @@ const unreadArgumentValues = (words) => new Map(
|
|
|
2712
2745
|
);
|
|
2713
2746
|
function unmigratedWordFindings(words, handledOffsets, locate) {
|
|
2714
2747
|
const values = unreadArgumentValues(words);
|
|
2748
|
+
const assignments = new Set(shellAssignments(words).map(({ word }) => word));
|
|
2715
2749
|
const namesOld = (word) => namesOldPackage(word.value) || namesOldPackage(values.get(word) ?? "");
|
|
2716
|
-
return words.filter((word) => !handledOffsets.has(word.start) && namesOld(word)).map((word) => ({
|
|
2750
|
+
return words.filter((word) => !handledOffsets.has(word.start) && !assignments.has(word) && namesOld(word)).map((word) => ({
|
|
2717
2751
|
offset: word.start,
|
|
2718
2752
|
manualStep: { kind: "old-name-in-command", location: locate(word.start), word: word.value }
|
|
2719
2753
|
}));
|
|
2720
2754
|
}
|
|
2721
2755
|
|
|
2756
|
+
const PATH_SEPARATOR$a = "/";
|
|
2757
|
+
const WINDOWS_SEPARATOR_RE = /\\/g;
|
|
2758
|
+
const QUOTE_RE = /["']/g;
|
|
2759
|
+
const WINDOWS_PATH_RE = /^[^/]*[^\\/\s]\\[^\\/\s][^/]*$/;
|
|
2760
|
+
function programPath(word) {
|
|
2761
|
+
const suffix = windowsSuffix(word.value);
|
|
2762
|
+
const written = word.raw.replace(QUOTE_RE, "");
|
|
2763
|
+
const isWindowsPath = suffix !== "" || WINDOWS_PATH_RE.test(written);
|
|
2764
|
+
if (!isWindowsPath) {
|
|
2765
|
+
return { path: word.value, suffix, written: word.value };
|
|
2766
|
+
}
|
|
2767
|
+
return { path: written.replace(WINDOWS_SEPARATOR_RE, PATH_SEPARATOR$a), suffix, written };
|
|
2768
|
+
}
|
|
2769
|
+
|
|
2722
2770
|
const RECIPE_PREFIX_RE$1 = /^[@+-]+(?=.)/;
|
|
2723
2771
|
function withoutRecipePrefix(words) {
|
|
2724
2772
|
const [first, ...rest] = words;
|
|
@@ -2731,11 +2779,20 @@ const NO_VARIABLES = {
|
|
|
2731
2779
|
programAt: () => void 0,
|
|
2732
2780
|
referenceAt: () => void 0
|
|
2733
2781
|
};
|
|
2782
|
+
const PATH_SEPARATOR$9 = "/";
|
|
2783
|
+
const BIN_FOLDER$1 = "/.bin/";
|
|
2784
|
+
function namesGenerator(word) {
|
|
2785
|
+
const { path, suffix } = programPath(word);
|
|
2786
|
+
if (path.includes(PATH_SEPARATOR$9)) {
|
|
2787
|
+
return path.endsWith(`${BIN_FOLDER$1}${GENERATOR_COMMAND}${suffix}`);
|
|
2788
|
+
}
|
|
2789
|
+
return packageReference(path.slice(0, path.length - suffix.length)).name === GENERATOR_COMMAND;
|
|
2790
|
+
}
|
|
2734
2791
|
function runsGenerator(command) {
|
|
2735
2792
|
const words = withoutRecipePrefix(command);
|
|
2736
2793
|
const { program } = commandRoles(words);
|
|
2737
2794
|
const word = program === void 0 ? void 0 : words[program];
|
|
2738
|
-
return word !== void 0 &&
|
|
2795
|
+
return word !== void 0 && namesGenerator(word);
|
|
2739
2796
|
}
|
|
2740
2797
|
|
|
2741
2798
|
const COMMAND_PREFIX_WORDS = /* @__PURE__ */ new Set([
|
|
@@ -2775,7 +2832,7 @@ function simpleCommand(words) {
|
|
|
2775
2832
|
const HEREDOC_OPERATOR = "<<";
|
|
2776
2833
|
const HERE_STRING_OPERATOR = "<<<";
|
|
2777
2834
|
const STRIP_TABS = "-";
|
|
2778
|
-
const LINE_BREAK$
|
|
2835
|
+
const LINE_BREAK$7 = "\n";
|
|
2779
2836
|
const LEADING_TABS_RE = /^\t+/;
|
|
2780
2837
|
const CARRIAGE_RETURN_RE = /\r$/;
|
|
2781
2838
|
function heredocAt(text, index, where) {
|
|
@@ -2807,7 +2864,7 @@ function isDelimiterLine(text, lineStart, end, heredoc) {
|
|
|
2807
2864
|
function readBody(text, start, heredoc) {
|
|
2808
2865
|
let lineStart = start;
|
|
2809
2866
|
while (lineStart < text.length) {
|
|
2810
|
-
const lineEnd = text.indexOf(LINE_BREAK$
|
|
2867
|
+
const lineEnd = text.indexOf(LINE_BREAK$7, lineStart);
|
|
2811
2868
|
const end = lineEnd === -1 ? text.length : lineEnd;
|
|
2812
2869
|
if (isDelimiterLine(text, lineStart, end, heredoc)) {
|
|
2813
2870
|
const body = { command: heredoc.command, start, text: text.slice(start, lineStart) };
|
|
@@ -2876,7 +2933,7 @@ const USES = {
|
|
|
2876
2933
|
"=": "assign",
|
|
2877
2934
|
"+": "alternative"
|
|
2878
2935
|
};
|
|
2879
|
-
const SINGLE_QUOTE = "'";
|
|
2936
|
+
const SINGLE_QUOTE$1 = "'";
|
|
2880
2937
|
const BACKSLASH$1 = "\\";
|
|
2881
2938
|
function expansionAt(text, start) {
|
|
2882
2939
|
const head = EXPANSION_HEAD_RE.exec(text.slice(start));
|
|
@@ -2898,8 +2955,8 @@ function wordExpansions(raw) {
|
|
|
2898
2955
|
const found = [];
|
|
2899
2956
|
for (let index = 0; index < raw.length; ) {
|
|
2900
2957
|
const char = raw[index];
|
|
2901
|
-
if (char === SINGLE_QUOTE) {
|
|
2902
|
-
const close = raw.indexOf(SINGLE_QUOTE, index + 1);
|
|
2958
|
+
if (char === SINGLE_QUOTE$1) {
|
|
2959
|
+
const close = raw.indexOf(SINGLE_QUOTE$1, index + 1);
|
|
2903
2960
|
index = close === -1 ? raw.length : close + 1;
|
|
2904
2961
|
} else if (char === BACKSLASH$1) {
|
|
2905
2962
|
index += 2;
|
|
@@ -2913,17 +2970,45 @@ function wordExpansions(raw) {
|
|
|
2913
2970
|
}
|
|
2914
2971
|
return found;
|
|
2915
2972
|
}
|
|
2916
|
-
const DOUBLE_QUOTE = '"';
|
|
2973
|
+
const DOUBLE_QUOTE$1 = '"';
|
|
2917
2974
|
function wholeWordExpansion(raw) {
|
|
2918
|
-
const isQuoted = raw.length > 1 && raw.startsWith(DOUBLE_QUOTE) && raw.endsWith(DOUBLE_QUOTE);
|
|
2975
|
+
const isQuoted = raw.length > 1 && raw.startsWith(DOUBLE_QUOTE$1) && raw.endsWith(DOUBLE_QUOTE$1);
|
|
2919
2976
|
const inner = isQuoted ? 1 : 0;
|
|
2920
2977
|
const [expansion] = wordExpansions(raw);
|
|
2921
2978
|
const isWhole = expansion?.expansionStart === inner && expansion.expansionEnd === raw.length - inner;
|
|
2922
2979
|
return isWhole ? expansion : void 0;
|
|
2923
2980
|
}
|
|
2924
2981
|
|
|
2982
|
+
const SHELLS = /* @__PURE__ */ new Set(["sh", "bash", "dash", "ash", "zsh", "ksh"]);
|
|
2983
|
+
const OPTION_PREFIXES = ["-", "+"];
|
|
2984
|
+
const SHORT_OPTION_PREFIX = "-";
|
|
2985
|
+
const LONG_OPTION_PREFIX = "--";
|
|
2986
|
+
const END_OF_OPTIONS = "--";
|
|
2987
|
+
const COMMAND_OPTION = "c";
|
|
2988
|
+
const SET_OPTIONS = /* @__PURE__ */ new Set(["-o", "+o"]);
|
|
2989
|
+
const PATH_SEPARATOR$8 = "/";
|
|
2990
|
+
const isShellOption = (word) => OPTION_PREFIXES.some((prefix) => word.startsWith(prefix));
|
|
2991
|
+
function shellScript(words) {
|
|
2992
|
+
const program = words[0]?.value.split(PATH_SEPARATOR$8).at(-1) ?? "";
|
|
2993
|
+
if (!SHELLS.has(program)) {
|
|
2994
|
+
return void 0;
|
|
2995
|
+
}
|
|
2996
|
+
let hasCommandOption = false;
|
|
2997
|
+
let index = 1;
|
|
2998
|
+
for (let word = words[index]?.value; word !== void 0; word = words[index]?.value) {
|
|
2999
|
+
if (word === END_OF_OPTIONS || !isShellOption(word)) {
|
|
3000
|
+
const script = word === END_OF_OPTIONS ? words[index + 1] : words[index];
|
|
3001
|
+
return hasCommandOption ? script : void 0;
|
|
3002
|
+
}
|
|
3003
|
+
const isShort = word.startsWith(SHORT_OPTION_PREFIX) && !word.startsWith(LONG_OPTION_PREFIX);
|
|
3004
|
+
hasCommandOption ||= isShort && word.includes(COMMAND_OPTION);
|
|
3005
|
+
index += SET_OPTIONS.has(word) ? 2 : 1;
|
|
3006
|
+
}
|
|
3007
|
+
return void 0;
|
|
3008
|
+
}
|
|
3009
|
+
|
|
2925
3010
|
const COMMENT = "#";
|
|
2926
|
-
const LINE_BREAK$
|
|
3011
|
+
const LINE_BREAK$6 = "\n";
|
|
2927
3012
|
function skipTrivia(text, index) {
|
|
2928
3013
|
const char = text[index];
|
|
2929
3014
|
if (WORD_BREAKS.has(char)) {
|
|
@@ -2953,7 +3038,7 @@ function topLevelCommands(text, indent) {
|
|
|
2953
3038
|
index = heredoc.end;
|
|
2954
3039
|
} else if (afterTrivia !== index) {
|
|
2955
3040
|
index = afterTrivia;
|
|
2956
|
-
} else if (text[index] === LINE_BREAK$
|
|
3041
|
+
} else if (text[index] === LINE_BREAK$6 && pending.length > 0) {
|
|
2957
3042
|
const read = readBodies(text, index + 1, pending);
|
|
2958
3043
|
heredocs.push(...read.bodies);
|
|
2959
3044
|
pending = [];
|
|
@@ -2973,21 +3058,23 @@ function topLevelCommands(text, indent) {
|
|
|
2973
3058
|
}
|
|
2974
3059
|
return { commands, heredocs, pipes };
|
|
2975
3060
|
}
|
|
2976
|
-
const QUOTES$
|
|
3061
|
+
const QUOTES$1 = /* @__PURE__ */ new Set(["'", '"']);
|
|
2977
3062
|
const NESTED_COMMAND_RE = /[\s;&|()`]/;
|
|
2978
|
-
function
|
|
3063
|
+
function isQuotedCommandLine(word) {
|
|
2979
3064
|
const quote = word.raw[0];
|
|
2980
|
-
const isOneQuotedString = QUOTES$
|
|
2981
|
-
return isOneQuotedString && NESTED_COMMAND_RE.test(word.value)
|
|
3065
|
+
const isOneQuotedString = QUOTES$1.has(quote) && word.raw.length > 1 && word.raw.endsWith(quote) && wordPart(word.raw, 0).end === word.raw.length;
|
|
3066
|
+
return isOneQuotedString && NESTED_COMMAND_RE.test(word.value);
|
|
3067
|
+
}
|
|
3068
|
+
function nestedCommandText(word, script) {
|
|
3069
|
+
return word === script || isQuotedCommandLine(word) ? unquotedRawText(word, 0) : void 0;
|
|
2982
3070
|
}
|
|
2983
|
-
const SHELLS$1 = /* @__PURE__ */ new Set(["sh", "bash", "dash", "ash", "zsh", "ksh"]);
|
|
2984
3071
|
const DOCKER_RUN = "RUN";
|
|
2985
3072
|
const PASS_THROUGH = "cat";
|
|
2986
|
-
const PATH_SEPARATOR$
|
|
2987
|
-
const OPTION_PREFIX
|
|
2988
|
-
const programName$1 = (command) => command[0]?.value.split(PATH_SEPARATOR$
|
|
2989
|
-
const isOption = (word) => word.value.startsWith(OPTION_PREFIX
|
|
2990
|
-
const isScriptShell = (command) => SHELLS
|
|
3073
|
+
const PATH_SEPARATOR$7 = "/";
|
|
3074
|
+
const OPTION_PREFIX = "-";
|
|
3075
|
+
const programName$1 = (command) => command[0]?.value.split(PATH_SEPARATOR$7).at(-1) ?? "";
|
|
3076
|
+
const isOption = (word) => word.value.startsWith(OPTION_PREFIX);
|
|
3077
|
+
const isScriptShell = (command) => SHELLS.has(programName$1(command)) && command.slice(1).every(isOption);
|
|
2991
3078
|
function readsScript(command) {
|
|
2992
3079
|
if (programName$1(command) !== DOCKER_RUN) {
|
|
2993
3080
|
return isScriptShell(command);
|
|
@@ -3004,9 +3091,11 @@ function scriptsRunBy(top, index, command) {
|
|
|
3004
3091
|
(body) => body.command === index && readsScript(command) || body.command === previous && isPipedScript
|
|
3005
3092
|
);
|
|
3006
3093
|
}
|
|
3007
|
-
const shifted = (words, offset) => words.map((word) => ({ ...word, start: word.start + offset, end: word.end + offset }));
|
|
3008
3094
|
function shellCommandsAt(text, offset, indent = 0) {
|
|
3009
|
-
return shellCommands(text, indent).map((words) =>
|
|
3095
|
+
return shellCommands(text, indent).map((words) => words.map((word) => movedWord(word, offset)));
|
|
3096
|
+
}
|
|
3097
|
+
function placedCommands(placed) {
|
|
3098
|
+
return shellCommands(placed.text).map((words) => words.map((word) => placedWord(word, placed)));
|
|
3010
3099
|
}
|
|
3011
3100
|
function expansionCommands(word) {
|
|
3012
3101
|
const expansions = wordExpansions(word.raw);
|
|
@@ -3014,7 +3103,7 @@ function expansionCommands(word) {
|
|
|
3014
3103
|
({ start }) => expansions.every((expansion) => start < expansion.start || start >= expansion.expansionEnd)
|
|
3015
3104
|
);
|
|
3016
3105
|
return [...expansions, ...literals].flatMap(
|
|
3017
|
-
(part) =>
|
|
3106
|
+
(part) => placedCommands(rawText(word, part.start, part.text))
|
|
3018
3107
|
);
|
|
3019
3108
|
}
|
|
3020
3109
|
function commandLineAssignments(command) {
|
|
@@ -3024,20 +3113,17 @@ function commandLineAssignments(command) {
|
|
|
3024
3113
|
];
|
|
3025
3114
|
return new Map(read.map((assignment) => [assignment.word, assignment]));
|
|
3026
3115
|
}
|
|
3027
|
-
function valueCommands$1(assignment) {
|
|
3028
|
-
const value = assignmentValue(assignment);
|
|
3029
|
-
return shellCommands(value.text).map((words) => words.map(value.place));
|
|
3030
|
-
}
|
|
3031
3116
|
function innerCommands(command) {
|
|
3032
3117
|
const assignments = commandLineAssignments(command);
|
|
3033
3118
|
const code = inlineCode(command)?.code;
|
|
3119
|
+
const script = shellScript(command);
|
|
3034
3120
|
return command.flatMap((word) => {
|
|
3035
|
-
const inner = word === code ? void 0 : nestedCommandText(word);
|
|
3121
|
+
const inner = word === code ? void 0 : nestedCommandText(word, script);
|
|
3036
3122
|
if (inner !== void 0) {
|
|
3037
|
-
return
|
|
3123
|
+
return placedCommands(inner);
|
|
3038
3124
|
}
|
|
3039
3125
|
const assignment = assignments.get(word);
|
|
3040
|
-
return assignment === void 0 ? expansionCommands(word) :
|
|
3126
|
+
return assignment === void 0 ? expansionCommands(word) : placedCommands(assignmentValue(assignment));
|
|
3041
3127
|
});
|
|
3042
3128
|
}
|
|
3043
3129
|
function shellCommands(text, indent = 0) {
|
|
@@ -3140,11 +3226,15 @@ function shellAppend(assignment, variables) {
|
|
|
3140
3226
|
}
|
|
3141
3227
|
const isOwnGeneratorCommand = (place, command) => place === "after-outside" && command !== void 0 && runsGenerator(command);
|
|
3142
3228
|
function appendedText(assignment) {
|
|
3143
|
-
|
|
3144
|
-
|
|
3229
|
+
return placedCommands(assignmentValue(assignment));
|
|
3230
|
+
}
|
|
3231
|
+
const appendsOwnGenerator = ({ assignment, place }) => isOwnGeneratorCommand(place, appendedText(assignment)[0]);
|
|
3232
|
+
function setsKnownProgram(placed, all) {
|
|
3233
|
+
const chain = all.slice(0, all.indexOf(placed) + 1).filter((earlier) => earlier.assignment.name === placed.assignment.name);
|
|
3234
|
+
return chain.some((part) => part.place !== "after-outside" || appendsOwnGenerator(part));
|
|
3145
3235
|
}
|
|
3146
3236
|
function shellAppends(commands, variables) {
|
|
3147
|
-
const appends = placedAssignments$1(commands).filter(isAfterValue).filter((
|
|
3237
|
+
const appends = placedAssignments$1(commands).filter(isAfterValue).filter((placed) => !appendsOwnGenerator(placed)).map(({ assignment }) => shellAppend(assignment, variables));
|
|
3148
3238
|
const taken = new Set(appends.flatMap(({ command }) => command === void 0 ? [] : [command]));
|
|
3149
3239
|
const isTaken = (command) => [...taken].some(
|
|
3150
3240
|
(found) => found.length === command.length && found[0]?.start === command[0]?.start
|
|
@@ -3155,23 +3245,29 @@ function shellAppends(commands, variables) {
|
|
|
3155
3245
|
};
|
|
3156
3246
|
}
|
|
3157
3247
|
|
|
3248
|
+
const passedFlag = (text) => text.split("=", 1)[0];
|
|
3158
3249
|
function flagFindings(word, locate) {
|
|
3159
|
-
const
|
|
3250
|
+
const passed = unquotedRawText(word, 0);
|
|
3251
|
+
const flag = passedFlag(passed.text);
|
|
3160
3252
|
const to = FLAG_RENAMES.get(flag);
|
|
3161
3253
|
if (to === void 0) {
|
|
3162
3254
|
return [];
|
|
3163
3255
|
}
|
|
3164
3256
|
const offset = word.start;
|
|
3165
|
-
const
|
|
3166
|
-
|
|
3167
|
-
|
|
3168
|
-
|
|
3257
|
+
const location = locate(offset);
|
|
3258
|
+
const span = placedSpan(passed, flag.length);
|
|
3259
|
+
if (span === void 0) {
|
|
3260
|
+
const manualStep = { kind: "split-flag", location, flag };
|
|
3261
|
+
return [{ offset, manualStep }];
|
|
3262
|
+
}
|
|
3263
|
+
const edit = { ...span, text: to };
|
|
3264
|
+
return [{ offset, edit, change: { kind: "flag-renamed", location, from: flag, to } }];
|
|
3169
3265
|
}
|
|
3170
3266
|
function renamedFlags(value) {
|
|
3171
|
-
const flags = shellCommands(value).flat().map((word) => word.
|
|
3267
|
+
const flags = shellCommands(value).flat().map((word) => passedFlag(word.value));
|
|
3172
3268
|
return [...new Set(flags.filter((flag) => FLAG_RENAMES.has(flag)))];
|
|
3173
3269
|
}
|
|
3174
|
-
function argumentFindings
|
|
3270
|
+
function argumentFindings(word, locate, variables) {
|
|
3175
3271
|
const reference = variables.referenceAt(word);
|
|
3176
3272
|
if (reference === void 0) {
|
|
3177
3273
|
return flagFindings(word, locate);
|
|
@@ -3195,7 +3291,7 @@ const oldFlagsOf = (findings) => findings.flatMap(({ change, manualStep }) => {
|
|
|
3195
3291
|
return manualStep?.kind === "flags-in-variable" ? [...manualStep.flags] : [];
|
|
3196
3292
|
});
|
|
3197
3293
|
function programArgumentFindings(words, { offset, use }, locate, variables) {
|
|
3198
|
-
const found = words.flatMap((word) => argumentFindings
|
|
3294
|
+
const found = words.flatMap((word) => argumentFindings(word, locate, variables));
|
|
3199
3295
|
if (use?.program !== "generator-or-other") {
|
|
3200
3296
|
return found;
|
|
3201
3297
|
}
|
|
@@ -3219,20 +3315,6 @@ function appendedValueFindings({ words, program }, locate, variables) {
|
|
|
3219
3315
|
return [...found, ...unmigratedWordFindings(words, handled, locate)];
|
|
3220
3316
|
}
|
|
3221
3317
|
|
|
3222
|
-
const PATH_SEPARATOR$8 = "/";
|
|
3223
|
-
const WINDOWS_SEPARATOR_RE = /\\/g;
|
|
3224
|
-
const QUOTE_RE = /["']/g;
|
|
3225
|
-
const WINDOWS_PATH_RE = /^[^/]*[^\\/\s]\\[^\\/\s][^/]*$/;
|
|
3226
|
-
function programPath(word) {
|
|
3227
|
-
const suffix = windowsSuffix(word.value);
|
|
3228
|
-
const written = word.raw.replace(QUOTE_RE, "");
|
|
3229
|
-
const isWindowsPath = suffix !== "" || WINDOWS_PATH_RE.test(written);
|
|
3230
|
-
if (!isWindowsPath) {
|
|
3231
|
-
return { path: word.value, suffix, written: word.value };
|
|
3232
|
-
}
|
|
3233
|
-
return { path: written.replace(WINDOWS_SEPARATOR_RE, PATH_SEPARATOR$8), suffix, written };
|
|
3234
|
-
}
|
|
3235
|
-
|
|
3236
3318
|
const SHELL_VARIABLE_RE$1 = /^"?\$(?:([A-Za-z_][A-Za-z0-9_]*)|\{([A-Za-z_][A-Za-z0-9_]*)\})"?$/;
|
|
3237
3319
|
function expandedName$1(text) {
|
|
3238
3320
|
const match = SHELL_VARIABLE_RE$1.exec(text);
|
|
@@ -3257,8 +3339,12 @@ function expansionDefinitions(name, expansion) {
|
|
|
3257
3339
|
const variable = isOutside ? { name, kind: "command", runsGenerator: false } : { name, kind: "reference", target: expansion.name };
|
|
3258
3340
|
return [word, variable];
|
|
3259
3341
|
}
|
|
3260
|
-
function programDefinitions$1(
|
|
3261
|
-
|
|
3342
|
+
function programDefinitions$1(definition) {
|
|
3343
|
+
const { name, value } = definition;
|
|
3344
|
+
if (definition.isAfterOutside === true) {
|
|
3345
|
+
return [{ name, kind: "run-time" }];
|
|
3346
|
+
}
|
|
3347
|
+
if (definition.isAppended === true) {
|
|
3262
3348
|
return [{ name, kind: "no-program" }];
|
|
3263
3349
|
}
|
|
3264
3350
|
const expansion = wholeWordExpansion(value.trim());
|
|
@@ -3297,12 +3383,14 @@ function assignedByExpansions(commands) {
|
|
|
3297
3383
|
]);
|
|
3298
3384
|
}
|
|
3299
3385
|
function withShellAssignments(commands, file) {
|
|
3300
|
-
const
|
|
3301
|
-
|
|
3302
|
-
|
|
3386
|
+
const placed = placedAssignments$1(commands);
|
|
3387
|
+
const assigned = placed.flatMap((entry) => {
|
|
3388
|
+
const { assignment } = entry;
|
|
3389
|
+
if (isArrayAssignment(assignment) || !setsKnownProgram(entry, placed)) {
|
|
3303
3390
|
return [];
|
|
3304
3391
|
}
|
|
3305
|
-
|
|
3392
|
+
const { name, value } = assignment;
|
|
3393
|
+
return appendsOwnGenerator(entry) ? [{ name, value, isAfterOutside: true }] : [{ name, value, isAppended: isAfterValue(entry) }];
|
|
3306
3394
|
});
|
|
3307
3395
|
const definitions = [...assigned, ...assignedByExpansions(commands)];
|
|
3308
3396
|
if (definitions.length === 0) {
|
|
@@ -3350,18 +3438,19 @@ function withUnreadVariables(variables) {
|
|
|
3350
3438
|
};
|
|
3351
3439
|
}
|
|
3352
3440
|
|
|
3353
|
-
const QUOTES
|
|
3354
|
-
const PATH_SEPARATOR$
|
|
3441
|
+
const QUOTES = /* @__PURE__ */ new Set(["'", '"']);
|
|
3442
|
+
const PATH_SEPARATOR$6 = "/";
|
|
3355
3443
|
const BIN_FOLDER = "/.bin/";
|
|
3356
3444
|
const OLD_PACKAGE_FOLDER = `node_modules/${GENERATOR_COMMAND}/`;
|
|
3357
3445
|
function renameAtEnd(word, name, to, suffix = "") {
|
|
3358
3446
|
const at = word.raw.lastIndexOf(name);
|
|
3359
3447
|
const tail = word.raw.slice(at + name.length);
|
|
3360
3448
|
const quote = tail.slice(suffix.length);
|
|
3361
|
-
if (at === -1 || quote !== "" && !QUOTES
|
|
3449
|
+
if (at === -1 || quote !== "" && !QUOTES.has(quote)) {
|
|
3362
3450
|
return void 0;
|
|
3363
3451
|
}
|
|
3364
|
-
|
|
3452
|
+
const span = writtenSpan(word, at, name.length);
|
|
3453
|
+
return span === void 0 ? void 0 : { ...span, text: to };
|
|
3365
3454
|
}
|
|
3366
3455
|
function packageFindings(found, locate) {
|
|
3367
3456
|
const { name, isPinned } = packageReference(found.value);
|
|
@@ -3386,7 +3475,7 @@ function programPathFindings(word, program, location) {
|
|
|
3386
3475
|
}
|
|
3387
3476
|
if (!path.endsWith(`${BIN_FOLDER}${GENERATOR_COMMAND}${suffix}`)) {
|
|
3388
3477
|
const manualStep = { kind: "old-name-in-command", location, word: written };
|
|
3389
|
-
const isGenerator = path.endsWith(`${PATH_SEPARATOR$
|
|
3478
|
+
const isGenerator = path.endsWith(`${PATH_SEPARATOR$6}${GENERATOR_COMMAND}${suffix}`);
|
|
3390
3479
|
return isGenerator ? [{ offset, manualStep }] : [];
|
|
3391
3480
|
}
|
|
3392
3481
|
const edit = renameAtEnd(word, GENERATOR_COMMAND, MIGRATED_GENERATOR_COMMAND, suffix);
|
|
@@ -3394,7 +3483,7 @@ function programPathFindings(word, program, location) {
|
|
|
3394
3483
|
}
|
|
3395
3484
|
function programFindings(word, location) {
|
|
3396
3485
|
const program = programPath(word);
|
|
3397
|
-
if (program.path.includes(PATH_SEPARATOR$
|
|
3486
|
+
if (program.path.includes(PATH_SEPARATOR$6)) {
|
|
3398
3487
|
return programPathFindings(word, program, location);
|
|
3399
3488
|
}
|
|
3400
3489
|
const { path, suffix } = program;
|
|
@@ -3459,8 +3548,17 @@ function commandWordFindings(commands, locate, variables = NO_VARIABLES, appende
|
|
|
3459
3548
|
)
|
|
3460
3549
|
]);
|
|
3461
3550
|
}
|
|
3551
|
+
function uniqueFindings(found) {
|
|
3552
|
+
const seen = /* @__PURE__ */ new Set();
|
|
3553
|
+
return found.filter((finding) => {
|
|
3554
|
+
const key = JSON.stringify(finding);
|
|
3555
|
+
const isNew = !seen.has(key);
|
|
3556
|
+
seen.add(key);
|
|
3557
|
+
return isNew;
|
|
3558
|
+
});
|
|
3559
|
+
}
|
|
3462
3560
|
function textFindings(found) {
|
|
3463
|
-
const findings =
|
|
3561
|
+
const findings = uniqueFindings(found).sort((left, right) => left.offset - right.offset);
|
|
3464
3562
|
return {
|
|
3465
3563
|
edits: findings.flatMap((finding) => finding.edit === void 0 ? [] : [finding.edit]),
|
|
3466
3564
|
changes: findings.flatMap((finding) => finding.change === void 0 ? [] : [finding.change]),
|
|
@@ -3600,13 +3698,13 @@ const NO_LONGER_INSTALLED = /* @__PURE__ */ new Map([
|
|
|
3600
3698
|
const ORIGINAL_NAMES = new Map(
|
|
3601
3699
|
[...PACKAGE_RENAMES].map(([original, successor]) => [successor, original])
|
|
3602
3700
|
);
|
|
3603
|
-
const PATH_SEPARATOR$
|
|
3701
|
+
const PATH_SEPARATOR$5 = "/";
|
|
3604
3702
|
function namesUninstalledPackage(text) {
|
|
3605
3703
|
return [...NO_LONGER_INSTALLED.keys()].some(
|
|
3606
3704
|
(name) => text.includes(name) || text.includes(ORIGINAL_NAMES.get(name) ?? name)
|
|
3607
3705
|
);
|
|
3608
3706
|
}
|
|
3609
|
-
const directoryOf = (path) => path.slice(0, path.lastIndexOf(PATH_SEPARATOR$
|
|
3707
|
+
const directoryOf = (path) => path.slice(0, path.lastIndexOf(PATH_SEPARATOR$5) + 1);
|
|
3610
3708
|
const isAtOrAbove = (path, filePath) => filePath.startsWith(directoryOf(path));
|
|
3611
3709
|
function declaredNames(manifest) {
|
|
3612
3710
|
return DEPENDENCY_FIELDS.flatMap((field) => mapsAt(manifest, field)).flatMap(textEntries).map(({ key }) => key.value);
|
|
@@ -3631,7 +3729,7 @@ function isDeclaredFor(manifests, filePath, name) {
|
|
|
3631
3729
|
return containing.length === 0 || containing.some(declares);
|
|
3632
3730
|
}
|
|
3633
3731
|
const packageOfSpecifier = (specifier) => {
|
|
3634
|
-
const slash = specifier.indexOf(PATH_SEPARATOR$
|
|
3732
|
+
const slash = specifier.indexOf(PATH_SEPARATOR$5);
|
|
3635
3733
|
return slash === -1 ? specifier : specifier.slice(0, slash);
|
|
3636
3734
|
};
|
|
3637
3735
|
function undeclaredImportSteps(imports, filePath, manifests) {
|
|
@@ -3642,28 +3740,23 @@ function undeclaredImportSteps(imports, filePath, manifests) {
|
|
|
3642
3740
|
});
|
|
3643
3741
|
}
|
|
3644
3742
|
|
|
3645
|
-
const
|
|
3646
|
-
|
|
3647
|
-
|
|
3648
|
-
|
|
3649
|
-
|
|
3650
|
-
|
|
3651
|
-
|
|
3652
|
-
|
|
3653
|
-
|
|
3654
|
-
|
|
3655
|
-
|
|
3656
|
-
|
|
3657
|
-
|
|
3658
|
-
|
|
3659
|
-
|
|
3660
|
-
|
|
3661
|
-
|
|
3662
|
-
return words[index + 1];
|
|
3663
|
-
}
|
|
3664
|
-
index += option === SET_OPTION ? 2 : 1;
|
|
3665
|
-
}
|
|
3666
|
-
return void 0;
|
|
3743
|
+
const ARGUMENTS_WORDS = new Set(
|
|
3744
|
+
["$", "$$"].flatMap(
|
|
3745
|
+
(dollar) => ["@", "{@}"].flatMap((name) => ["", '"'].map((quote) => `${quote}${dollar}${name}${quote}`))
|
|
3746
|
+
)
|
|
3747
|
+
);
|
|
3748
|
+
function runsArguments(script) {
|
|
3749
|
+
return shellCommands(script).some((words) => {
|
|
3750
|
+
const { program } = commandRoles(words);
|
|
3751
|
+
return program !== void 0 && ARGUMENTS_WORDS.has(words[program]?.raw ?? "");
|
|
3752
|
+
});
|
|
3753
|
+
}
|
|
3754
|
+
function runsItsCommand(entrypoint) {
|
|
3755
|
+
const script = shellScript(entrypoint);
|
|
3756
|
+
return script === void 0 || runsArguments(script.value);
|
|
3757
|
+
}
|
|
3758
|
+
function containerCommand(entrypoint, command) {
|
|
3759
|
+
return runsGenerator(command) && runsItsCommand(entrypoint) ? [entrypoint, command] : [[...entrypoint, ...command]];
|
|
3667
3760
|
}
|
|
3668
3761
|
function entrypointProgram(entrypoint) {
|
|
3669
3762
|
const script = shellScript(entrypoint);
|
|
@@ -3714,12 +3807,17 @@ function entrypointOf(stages, index) {
|
|
|
3714
3807
|
const base = baseStage(stages, index);
|
|
3715
3808
|
return own ?? (base === -1 ? void 0 : entrypointOf(stages, base));
|
|
3716
3809
|
}
|
|
3717
|
-
function
|
|
3810
|
+
function entrypointPairs(text, forms) {
|
|
3718
3811
|
const stages = dockerStages(text, forms);
|
|
3719
3812
|
return stages.flatMap((stage, index) => {
|
|
3720
3813
|
const entrypoint = entrypointOf(stages, index)?.form;
|
|
3721
3814
|
const command = stage.command?.form;
|
|
3722
|
-
|
|
3815
|
+
return entrypoint === void 0 || command === void 0 ? [] : [{ entrypoint, command }];
|
|
3816
|
+
});
|
|
3817
|
+
}
|
|
3818
|
+
function entrypointCommandFindings(pairs, locate) {
|
|
3819
|
+
return pairs.flatMap(({ entrypoint, command }) => {
|
|
3820
|
+
if (shellScript(entrypoint.words) === void 0) {
|
|
3723
3821
|
return [];
|
|
3724
3822
|
}
|
|
3725
3823
|
const pair = { entrypoint: entrypoint.words, command: command.words };
|
|
@@ -3727,16 +3825,140 @@ function entrypointCommandFindings(text, forms, locate) {
|
|
|
3727
3825
|
});
|
|
3728
3826
|
}
|
|
3729
3827
|
|
|
3828
|
+
const DEFAULT_ESCAPE = "\\";
|
|
3829
|
+
const DIRECTIVE_RE = /^#[ \t]*([A-Za-z]+)[ \t]*=[ \t]*(\S+)[ \t]*$/;
|
|
3830
|
+
const ESCAPE_DIRECTIVE = "escape";
|
|
3831
|
+
const LINE_BREAK$5 = "\n";
|
|
3832
|
+
const CARRIAGE_RETURN = "\r";
|
|
3833
|
+
const BLANKS = /* @__PURE__ */ new Set([" ", " ", CARRIAGE_RETURN, LINE_BREAK$5]);
|
|
3834
|
+
const SINGLE_QUOTE = "'";
|
|
3835
|
+
const DOUBLE_QUOTE = '"';
|
|
3836
|
+
const DOUBLE_QUOTE_ESCAPES = /* @__PURE__ */ new Set([DOUBLE_QUOTE, "$"]);
|
|
3837
|
+
const ASSIGNMENT$1 = "=";
|
|
3838
|
+
const VARIABLE_INSTRUCTIONS = /* @__PURE__ */ new Set(["ARG", "ENV"]);
|
|
3839
|
+
const LEGACY_ENV_INSTRUCTION = "ENV";
|
|
3840
|
+
function escapeCharacter(text) {
|
|
3841
|
+
for (const line of text.split(LINE_BREAK$5)) {
|
|
3842
|
+
const directive = DIRECTIVE_RE.exec(line.replace(CARRIAGE_RETURN, ""));
|
|
3843
|
+
if (directive === null) {
|
|
3844
|
+
return DEFAULT_ESCAPE;
|
|
3845
|
+
}
|
|
3846
|
+
if (directive[1]?.toLowerCase() === ESCAPE_DIRECTIVE) {
|
|
3847
|
+
return directive[2];
|
|
3848
|
+
}
|
|
3849
|
+
}
|
|
3850
|
+
return DEFAULT_ESCAPE;
|
|
3851
|
+
}
|
|
3852
|
+
function instructionEnd(text, index, escapeMark) {
|
|
3853
|
+
for (let end = text.indexOf(LINE_BREAK$5, index); end !== -1; ) {
|
|
3854
|
+
if (!text.slice(index, end).trimEnd().endsWith(escapeMark)) {
|
|
3855
|
+
return end;
|
|
3856
|
+
}
|
|
3857
|
+
index = end + 1;
|
|
3858
|
+
end = text.indexOf(LINE_BREAK$5, index);
|
|
3859
|
+
}
|
|
3860
|
+
return text.length;
|
|
3861
|
+
}
|
|
3862
|
+
const add = (word, text, index) => {
|
|
3863
|
+
word.value += text[index];
|
|
3864
|
+
word.offsets.push(index);
|
|
3865
|
+
};
|
|
3866
|
+
function isContinuation(text, index, escapeMark) {
|
|
3867
|
+
const lineEnd = text.indexOf(LINE_BREAK$5, index);
|
|
3868
|
+
return text[index] === escapeMark && lineEnd !== -1 && text.slice(index + 1, lineEnd).trim() === "";
|
|
3869
|
+
}
|
|
3870
|
+
function isQuotedEscape(text, index, escapeMark) {
|
|
3871
|
+
const next = text[index + 1] ?? "";
|
|
3872
|
+
return text[index] === escapeMark && (DOUBLE_QUOTE_ESCAPES.has(next) || next === escapeMark);
|
|
3873
|
+
}
|
|
3874
|
+
function readQuoted(text, index, word, escapeMark) {
|
|
3875
|
+
const quote = text[index];
|
|
3876
|
+
let at = index + 1;
|
|
3877
|
+
for (; at < text.length && text[at] !== quote; at++) {
|
|
3878
|
+
if (isContinuation(text, at, escapeMark)) {
|
|
3879
|
+
at = text.indexOf(LINE_BREAK$5, at);
|
|
3880
|
+
} else {
|
|
3881
|
+
at += quote === DOUBLE_QUOTE && isQuotedEscape(text, at, escapeMark) ? 1 : 0;
|
|
3882
|
+
add(word, text, at);
|
|
3883
|
+
}
|
|
3884
|
+
}
|
|
3885
|
+
return at + 1;
|
|
3886
|
+
}
|
|
3887
|
+
function readPart(text, index, word, escapeMark) {
|
|
3888
|
+
const char = text[index];
|
|
3889
|
+
if (char === SINGLE_QUOTE || char === DOUBLE_QUOTE) {
|
|
3890
|
+
return readQuoted(text, index, word, escapeMark);
|
|
3891
|
+
}
|
|
3892
|
+
const end = index + (char === escapeMark && index + 1 < text.length ? 2 : 1);
|
|
3893
|
+
add(word, text, end - 1);
|
|
3894
|
+
return end;
|
|
3895
|
+
}
|
|
3896
|
+
function endWord(word, words) {
|
|
3897
|
+
const value = word.value.trimEnd();
|
|
3898
|
+
if (value !== "") {
|
|
3899
|
+
words.push({ text: value, offsets: word.offsets.slice(0, value.length) });
|
|
3900
|
+
}
|
|
3901
|
+
return { value: "", offsets: [] };
|
|
3902
|
+
}
|
|
3903
|
+
function dockerWords(text, range, escapeMark, isWhole = false) {
|
|
3904
|
+
const words = [];
|
|
3905
|
+
const instruction = text.slice(0, range.end);
|
|
3906
|
+
let word = { value: "", offsets: [] };
|
|
3907
|
+
for (let index = range.start; index < range.end; ) {
|
|
3908
|
+
if (isContinuation(text, index, escapeMark)) {
|
|
3909
|
+
index = text.indexOf(LINE_BREAK$5, index) + 1;
|
|
3910
|
+
} else if (BLANKS.has(text[index]) && (!isWhole || word.value === "")) {
|
|
3911
|
+
word = endWord(word, words);
|
|
3912
|
+
index++;
|
|
3913
|
+
} else {
|
|
3914
|
+
index = readPart(instruction, index, word, escapeMark);
|
|
3915
|
+
}
|
|
3916
|
+
}
|
|
3917
|
+
endWord(word, words);
|
|
3918
|
+
return words;
|
|
3919
|
+
}
|
|
3920
|
+
function assignedVariable({ text, offsets }) {
|
|
3921
|
+
const at = text.indexOf(ASSIGNMENT$1);
|
|
3922
|
+
if (at <= 0) {
|
|
3923
|
+
return [];
|
|
3924
|
+
}
|
|
3925
|
+
return [
|
|
3926
|
+
{
|
|
3927
|
+
name: text.slice(0, at),
|
|
3928
|
+
value: { text: text.slice(at + 1), offsets: offsets.slice(at + 1) }
|
|
3929
|
+
}
|
|
3930
|
+
];
|
|
3931
|
+
}
|
|
3932
|
+
function instructionVariables(text, keyword, range, escapeMark) {
|
|
3933
|
+
const [first, ...rest] = dockerWords(text, range, escapeMark);
|
|
3934
|
+
if (first === void 0) {
|
|
3935
|
+
return [];
|
|
3936
|
+
}
|
|
3937
|
+
if (keyword === LEGACY_ENV_INSTRUCTION && !first.text.includes(ASSIGNMENT$1)) {
|
|
3938
|
+
const valueStart = rest[0]?.offsets[0] ?? range.end;
|
|
3939
|
+
const [value] = dockerWords(text, { start: valueStart, end: range.end }, escapeMark, true);
|
|
3940
|
+
return [{ name: first.text, value: value ?? { text: "", offsets: [] } }];
|
|
3941
|
+
}
|
|
3942
|
+
return [first, ...rest].flatMap(assignedVariable);
|
|
3943
|
+
}
|
|
3944
|
+
function variableInstructions(text, commands) {
|
|
3945
|
+
const escapeMark = escapeCharacter(text);
|
|
3946
|
+
return commands.flatMap(([keyword]) => {
|
|
3947
|
+
if (keyword === void 0 || !VARIABLE_INSTRUCTIONS.has(keyword.value)) {
|
|
3948
|
+
return [];
|
|
3949
|
+
}
|
|
3950
|
+
const range = { start: keyword.end, end: instructionEnd(text, keyword.end, escapeMark) };
|
|
3951
|
+
const variables = instructionVariables(text, keyword.value, range, escapeMark);
|
|
3952
|
+
return [{ start: keyword.start, end: range.end, variables }];
|
|
3953
|
+
});
|
|
3954
|
+
}
|
|
3955
|
+
|
|
3730
3956
|
const EXEC_FORM_START_RE = /^[ \t]*(?:RUN|CMD|ENTRYPOINT)(?:[ \t]+--\S+)*[ \t]+\[/gm;
|
|
3731
3957
|
const ARRAY_BLANK_RE = /(?:[ \t\r\n]|\\\r?\n)*/y;
|
|
3732
3958
|
const QUOTED_RE = /"(?:[^"\\\n]|\\.)*"/y;
|
|
3733
3959
|
const ITEM_SEPARATOR = ",";
|
|
3734
3960
|
const NOT_LINE_BREAK_RE$1 = /[^\n]/g;
|
|
3735
3961
|
const ARRAY_END = "]";
|
|
3736
|
-
const VARIABLE_INSTRUCTIONS = /* @__PURE__ */ new Set(["ARG", "ENV"]);
|
|
3737
|
-
const LEGACY_ENV_INSTRUCTION = "ENV";
|
|
3738
|
-
const ASSIGNMENT$1 = "=";
|
|
3739
|
-
const QUOTES = /* @__PURE__ */ new Set(['"', "'"]);
|
|
3740
3962
|
function matchAt(pattern, text, index) {
|
|
3741
3963
|
pattern.lastIndex = index;
|
|
3742
3964
|
return pattern.exec(text)?.[0];
|
|
@@ -3783,10 +4005,15 @@ function execForms(text) {
|
|
|
3783
4005
|
return form === void 0 ? [] : [{ ...form, lineStart: match.index }];
|
|
3784
4006
|
});
|
|
3785
4007
|
}
|
|
3786
|
-
function execCommands(forms) {
|
|
4008
|
+
function execCommands(forms, pairs) {
|
|
4009
|
+
const paired = new Set(pairs.map((pair) => pair.command));
|
|
3787
4010
|
const commands = [];
|
|
3788
4011
|
const escaped = [];
|
|
3789
|
-
|
|
4012
|
+
const read = [
|
|
4013
|
+
...forms.filter((form) => !paired.has(form)).map((form) => form.words),
|
|
4014
|
+
...pairs.flatMap((pair) => containerCommand(pair.entrypoint.words, pair.command.words))
|
|
4015
|
+
];
|
|
4016
|
+
for (const words of read) {
|
|
3790
4017
|
commands.push(words);
|
|
3791
4018
|
const script = shellScript(words);
|
|
3792
4019
|
if (script !== void 0 && script.raw === script.value) {
|
|
@@ -3795,7 +4022,8 @@ function execCommands(forms) {
|
|
|
3795
4022
|
escaped.push(script);
|
|
3796
4023
|
}
|
|
3797
4024
|
}
|
|
3798
|
-
|
|
4025
|
+
const scripts = new Map(escaped.map((script) => [script.start, script]));
|
|
4026
|
+
return { commands, escaped: [...scripts.values()] };
|
|
3799
4027
|
}
|
|
3800
4028
|
function withoutExecForms(text, forms) {
|
|
3801
4029
|
const parts = [];
|
|
@@ -3816,39 +4044,6 @@ function escapedScriptSteps(scripts, lineOf) {
|
|
|
3816
4044
|
return migrated === script.value ? [] : [{ kind: "command-string", line: lineOf(script.start), to: migrated }];
|
|
3817
4045
|
});
|
|
3818
4046
|
}
|
|
3819
|
-
function assignedVariable(word) {
|
|
3820
|
-
const at = word.raw.indexOf(ASSIGNMENT$1);
|
|
3821
|
-
if (at <= 0) {
|
|
3822
|
-
return void 0;
|
|
3823
|
-
}
|
|
3824
|
-
const raw = word.raw.slice(at + 1);
|
|
3825
|
-
const isQuoted = raw.length >= 2 && QUOTES.has(raw[0]) && raw.at(-1) === raw[0];
|
|
3826
|
-
const value = isQuoted ? raw.slice(1, -1) : raw;
|
|
3827
|
-
const start = word.start + at + 1 + (isQuoted ? 1 : 0);
|
|
3828
|
-
return { name: word.raw.slice(0, at), value, start };
|
|
3829
|
-
}
|
|
3830
|
-
function instructionVariables(text, words) {
|
|
3831
|
-
const [instruction, first, ...rest] = words;
|
|
3832
|
-
const last = rest.at(-1);
|
|
3833
|
-
if (instruction.value === LEGACY_ENV_INSTRUCTION && !first.raw.includes(ASSIGNMENT$1)) {
|
|
3834
|
-
const value = last === void 0 ? "" : text.slice(rest[0]?.start, last.end);
|
|
3835
|
-
return [{ name: first.value, value, start: rest[0]?.start ?? first.end }];
|
|
3836
|
-
}
|
|
3837
|
-
return [first, ...rest].flatMap((word) => assignedVariable(word) ?? []);
|
|
3838
|
-
}
|
|
3839
|
-
function variableInstructions(text, commands) {
|
|
3840
|
-
return commands.flatMap((words) => {
|
|
3841
|
-
const [instruction, first] = words;
|
|
3842
|
-
if (instruction === void 0 || first === void 0) {
|
|
3843
|
-
return [];
|
|
3844
|
-
}
|
|
3845
|
-
if (!VARIABLE_INSTRUCTIONS.has(instruction.value)) {
|
|
3846
|
-
return [];
|
|
3847
|
-
}
|
|
3848
|
-
const end = words.at(-1).end;
|
|
3849
|
-
return [{ start: instruction.start, end, variables: instructionVariables(text, words) }];
|
|
3850
|
-
});
|
|
3851
|
-
}
|
|
3852
4047
|
function withoutVariableInstructions(commands, instructions) {
|
|
3853
4048
|
const isInInstruction = (words) => {
|
|
3854
4049
|
const start = words[0]?.start ?? -1;
|
|
@@ -3858,20 +4053,21 @@ function withoutVariableInstructions(commands, instructions) {
|
|
|
3858
4053
|
};
|
|
3859
4054
|
return commands.filter((words) => !isInInstruction(words));
|
|
3860
4055
|
}
|
|
3861
|
-
const valueCommands = ({ value, start }) => shellCommandsAt(value, start);
|
|
3862
4056
|
function migrateDockerfile(text, file) {
|
|
3863
4057
|
const lineOf = lineLocator(text);
|
|
3864
4058
|
const locate = (offset) => `${file}:${lineOf(offset)}`;
|
|
3865
4059
|
const forms = execForms(text);
|
|
3866
|
-
const
|
|
4060
|
+
const pairs = entrypointPairs(text, forms);
|
|
4061
|
+
const exec = execCommands(forms, pairs);
|
|
3867
4062
|
const shellForm = shellCommands(withoutExecForms(text, forms));
|
|
3868
4063
|
const instructions = variableInstructions(text, shellForm);
|
|
3869
|
-
const
|
|
3870
|
-
const
|
|
4064
|
+
const variables = instructions.flatMap((instruction) => instruction.variables);
|
|
4065
|
+
const definitions = variables.map(({ name, value }) => ({ name, value: value.text }));
|
|
4066
|
+
const values = variables.flatMap(({ value }) => placedCommands(value));
|
|
3871
4067
|
const run = withoutVariableInstructions(shellForm, instructions);
|
|
3872
4068
|
const commands = [...run, ...values, ...exec.commands];
|
|
3873
4069
|
const found = commandWordFindings(commands, locate, shellVariables(definitions));
|
|
3874
|
-
const entry = textFindings(entrypointCommandFindings(
|
|
4070
|
+
const entry = textFindings(entrypointCommandFindings(pairs, locate));
|
|
3875
4071
|
const edits = [...found.edits, ...entry.edits];
|
|
3876
4072
|
const changes = [...found.changes, ...entry.changes];
|
|
3877
4073
|
const steps = [...found.manualSteps, ...entry.manualSteps];
|
|
@@ -5011,7 +5207,7 @@ function withoutAssignmentHeads(text, assignments) {
|
|
|
5011
5207
|
}
|
|
5012
5208
|
const COMPUTED_RE = /^\$[({]/;
|
|
5013
5209
|
const isComputed = (written) => COMPUTED_RE.test(written.trim().replace(RECIPE_PREFIX_RE, ""));
|
|
5014
|
-
function referencedName(written) {
|
|
5210
|
+
function referencedName$1(written) {
|
|
5015
5211
|
const match = VARIABLE_REFERENCE_RE.exec(written.trim().replace(RECIPE_PREFIX_RE, ""));
|
|
5016
5212
|
return match === null ? void 0 : match[1] ?? match[2] ?? match[3];
|
|
5017
5213
|
}
|
|
@@ -5029,7 +5225,7 @@ function valueDefinition(text, { name, valueStart, valueEnd }, commands) {
|
|
|
5029
5225
|
return { name, kind: "no-program" };
|
|
5030
5226
|
}
|
|
5031
5227
|
const program = programWritten(text, first);
|
|
5032
|
-
const target = referencedName(program);
|
|
5228
|
+
const target = referencedName$1(program);
|
|
5033
5229
|
if (target !== void 0) {
|
|
5034
5230
|
return { name, kind: "reference", target };
|
|
5035
5231
|
}
|
|
@@ -5088,7 +5284,7 @@ function variableValues(text, assignments) {
|
|
|
5088
5284
|
}
|
|
5089
5285
|
function makefileVariables(text, assignments, programs) {
|
|
5090
5286
|
const values = variableValues(text, assignments);
|
|
5091
|
-
const nameAt = (word) => referencedName(text.slice(word.start, word.end));
|
|
5287
|
+
const nameAt = (word) => referencedName$1(text.slice(word.start, word.end));
|
|
5092
5288
|
const variables = {
|
|
5093
5289
|
programAt: (program) => {
|
|
5094
5290
|
const written = text.slice(program.start, program.end);
|
|
@@ -5509,49 +5705,90 @@ function withInputDefaults(variables, defaults) {
|
|
|
5509
5705
|
}
|
|
5510
5706
|
|
|
5511
5707
|
const ARGUMENT_KEYS = /* @__PURE__ */ new Map([
|
|
5512
|
-
["entrypoint", "command"],
|
|
5513
|
-
["command", "args"]
|
|
5708
|
+
["entrypoint", ["command", "args"]],
|
|
5709
|
+
["command", ["args"]]
|
|
5514
5710
|
]);
|
|
5515
5711
|
const PAIRED_KEYS = /* @__PURE__ */ new Set([
|
|
5516
5712
|
...ARGUMENT_KEYS.keys(),
|
|
5517
|
-
...ARGUMENT_KEYS.values()
|
|
5713
|
+
...[...ARGUMENT_KEYS.values()].flat()
|
|
5518
5714
|
]);
|
|
5519
|
-
const
|
|
5715
|
+
const MERGE_KEY = "<<";
|
|
5520
5716
|
const LINE_BREAK = "\n";
|
|
5521
5717
|
const isItem = (string) => typeof string.path.at(-1) === "number";
|
|
5522
5718
|
const isContainerListItem = (string) => isItem(string) && PAIRED_KEYS.has(String(string.path.at(-2)));
|
|
5523
5719
|
const isList = (value) => value.strings[0] !== void 0 && isItem(value.strings[0]);
|
|
5524
|
-
|
|
5720
|
+
function mapOf(string) {
|
|
5721
|
+
const path = string.path.slice(0, isItem(string) ? -2 : -1);
|
|
5722
|
+
let isMerged = false;
|
|
5723
|
+
for (; ; ) {
|
|
5724
|
+
if (path.at(-1) === MERGE_KEY) {
|
|
5725
|
+
path.pop();
|
|
5726
|
+
} else if (typeof path.at(-1) === "number" && path.at(-2) === MERGE_KEY) {
|
|
5727
|
+
path.splice(-2);
|
|
5728
|
+
} else {
|
|
5729
|
+
return { map: JSON.stringify(path), isMerged };
|
|
5730
|
+
}
|
|
5731
|
+
isMerged = true;
|
|
5732
|
+
}
|
|
5733
|
+
}
|
|
5525
5734
|
function isNextItem(value, string) {
|
|
5526
5735
|
const last = value?.strings.at(-1);
|
|
5527
5736
|
return last !== void 0 && isItem(last) && isItem(string) && JSON.stringify(last.path.slice(0, -1)) === JSON.stringify(string.path.slice(0, -1)) && Number(string.path.at(-1)) > Number(last.path.at(-1));
|
|
5528
5737
|
}
|
|
5529
5738
|
function keyValues(strings) {
|
|
5530
5739
|
const values = [];
|
|
5531
|
-
const starts = /* @__PURE__ */ new Set();
|
|
5532
5740
|
for (const string of strings) {
|
|
5533
5741
|
const key = ownerKey(string.path) ?? "";
|
|
5534
5742
|
const isValue = isItem(string) ? string.path.at(-2) === key : string.path.at(-1) === key;
|
|
5535
|
-
if (!PAIRED_KEYS.has(key) || !isValue
|
|
5743
|
+
if (!PAIRED_KEYS.has(key) || !isValue) {
|
|
5536
5744
|
continue;
|
|
5537
5745
|
}
|
|
5538
|
-
starts.add(string.start);
|
|
5539
5746
|
const last = values.at(-1);
|
|
5540
5747
|
if (last !== void 0 && isNextItem(last, string)) {
|
|
5541
5748
|
last.strings.push(string);
|
|
5542
5749
|
} else {
|
|
5543
|
-
values.push({
|
|
5750
|
+
values.push({ ...mapOf(string), key, strings: [string] });
|
|
5544
5751
|
}
|
|
5545
5752
|
}
|
|
5546
5753
|
return values;
|
|
5547
5754
|
}
|
|
5755
|
+
function mapValues(values) {
|
|
5756
|
+
const maps = [];
|
|
5757
|
+
const latest = /* @__PURE__ */ new Map();
|
|
5758
|
+
for (const value of values) {
|
|
5759
|
+
let map = latest.get(value.map);
|
|
5760
|
+
if (map === void 0 || !value.isMerged && map.own.has(value.key)) {
|
|
5761
|
+
map = { own: /* @__PURE__ */ new Map(), merged: /* @__PURE__ */ new Map() };
|
|
5762
|
+
maps.push(map);
|
|
5763
|
+
latest.set(value.map, map);
|
|
5764
|
+
}
|
|
5765
|
+
const values2 = value.isMerged ? map.merged : map.own;
|
|
5766
|
+
if (!values2.has(value.key)) {
|
|
5767
|
+
values2.set(value.key, value);
|
|
5768
|
+
}
|
|
5769
|
+
}
|
|
5770
|
+
return maps;
|
|
5771
|
+
}
|
|
5772
|
+
function containerOf({ own, merged }) {
|
|
5773
|
+
const keyValue = (key) => own.get(key) ?? merged.get(key);
|
|
5774
|
+
for (const [key, argumentKeys] of ARGUMENT_KEYS) {
|
|
5775
|
+
const entrypoint = keyValue(key);
|
|
5776
|
+
if (entrypoint !== void 0) {
|
|
5777
|
+
const argumentKey = argumentKeys.find((found) => keyValue(found) !== void 0);
|
|
5778
|
+
return [
|
|
5779
|
+
{ entrypoint, command: argumentKey === void 0 ? void 0 : keyValue(argumentKey) }
|
|
5780
|
+
];
|
|
5781
|
+
}
|
|
5782
|
+
}
|
|
5783
|
+
return [];
|
|
5784
|
+
}
|
|
5548
5785
|
const isPlaceable = (string, text) => !string.isEscaped && !(string.isFolded && text.slice(string.content.start, string.content.end).includes(LINE_BREAK));
|
|
5549
5786
|
function scalarWords(scalar, text) {
|
|
5550
5787
|
const { start, end } = scalar.content;
|
|
5551
5788
|
const isPlaced = isPlaceable(scalar, text);
|
|
5552
|
-
const
|
|
5553
|
-
const at = (word) => isPlaced ?
|
|
5554
|
-
return { words:
|
|
5789
|
+
const commands = shellCommands(isPlaced ? text.slice(start, end) : scalar.value);
|
|
5790
|
+
const at = (word) => isPlaced ? movedWord(word, start) : { ...word, start: scalar.start, end: scalar.start };
|
|
5791
|
+
return { words: (commands[0] ?? []).map(at), isPlaced, isWhole: commands.length <= 1 };
|
|
5555
5792
|
}
|
|
5556
5793
|
function valueWords(value, text) {
|
|
5557
5794
|
const [first] = value.strings;
|
|
@@ -5562,56 +5799,37 @@ function valueWords(value, text) {
|
|
|
5562
5799
|
const { start, end } = item.content;
|
|
5563
5800
|
return { start, end, value: item.value, raw: text.slice(start, end), item };
|
|
5564
5801
|
});
|
|
5565
|
-
return { words, isPlaced: true };
|
|
5566
|
-
}
|
|
5567
|
-
function pairOf(left, right) {
|
|
5568
|
-
if (right === void 0 || left.map !== right.map) {
|
|
5569
|
-
return void 0;
|
|
5570
|
-
}
|
|
5571
|
-
if (ARGUMENT_KEYS.get(left.key) === right.key) {
|
|
5572
|
-
return [left, right];
|
|
5573
|
-
}
|
|
5574
|
-
return ARGUMENT_KEYS.get(right.key) === left.key ? [right, left] : void 0;
|
|
5575
|
-
}
|
|
5576
|
-
function containers(values) {
|
|
5577
|
-
const found = [];
|
|
5578
|
-
for (let index = 0; index < values.length; index++) {
|
|
5579
|
-
const value = values[index];
|
|
5580
|
-
const pair = pairOf(value, values[index + 1]);
|
|
5581
|
-
if (pair !== void 0) {
|
|
5582
|
-
found.push({ entrypoint: pair[0], command: pair[1] });
|
|
5583
|
-
index++;
|
|
5584
|
-
} else if (value.key !== TRAILING_KEY) {
|
|
5585
|
-
found.push({ entrypoint: value, command: void 0 });
|
|
5586
|
-
}
|
|
5587
|
-
}
|
|
5588
|
-
return found;
|
|
5589
|
-
}
|
|
5590
|
-
function listCommand({ entrypoint, command }, text) {
|
|
5591
|
-
const parts = command === void 0 ? [entrypoint] : [entrypoint, command];
|
|
5592
|
-
return parts.filter(isList).flatMap((part) => valueWords(part, text).words);
|
|
5802
|
+
return { words, isPlaced: true, isWhole: true };
|
|
5593
5803
|
}
|
|
5594
|
-
|
|
5595
|
-
|
|
5804
|
+
const isJoinable = (words) => words.isPlaced && words.isWhole;
|
|
5805
|
+
function containerReading({ entrypoint, command }, text, locate) {
|
|
5806
|
+
const first = valueWords(entrypoint, text);
|
|
5596
5807
|
if (command === void 0) {
|
|
5597
|
-
return [];
|
|
5598
|
-
}
|
|
5599
|
-
const words = valueWords(entrypoint, text).words;
|
|
5600
|
-
if (isList(entrypoint) && isList(command) && shellScript(words) === void 0) {
|
|
5601
|
-
return [];
|
|
5808
|
+
return { commands: isList(entrypoint) ? [first.words] : [], flags: [], scalars: [] };
|
|
5602
5809
|
}
|
|
5603
5810
|
const args = valueWords(command, text);
|
|
5604
|
-
const pair = { entrypoint: words, command: args.words, written: entrypoint.key };
|
|
5605
|
-
|
|
5811
|
+
const pair = { entrypoint: first.words, command: args.words, written: entrypoint.key };
|
|
5812
|
+
if (isJoinable(first) && isJoinable(args)) {
|
|
5813
|
+
const isScript = shellScript(first.words) !== void 0;
|
|
5814
|
+
return {
|
|
5815
|
+
commands: containerCommand(first.words, args.words),
|
|
5816
|
+
flags: isScript ? entrypointArgumentFindings(pair, locate) : [],
|
|
5817
|
+
scalars: [entrypoint, command].filter((part) => !isList(part)).flatMap((part) => part.strings)
|
|
5818
|
+
};
|
|
5819
|
+
}
|
|
5820
|
+
const lists = [entrypoint, command].filter(isList).map((part) => valueWords(part, text).words);
|
|
5821
|
+
const flags = entrypointArgumentFindings({ ...pair, isPlaced: args.isPlaced }, locate);
|
|
5822
|
+
return { commands: lists, flags, scalars: [] };
|
|
5606
5823
|
}
|
|
5607
5824
|
function containerCommands(text, strings, locate) {
|
|
5608
|
-
const found =
|
|
5609
|
-
const commands = found.
|
|
5825
|
+
const found = mapValues(keyValues(strings)).flatMap(containerOf).map((container) => containerReading(container, text, locate));
|
|
5826
|
+
const commands = found.flatMap((reading) => reading.commands);
|
|
5610
5827
|
const scripts = commands.flatMap((words) => shellScript(words)?.item ?? []);
|
|
5611
|
-
const flags = found.flatMap((
|
|
5828
|
+
const flags = found.flatMap((reading) => reading.flags);
|
|
5612
5829
|
return {
|
|
5613
5830
|
findings: [commandWordFindings(commands, locate), textFindings(flags)],
|
|
5614
|
-
scripts: new Set(scripts)
|
|
5831
|
+
scripts: new Set(scripts),
|
|
5832
|
+
commandStrings: new Set(found.flatMap((reading) => reading.scalars.map(({ start }) => start)))
|
|
5615
5833
|
};
|
|
5616
5834
|
}
|
|
5617
5835
|
|
|
@@ -5820,15 +6038,40 @@ const AZURE_PIPELINES_FILE = {
|
|
|
5820
6038
|
includes: AZURE_TEMPLATES
|
|
5821
6039
|
};
|
|
5822
6040
|
const ENV_EXPRESSION_RE = /\$\{\{[ \t]*env\.([A-Za-z_][A-Za-z0-9_]*)[ \t]*\}\}/g;
|
|
6041
|
+
const WORKFLOW_ENVIRONMENT = {
|
|
6042
|
+
...PLAIN,
|
|
6043
|
+
keys: /* @__PURE__ */ new Set(),
|
|
6044
|
+
reference: ENV_EXPRESSION_RE
|
|
6045
|
+
};
|
|
5823
6046
|
const asShellVariable = (reference, name) => `$${name}`.padEnd(reference.length, " ");
|
|
6047
|
+
const YAML_FILE_KINDS = [
|
|
6048
|
+
DEFAULT_YAML_FILE,
|
|
6049
|
+
GITLAB_CI_FILE,
|
|
6050
|
+
CI_ENVIRONMENT_FILE,
|
|
6051
|
+
CIRCLECI_FILE,
|
|
6052
|
+
COMPOSE_FILE,
|
|
6053
|
+
TASKFILE,
|
|
6054
|
+
AZURE_PIPELINES_FILE
|
|
6055
|
+
];
|
|
6056
|
+
const referencedName = (environment, groups) => environment.shellName(
|
|
6057
|
+
groups.find((part) => typeof part === "string") ?? "",
|
|
6058
|
+
VARIABLES_KEY
|
|
6059
|
+
);
|
|
6060
|
+
function referencedVariables(text) {
|
|
6061
|
+
const environments = [...YAML_FILE_KINDS.map((kind) => kind.environment), WORKFLOW_ENVIRONMENT];
|
|
6062
|
+
return environments.flatMap(
|
|
6063
|
+
(environment) => environment.reference === void 0 ? [] : [...text.matchAll(environment.reference)].map(
|
|
6064
|
+
(match) => referencedName(environment, match.slice(1))
|
|
6065
|
+
)
|
|
6066
|
+
);
|
|
6067
|
+
}
|
|
5824
6068
|
function withToolReferences(text, { environment, names }) {
|
|
5825
|
-
const { reference
|
|
6069
|
+
const { reference } = environment;
|
|
5826
6070
|
if (reference === void 0) {
|
|
5827
6071
|
return text;
|
|
5828
6072
|
}
|
|
5829
6073
|
return text.replace(reference, (written, ...groups) => {
|
|
5830
|
-
const
|
|
5831
|
-
const name = shellName(group, VARIABLES_KEY);
|
|
6074
|
+
const name = referencedName(environment, groups);
|
|
5832
6075
|
return names.has(name) ? asShellVariable(written, name) : written;
|
|
5833
6076
|
});
|
|
5834
6077
|
}
|
|
@@ -5995,18 +6238,21 @@ function appliedFindings(text, found) {
|
|
|
5995
6238
|
manualSteps: found.flatMap((findings) => findings.manualSteps)
|
|
5996
6239
|
};
|
|
5997
6240
|
}
|
|
5998
|
-
|
|
6241
|
+
const NO_NAMES = /* @__PURE__ */ new Set();
|
|
6242
|
+
function migrateYamlCommands(text, file, strings, reading = DEFAULT_YAML_FILE) {
|
|
6243
|
+
const { commandKeys, environment, parameters, outsideVariables = NO_NAMES } = reading;
|
|
5999
6244
|
const lineOf = lineLocator(text);
|
|
6000
6245
|
const locate = (offset) => `${file}:${lineOf(offset)}`;
|
|
6001
6246
|
const shellOf = stepShells(strings);
|
|
6002
6247
|
const values = valuesOf(strings, commandKeys).filter((value) => shellOf(value) === void 0);
|
|
6003
|
-
const
|
|
6004
|
-
const
|
|
6248
|
+
const { findings, scripts, commandStrings } = containerCommands(text, strings, locate);
|
|
6249
|
+
const isOwnCommand = (value) => !isContainerListItem(value) && !commandStrings.has(value.start);
|
|
6250
|
+
const commandValues = new Set(values.filter(isOwnCommand));
|
|
6005
6251
|
const entries = environmentEntries(strings, environment);
|
|
6006
6252
|
const defaults = parameterDefaults(strings, parameters);
|
|
6007
6253
|
const isShellText = (value) => commandValues.has(value) || scripts.has(value) || entries.has(value) || defaults.has(value);
|
|
6008
6254
|
const shellValues = oncePerPlace(strings.filter(isShellText));
|
|
6009
|
-
const names = new Set([...entries.values()].map((entry) => entry.name));
|
|
6255
|
+
const names = /* @__PURE__ */ new Set([...[...entries.values()].map((entry) => entry.name), ...outsideVariables]);
|
|
6010
6256
|
const references = { environment, names, parameters };
|
|
6011
6257
|
const inputs = inputValues(defaults);
|
|
6012
6258
|
const variablesAt = scopedVariables({ text, entries, inputs, references });
|
|
@@ -6063,7 +6309,7 @@ function listsByHook(strings, key) {
|
|
|
6063
6309
|
}
|
|
6064
6310
|
function entryWords(text, entry) {
|
|
6065
6311
|
const { start } = entry.content;
|
|
6066
|
-
return shellCommands(shellText(text, entry)).flat().map((word) => (
|
|
6312
|
+
return shellCommands(shellText(text, entry)).flat().map((word) => movedWord(word, start));
|
|
6067
6313
|
}
|
|
6068
6314
|
const itemWord = (text, item) => {
|
|
6069
6315
|
const { start, end } = item.content;
|
|
@@ -6185,7 +6431,7 @@ function usesVariable(text, names) {
|
|
|
6185
6431
|
const alternatives = [...names].map((name2) => name2.replace(SPECIAL_CHARACTERS_RE$1, "\\$&"));
|
|
6186
6432
|
const name = `(?:${alternatives.join("|")})`;
|
|
6187
6433
|
const expansion = `\\$(?:\\{|\\(|env:)?${name}${NAME_END}|%${name}%`;
|
|
6188
|
-
return new RegExp(expansion).test(text);
|
|
6434
|
+
return new RegExp(expansion).test(text) || referencedVariables(text).some((found) => names.has(found));
|
|
6189
6435
|
}
|
|
6190
6436
|
|
|
6191
6437
|
const withSteps = (migration, steps) => ({
|
|
@@ -6451,8 +6697,13 @@ const COMMAND_CONFIG_KINDS = [
|
|
|
6451
6697
|
{
|
|
6452
6698
|
matches: (path) => TASKFILE_NAMES.has(baseName(path)),
|
|
6453
6699
|
migrate: whenNamed(
|
|
6454
|
-
yamlConfig((
|
|
6455
|
-
usedStringsStep(
|
|
6700
|
+
yamlConfig((context, path) => [
|
|
6701
|
+
usedStringsStep(
|
|
6702
|
+
(text, strings) => migrateYamlCommands(text, path, strings, {
|
|
6703
|
+
...TASKFILE,
|
|
6704
|
+
outsideVariables: context.yamlReach.generatorVariables
|
|
6705
|
+
})
|
|
6706
|
+
)
|
|
6456
6707
|
])
|
|
6457
6708
|
)
|
|
6458
6709
|
},
|
|
@@ -6469,7 +6720,10 @@ const yamlCommandsStep = (path, { apiDescriptionParts, yamlReach }) => (text, re
|
|
|
6469
6720
|
const isCiFile = isCiConfigFile(path) || yamlReach.kinds.has(path);
|
|
6470
6721
|
const isApi = !isCiFile && read.kind === "read" && isApiDescription(read.documents);
|
|
6471
6722
|
return apiDescriptionParts.has(path) || isApi ? unchanged(text) : usedStringsStep(
|
|
6472
|
-
(current, strings) => migrateYamlCommands(current, path, strings,
|
|
6723
|
+
(current, strings) => migrateYamlCommands(current, path, strings, {
|
|
6724
|
+
...yamlKindOf(yamlReach, path),
|
|
6725
|
+
outsideVariables: yamlReach.generatorVariables
|
|
6726
|
+
})
|
|
6473
6727
|
)(text, read);
|
|
6474
6728
|
};
|
|
6475
6729
|
const manifestTarget = ({ version, catalogs, aliases }, path) => ({
|
|
@@ -6836,6 +7090,7 @@ const NOT_ONLY_GENERATOR_NOTE = "may run openapi-typescript or another program (
|
|
|
6836
7090
|
const OLD_NAME_IN_COMMAND_NOTE = "names an old package where the tool cannot tell what runs it (a script name, an argument of a program it does not know), so it was kept: migrate it by hand";
|
|
6837
7091
|
const SCRIPT_NOT_SHELL_NOTE = "so the tool does not read it as commands: migrate the old package names in it by hand";
|
|
6838
7092
|
const COMMAND_STRING_NOTE = "a string runs openapi-typescript, so it was kept; change it to";
|
|
7093
|
+
const SPLIT_FLAG_NOTE = "is an old flag of the generator that quotes split where it is written, so it was kept: rename";
|
|
6839
7094
|
function pinnedPackageMessage(step) {
|
|
6840
7095
|
const successor = PACKAGE_RENAMES.get(step.name) ?? step.name;
|
|
6841
7096
|
return `${step.location} names a pinned ${step.name}@<version>: change it to ${successor}@<version>`;
|
|
@@ -6854,6 +7109,7 @@ const COMMAND_STEP_KINDS = /* @__PURE__ */ new Set([
|
|
|
6854
7109
|
"pinned-package",
|
|
6855
7110
|
"old-package-file",
|
|
6856
7111
|
"old-name-in-command",
|
|
7112
|
+
"split-flag",
|
|
6857
7113
|
"script-not-shell",
|
|
6858
7114
|
"command-string"
|
|
6859
7115
|
]);
|
|
@@ -6872,6 +7128,8 @@ function commandStepMessage(step) {
|
|
|
6872
7128
|
return `${step.location}: ${step.path} ${OLD_FILE_NOTE$1}`;
|
|
6873
7129
|
case "old-name-in-command":
|
|
6874
7130
|
return `${step.location}: "${step.word}" ${OLD_NAME_IN_COMMAND_NOTE}`;
|
|
7131
|
+
case "split-flag":
|
|
7132
|
+
return `${step.location}: ${step.flag} ${SPLIT_FLAG_NOTE} ${flagRenames([step.flag])}`;
|
|
6875
7133
|
case "script-not-shell":
|
|
6876
7134
|
return `${step.location}: the script runs with ${step.shell}, ${SCRIPT_NOT_SHELL_NOTE}`;
|
|
6877
7135
|
case "command-string":
|