openapi-typesafe-migrate 1.0.0-rc.8 → 1.0.0-rc.9

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/dist/cli/main.mjs CHANGED
@@ -4,7 +4,7 @@ import { win32, posix, join, dirname, isAbsolute, relative, sep, basename, resol
4
4
  import { realpath, lstat, stat, access, readFile, writeFile, chmod, rename, rm, readdir } from 'node:fs/promises';
5
5
  import { spawn } from 'node:child_process';
6
6
  import ts from '@typescript/typescript6';
7
- import { Scalar, parseAllDocuments, isScalar as isScalar$1, isSeq, isMap as isMap$1, isNode, CST } from 'yaml';
7
+ import { Scalar, parseAllDocuments, isScalar as isScalar$1, isSeq, isMap as isMap$1, isAlias, isNode, CST } from 'yaml';
8
8
  import { parseArgs } from 'node:util';
9
9
 
10
10
  const WINDOWS = "win32";
@@ -1336,10 +1336,14 @@ function joined(elements, operator, names) {
1336
1336
  if (parts.some((part) => part === void 0)) {
1337
1337
  return void 0;
1338
1338
  }
1339
- const texts = parts.map(
1340
- (part) => operator === "&" && part.operator === "|" ? `(${part.text})` : part.text
1339
+ const members = parts.map(
1340
+ (part) => operator === "&" && part.operator === "|" ? plain$1(`(${part.text})`) : part
1341
1341
  );
1342
- return { text: texts.join(` ${operator} `), operator: texts.length > 1 ? operator : null };
1342
+ const [only] = members;
1343
+ if (members.length === 1 && only !== void 0) {
1344
+ return only;
1345
+ }
1346
+ return { text: members.map((member) => member.text).join(` ${operator} `), operator };
1343
1347
  }
1344
1348
  function factoryCallText(call, method, names) {
1345
1349
  const [first, second] = call.arguments;
@@ -1954,6 +1958,7 @@ function convertScalar(node, isFlow) {
1954
1958
  const isReplaceable = quotings !== void 0 && node.anchor === void 0 && node.tag === void 0;
1955
1959
  return {
1956
1960
  kind: "scalar",
1961
+ ...anchorOf(node),
1957
1962
  value,
1958
1963
  content: contentRange(node.srcToken, span),
1959
1964
  isFolded: node.type !== Scalar.BLOCK_LITERAL,
@@ -1962,6 +1967,7 @@ function convertScalar(node, isFlow) {
1962
1967
  ...span
1963
1968
  };
1964
1969
  }
1970
+ const anchorOf = (node) => node.anchor === void 0 ? {} : { anchor: node.anchor };
1965
1971
  const flowOf = (conversion, node) => ({
1966
1972
  isFlow: conversion.isFlow || node.flow === true
1967
1973
  });
@@ -1971,7 +1977,8 @@ function convert(node, conversion) {
1971
1977
  }
1972
1978
  if (isSeq(node)) {
1973
1979
  const inner = flowOf(conversion, node);
1974
- return { kind: "list", items: node.items.map((item) => convert(item, inner)), ...spanOf(node) };
1980
+ const items = node.items.map((item) => convert(item, inner));
1981
+ return { kind: "list", items, ...anchorOf(node), ...spanOf(node) };
1975
1982
  }
1976
1983
  if (isMap$1(node)) {
1977
1984
  const inner = flowOf(conversion, node);
@@ -1979,7 +1986,10 @@ function convert(node, conversion) {
1979
1986
  key: convert(pair.key, inner),
1980
1987
  value: convert(pair.value, inner)
1981
1988
  }));
1982
- return { kind: "map", entries, ...spanOf(node) };
1989
+ return { kind: "map", entries, ...anchorOf(node), ...spanOf(node) };
1990
+ }
1991
+ if (isAlias(node)) {
1992
+ return { kind: "other", alias: node.source, ...spanOf(node) };
1983
1993
  }
1984
1994
  return { kind: "other", ...spanOf(isNode(node) ? node : {}) };
1985
1995
  }
@@ -2062,10 +2072,10 @@ const PNPM_SETTINGS_FIELD = "pnpm";
2062
2072
  const OLD_PEER_DEPENDENTS = /* @__PURE__ */ new Map([
2063
2073
  ["swr-openapi", { peer: "openapi-fetch", range: ">=0.15" }]
2064
2074
  ]);
2065
- const PATH_SEPARATOR$9 = "/";
2075
+ const PATH_SEPARATOR$a = "/";
2066
2076
  const QUERY_START = "?";
2067
2077
  function renamedSpecifier(value) {
2068
- const ends = [value.indexOf(PATH_SEPARATOR$9), value.indexOf(QUERY_START)].filter(
2078
+ const ends = [value.indexOf(PATH_SEPARATOR$a), value.indexOf(QUERY_START)].filter(
2069
2079
  (at) => at !== -1
2070
2080
  );
2071
2081
  const name = value.slice(0, ends.length === 0 ? value.length : Math.min(...ends));
@@ -2075,12 +2085,12 @@ function renamedSpecifier(value) {
2075
2085
  }
2076
2086
  const rest = value.slice(name.length);
2077
2087
  const subpath = rest.split(QUERY_START, 1)[0] ?? rest;
2078
- return { to: `${renamed}${rest}`, isDeep: subpath !== "" && subpath !== PATH_SEPARATOR$9 };
2088
+ return { to: `${renamed}${rest}`, isDeep: subpath !== "" && subpath !== PATH_SEPARATOR$a };
2079
2089
  }
2080
2090
  const NODE_MODULES_FOLDER = "node_modules/";
2081
2091
  function oldPackageInNodeModules(path) {
2082
2092
  return [...PACKAGE_RENAMES.keys()].find(
2083
- (name) => path.includes(`${NODE_MODULES_FOLDER}${name}${PATH_SEPARATOR$9}`) || path.endsWith(`${NODE_MODULES_FOLDER}${name}`)
2093
+ (name) => path.includes(`${NODE_MODULES_FOLDER}${name}${PATH_SEPARATOR$a}`) || path.endsWith(`${NODE_MODULES_FOLDER}${name}`)
2084
2094
  );
2085
2095
  }
2086
2096
 
@@ -2095,22 +2105,40 @@ function valuesAt(map, key) {
2095
2105
  function mapsAt(map, key) {
2096
2106
  return valuesAt(map, key).filter(isMap);
2097
2107
  }
2098
- function stringsBelow(node, path) {
2108
+ const NO_ALIASES = () => void 0;
2109
+ function stringsBelow(node, path, targetOf) {
2099
2110
  switch (node.kind) {
2100
2111
  case "scalar":
2101
2112
  return [{ ...node, path }];
2102
2113
  case "list":
2103
- return node.items.flatMap((item, index) => stringsBelow(item, [...path, index]));
2114
+ return node.items.flatMap((item, index) => stringsBelow(item, [...path, index], targetOf));
2104
2115
  case "map":
2105
2116
  return textEntries(node).flatMap(
2106
- ({ key, value }) => stringsBelow(value, [...path, key.value])
2117
+ ({ key, value }) => stringsBelow(value, [...path, key.value], targetOf)
2107
2118
  );
2108
- default:
2109
- return [];
2119
+ default: {
2120
+ const target = targetOf(node);
2121
+ return target === void 0 ? [] : stringsBelow(target, path, targetOf);
2122
+ }
2110
2123
  }
2111
2124
  }
2112
2125
  function documentStrings(documents) {
2113
- return documents.flatMap((document) => stringsBelow(document, []));
2126
+ return documents.flatMap((document) => stringsBelow(document, [], NO_ALIASES));
2127
+ }
2128
+ function nodesBelow(node) {
2129
+ const children = node.kind === "list" ? node.items : node.kind === "map" ? node.entries.flatMap(({ key, value }) => [key, value]) : [];
2130
+ return [node, ...children.flatMap(nodesBelow)];
2131
+ }
2132
+ function aliasTargets(document) {
2133
+ const anchored = nodesBelow(document).filter(
2134
+ (node) => node.kind !== "other" && node.anchor !== void 0
2135
+ );
2136
+ return (alias) => anchored.findLast(
2137
+ (node) => node.kind !== "other" && node.anchor === alias.alias && node.end <= alias.start
2138
+ );
2139
+ }
2140
+ function usedDocumentStrings(documents) {
2141
+ return documents.flatMap((document) => stringsBelow(document, [], aliasTargets(document)));
2114
2142
  }
2115
2143
  function ownerKey(path) {
2116
2144
  return path.findLast((part) => typeof part === "string");
@@ -2308,6 +2336,64 @@ const INSTALLERS = [
2308
2336
  ];
2309
2337
  const NPM_SPECIFIER_PREFIX = "npm:";
2310
2338
 
2339
+ const EXPRESSION_OPEN = "${{";
2340
+ const EXPRESSION_CLOSE = "}}";
2341
+ const LITERAL_QUOTE = "'";
2342
+ const SHELL_SINGLE_QUOTE = "'";
2343
+ const BACKSLASH$3 = "\\";
2344
+ const DOUBLE_QUOTE$1 = '"';
2345
+ function expressionEnd(text, start) {
2346
+ for (let index = start + EXPRESSION_OPEN.length; index < text.length; ) {
2347
+ if (text.startsWith(EXPRESSION_CLOSE, index)) {
2348
+ return index + EXPRESSION_CLOSE.length;
2349
+ }
2350
+ const close = text[index] === LITERAL_QUOTE ? text.indexOf(LITERAL_QUOTE, index + 1) : index;
2351
+ index = close === -1 ? text.length : close + 1;
2352
+ }
2353
+ return void 0;
2354
+ }
2355
+ function literalsIn(raw, start, end) {
2356
+ const found = [];
2357
+ let open = raw.indexOf(LITERAL_QUOTE, start);
2358
+ while (open !== -1 && open < end) {
2359
+ let close = raw.indexOf(LITERAL_QUOTE, open + 1);
2360
+ let isEscaped = false;
2361
+ while (close !== -1 && raw[close + 1] === LITERAL_QUOTE) {
2362
+ isEscaped = true;
2363
+ close = raw.indexOf(LITERAL_QUOTE, close + 2);
2364
+ }
2365
+ if (close === -1) {
2366
+ break;
2367
+ }
2368
+ found.push(...isEscaped ? [] : [{ text: raw.slice(open + 1, close), start: open + 1 }]);
2369
+ open = raw.indexOf(LITERAL_QUOTE, close + 1);
2370
+ }
2371
+ return found;
2372
+ }
2373
+ function expressionLiterals(raw) {
2374
+ const found = [];
2375
+ for (let index = 0; index < raw.length; ) {
2376
+ if (raw[index] === SHELL_SINGLE_QUOTE) {
2377
+ const close = raw.indexOf(SHELL_SINGLE_QUOTE, index + 1);
2378
+ index = close === -1 ? raw.length : close + 1;
2379
+ } else if (raw[index] === BACKSLASH$3) {
2380
+ index += 2;
2381
+ } else if (raw.startsWith(EXPRESSION_OPEN, index)) {
2382
+ const end = expressionEnd(raw, index) ?? raw.length;
2383
+ found.push(...literalsIn(raw, index + EXPRESSION_OPEN.length, end));
2384
+ index = end;
2385
+ } else {
2386
+ index += 1;
2387
+ }
2388
+ }
2389
+ return found;
2390
+ }
2391
+ function isWholeExpression(raw) {
2392
+ const isQuoted = raw.length > 1 && raw.startsWith(DOUBLE_QUOTE$1) && raw.endsWith(DOUBLE_QUOTE$1);
2393
+ const inner = isQuoted ? 1 : 0;
2394
+ return raw.startsWith(EXPRESSION_OPEN, inner) && expressionEnd(raw, inner) === raw.length - inner;
2395
+ }
2396
+
2311
2397
  const COMMAND_SEPARATORS = /* @__PURE__ */ new Set([
2312
2398
  ";",
2313
2399
  "&",
@@ -2318,8 +2404,8 @@ const COMMAND_SEPARATORS = /* @__PURE__ */ new Set([
2318
2404
  "\n"
2319
2405
  ]);
2320
2406
  const WORD_BREAKS = /* @__PURE__ */ new Set([" ", " ", "\r", "<", ">"]);
2321
- const BACKSLASH$3 = "\\";
2322
- const DOUBLE_QUOTE_ESCAPES = /* @__PURE__ */ new Set(["$", "`", '"', BACKSLASH$3, "\n"]);
2407
+ const BACKSLASH$2 = "\\";
2408
+ const DOUBLE_QUOTE_ESCAPES = /* @__PURE__ */ new Set(["$", "`", '"', BACKSLASH$2, "\n"]);
2323
2409
  function singleQuoted(text, start) {
2324
2410
  const close = text.indexOf("'", start + 1);
2325
2411
  const end = close === -1 ? text.length : close + 1;
@@ -2330,13 +2416,13 @@ function doubleQuoted(text, start) {
2330
2416
  let index = start + 1;
2331
2417
  while (index < text.length && text[index] !== '"') {
2332
2418
  const next = text[index + 1] ?? "";
2333
- const isEscape = text[index] === BACKSLASH$3 && DOUBLE_QUOTE_ESCAPES.has(next);
2419
+ const isEscape = text[index] === BACKSLASH$2 && DOUBLE_QUOTE_ESCAPES.has(next);
2334
2420
  value += isEscape ? next === "\n" ? "" : next : text[index];
2335
2421
  index += isEscape ? 2 : 1;
2336
2422
  }
2337
2423
  return { end: Math.min(index + 1, text.length), value };
2338
2424
  }
2339
- const isLineContinuation = (text, index) => text[index] === BACKSLASH$3 && (text[index + 1] === "\n" || text.startsWith("\r\n", index + 1));
2425
+ const isLineContinuation = (text, index) => text[index] === BACKSLASH$2 && (text[index + 1] === "\n" || text.startsWith("\r\n", index + 1));
2340
2426
  const ARITHMETIC_OPEN = "$((";
2341
2427
  const NESTING_OPEN = "(";
2342
2428
  const NESTING_CLOSE = ")";
@@ -2356,7 +2442,9 @@ const PARAMETER_CLOSE = "}";
2356
2442
  function parameterExpansionEnd(text, start) {
2357
2443
  let depth = 1;
2358
2444
  for (let index = start + PARAMETER_OPEN.length; index < text.length; ) {
2359
- if (text.startsWith(PARAMETER_OPEN, index)) {
2445
+ if (text.startsWith(EXPRESSION_OPEN, index)) {
2446
+ index = expressionEnd(text, index) ?? text.length;
2447
+ } else if (text.startsWith(PARAMETER_OPEN, index)) {
2360
2448
  depth += 1;
2361
2449
  index += PARAMETER_OPEN.length;
2362
2450
  } else if (text[index] === PARAMETER_CLOSE) {
@@ -2379,7 +2467,7 @@ function quotedOrEscapedEnd(text, index) {
2379
2467
  if (char === '"') {
2380
2468
  return doubleQuoted(text, index).end;
2381
2469
  }
2382
- return char === BACKSLASH$3 ? index + 2 : void 0;
2470
+ return char === BACKSLASH$2 ? index + 2 : void 0;
2383
2471
  }
2384
2472
  function expansionPart(text, index) {
2385
2473
  if (text.startsWith(ARITHMETIC_OPEN, index)) {
@@ -2400,7 +2488,7 @@ function wordPart(text, index) {
2400
2488
  if (char === '"') {
2401
2489
  return doubleQuoted(text, index);
2402
2490
  }
2403
- if (char === BACKSLASH$3 && index + 1 < text.length) {
2491
+ if (char === BACKSLASH$2 && index + 1 < text.length) {
2404
2492
  return { end: index + 2, value: text[index + 1] };
2405
2493
  }
2406
2494
  return { end: index + 1, value: char };
@@ -2489,7 +2577,9 @@ function skipAssignments(words, start) {
2489
2577
  return index;
2490
2578
  }
2491
2579
  const WINDOWS_PROGRAM_SUFFIX_RE = /\.(?:cmd|exe|ps1)$/i;
2492
- const entryWord = (word) => word?.value.replace(WINDOWS_PROGRAM_SUFFIX_RE, "");
2580
+ const windowsSuffix = (value) => WINDOWS_PROGRAM_SUFFIX_RE.exec(value)?.[0] ?? "";
2581
+ const withoutWindowsSuffix = (value) => value.slice(0, value.length - windowsSuffix(value).length);
2582
+ const entryWord = (word) => word === void 0 ? void 0 : withoutWindowsSuffix(word.value);
2493
2583
  function matchingPrefix(entries, words, index) {
2494
2584
  return entries.find(
2495
2585
  (entry) => entry.words.every((name, offset) => entryWord(words[index + offset]) === name)
@@ -2573,7 +2663,7 @@ function runsGenerator(command) {
2573
2663
  const words = withoutRecipePrefix(command);
2574
2664
  const { program } = commandRoles(words);
2575
2665
  const word = program === void 0 ? void 0 : words[program];
2576
- return word !== void 0 && packageReference(word.value).name === GENERATOR_COMMAND;
2666
+ return word !== void 0 && packageReference(withoutWindowsSuffix(word.value)).name === GENERATOR_COMMAND;
2577
2667
  }
2578
2668
 
2579
2669
  const CODE_OPTIONS = /* @__PURE__ */ new Map([
@@ -2618,6 +2708,15 @@ function inlineCode(command) {
2618
2708
  return void 0;
2619
2709
  }
2620
2710
 
2711
+ const PATH_SEPARATOR$9 = "/";
2712
+ const WINDOWS_SEPARATOR_RE = /\\/g;
2713
+ const QUOTE_RE = /["']/g;
2714
+ function programPath(word) {
2715
+ const suffix = windowsSuffix(word.value);
2716
+ const windowsPath = word.raw.replace(QUOTE_RE, "").replace(WINDOWS_SEPARATOR_RE, PATH_SEPARATOR$9);
2717
+ return { path: suffix === "" ? word.value : windowsPath, suffix };
2718
+ }
2719
+
2621
2720
  const EXPANSION_HEAD_RE = /^\$\{([A-Za-z_][A-Za-z0-9_]*):?([-=+])/;
2622
2721
  const USES = {
2623
2722
  "-": "default",
@@ -2625,7 +2724,7 @@ const USES = {
2625
2724
  "+": "alternative"
2626
2725
  };
2627
2726
  const SINGLE_QUOTE = "'";
2628
- const BACKSLASH$2 = "\\";
2727
+ const BACKSLASH$1 = "\\";
2629
2728
  function expansionAt(text, start) {
2630
2729
  const head = EXPANSION_HEAD_RE.exec(text.slice(start));
2631
2730
  const end = head === null ? void 0 : parameterExpansionEnd(text, start);
@@ -2649,7 +2748,7 @@ function wordExpansions(raw) {
2649
2748
  if (char === SINGLE_QUOTE) {
2650
2749
  const close = raw.indexOf(SINGLE_QUOTE, index + 1);
2651
2750
  index = close === -1 ? raw.length : close + 1;
2652
- } else if (char === BACKSLASH$2) {
2751
+ } else if (char === BACKSLASH$1) {
2653
2752
  index += 2;
2654
2753
  } else if (raw.startsWith(PARAMETER_OPEN, index)) {
2655
2754
  const expansion = expansionAt(raw, index);
@@ -2661,9 +2760,9 @@ function wordExpansions(raw) {
2661
2760
  }
2662
2761
  return found;
2663
2762
  }
2664
- const DOUBLE_QUOTE$1 = '"';
2763
+ const DOUBLE_QUOTE = '"';
2665
2764
  function wholeWordExpansion(raw) {
2666
- const isQuoted = raw.length > 1 && raw.startsWith(DOUBLE_QUOTE$1) && raw.endsWith(DOUBLE_QUOTE$1);
2765
+ const isQuoted = raw.length > 1 && raw.startsWith(DOUBLE_QUOTE) && raw.endsWith(DOUBLE_QUOTE);
2667
2766
  const inner = isQuoted ? 1 : 0;
2668
2767
  const [expansion] = wordExpansions(raw);
2669
2768
  const isWhole = expansion?.expansionStart === inner && expansion.expansionEnd === raw.length - inner;
@@ -2726,64 +2825,6 @@ function readBodies(text, start, pending) {
2726
2825
  return { bodies, end };
2727
2826
  }
2728
2827
 
2729
- const EXPRESSION_OPEN = "${{";
2730
- const EXPRESSION_CLOSE = "}}";
2731
- const LITERAL_QUOTE = "'";
2732
- const SHELL_SINGLE_QUOTE = "'";
2733
- const BACKSLASH$1 = "\\";
2734
- const DOUBLE_QUOTE = '"';
2735
- function expressionEnd(text, start) {
2736
- for (let index = start + EXPRESSION_OPEN.length; index < text.length; ) {
2737
- if (text.startsWith(EXPRESSION_CLOSE, index)) {
2738
- return index + EXPRESSION_CLOSE.length;
2739
- }
2740
- const close = text[index] === LITERAL_QUOTE ? text.indexOf(LITERAL_QUOTE, index + 1) : index;
2741
- index = close === -1 ? text.length : close + 1;
2742
- }
2743
- return void 0;
2744
- }
2745
- function literalsIn(raw, start, end) {
2746
- const found = [];
2747
- let open = raw.indexOf(LITERAL_QUOTE, start);
2748
- while (open !== -1 && open < end) {
2749
- let close = raw.indexOf(LITERAL_QUOTE, open + 1);
2750
- let isEscaped = false;
2751
- while (close !== -1 && raw[close + 1] === LITERAL_QUOTE) {
2752
- isEscaped = true;
2753
- close = raw.indexOf(LITERAL_QUOTE, close + 2);
2754
- }
2755
- if (close === -1) {
2756
- break;
2757
- }
2758
- found.push(...isEscaped ? [] : [{ text: raw.slice(open + 1, close), start: open + 1 }]);
2759
- open = raw.indexOf(LITERAL_QUOTE, close + 1);
2760
- }
2761
- return found;
2762
- }
2763
- function expressionLiterals(raw) {
2764
- const found = [];
2765
- for (let index = 0; index < raw.length; ) {
2766
- if (raw[index] === SHELL_SINGLE_QUOTE) {
2767
- const close = raw.indexOf(SHELL_SINGLE_QUOTE, index + 1);
2768
- index = close === -1 ? raw.length : close + 1;
2769
- } else if (raw[index] === BACKSLASH$1) {
2770
- index += 2;
2771
- } else if (raw.startsWith(EXPRESSION_OPEN, index)) {
2772
- const end = expressionEnd(raw, index) ?? raw.length;
2773
- found.push(...literalsIn(raw, index + EXPRESSION_OPEN.length, end));
2774
- index = end;
2775
- } else {
2776
- index += 1;
2777
- }
2778
- }
2779
- return found;
2780
- }
2781
- function isWholeExpression(raw) {
2782
- const isQuoted = raw.length > 1 && raw.startsWith(DOUBLE_QUOTE) && raw.endsWith(DOUBLE_QUOTE);
2783
- const inner = isQuoted ? 1 : 0;
2784
- return raw.startsWith(EXPRESSION_OPEN, inner) && expressionEnd(raw, inner) === raw.length - inner;
2785
- }
2786
-
2787
2828
  const COMMENT = "#";
2788
2829
  const LINE_BREAK$4 = "\n";
2789
2830
  function skipTrivia(text, index) {
@@ -2903,9 +2944,15 @@ const shifted = (words, offset) => words.map((word) => ({ ...word, start: word.s
2903
2944
  function shellCommandsAt(text, offset, indent = 0) {
2904
2945
  return shellCommands(text, indent).map((words) => shifted(words, offset));
2905
2946
  }
2906
- const expansionCommands = (word) => [...wordExpansions(word.raw), ...expressionLiterals(word.raw)].flatMap(
2907
- (part) => shellCommandsAt(part.text, word.start + part.start)
2908
- );
2947
+ function expansionCommands(word) {
2948
+ const expansions = wordExpansions(word.raw);
2949
+ const literals = expressionLiterals(word.raw).filter(
2950
+ ({ start }) => expansions.every((expansion) => start < expansion.start || start >= expansion.expansionEnd)
2951
+ );
2952
+ return [...expansions, ...literals].flatMap(
2953
+ (part) => shellCommandsAt(part.text, word.start + part.start)
2954
+ );
2955
+ }
2909
2956
  function innerCommands(command) {
2910
2957
  const assignments = new Map(shellAssignments(command).map((found) => [found.word, found]));
2911
2958
  const code = inlineCode(command)?.code;
@@ -2946,6 +2993,8 @@ function canRunGenerator(definition, generators) {
2946
2993
  return generators.has(definition.target);
2947
2994
  case "append":
2948
2995
  return false;
2996
+ case "run-time":
2997
+ return true;
2949
2998
  default:
2950
2999
  return assertNever(definition);
2951
3000
  }
@@ -2958,6 +3007,8 @@ function canRunOther(definition, others, defined) {
2958
3007
  return others.has(definition.target) || !defined.has(definition.target);
2959
3008
  case "append":
2960
3009
  return false;
3010
+ case "run-time":
3011
+ return true;
2961
3012
  default:
2962
3013
  return assertNever(definition);
2963
3014
  }
@@ -2986,15 +3037,24 @@ function variablePrograms(definitions) {
2986
3037
  return new Map([...defined].map((name) => [name, programOf(name)]));
2987
3038
  }
2988
3039
 
2989
- const SHELL_VARIABLE_RE = /^"?\$(?:([A-Za-z_][A-Za-z0-9_]*)|\{([A-Za-z_][A-Za-z0-9_]*)\})"?$/;
2990
- function expandedName(text) {
2991
- const match = SHELL_VARIABLE_RE.exec(text);
3040
+ const SHELL_VARIABLE_RE$1 = /^"?\$(?:([A-Za-z_][A-Za-z0-9_]*)|\{([A-Za-z_][A-Za-z0-9_]*)\})"?$/;
3041
+ function expandedName$1(text) {
3042
+ const match = SHELL_VARIABLE_RE$1.exec(text);
2992
3043
  return match === null ? void 0 : match[1] ?? match[2];
2993
3044
  }
2994
3045
  const textRunsGenerator = (text) => shellCommands(text).some(runsGenerator);
3046
+ function runsExpression(command) {
3047
+ const { program } = commandRoles(command);
3048
+ const word = program === void 0 ? void 0 : command[program];
3049
+ return word !== void 0 && isWholeExpression(word.raw);
3050
+ }
2995
3051
  function textDefinition(name, text) {
2996
- const target = expandedName(text.trim());
2997
- return target === void 0 ? { name, kind: "command", runsGenerator: textRunsGenerator(text) } : { name, kind: "reference", target };
3052
+ const target = expandedName$1(text.trim());
3053
+ if (target !== void 0) {
3054
+ return { name, kind: "reference", target };
3055
+ }
3056
+ const commands = shellCommands(text);
3057
+ return commands.some(runsExpression) ? { name, kind: "run-time" } : { name, kind: "command", runsGenerator: commands.some(runsGenerator) };
2998
3058
  }
2999
3059
  function expansionDefinitions(name, expansion) {
3000
3060
  const word = textDefinition(name, expansion.text);
@@ -3012,7 +3072,7 @@ function shellVariables(definitions) {
3012
3072
  values.set(name, [values.get(name), value].filter((part) => part !== void 0).join(" "));
3013
3073
  }
3014
3074
  const programs = variablePrograms(definitions.flatMap(programDefinitions$1));
3015
- const nameAt = (word) => expandedName(word.raw);
3075
+ const nameAt = (word) => expandedName$1(word.raw);
3016
3076
  return {
3017
3077
  programAt: (program) => {
3018
3078
  const name = nameAt(program);
@@ -3057,7 +3117,7 @@ function expansionUse(word, variables) {
3057
3117
  return void 0;
3058
3118
  }
3059
3119
  const programOf = (name) => (name === void 0 ? void 0 : variables.programAt({ ...word, raw: `$${name}` })?.program) ?? "other";
3060
- const target = expandedName(expansion.text.trim());
3120
+ const target = expandedName$1(expansion.text.trim());
3061
3121
  const textProgram = textRunsGenerator(expansion.text) ? "generator" : "other";
3062
3122
  const own = target === void 0 ? textProgram : programOf(target);
3063
3123
  const variable = programOf(expansion.use === "alternative" ? void 0 : expansion.name);
@@ -3084,10 +3144,11 @@ const QUOTES$1 = /* @__PURE__ */ new Set(["'", '"']);
3084
3144
  const PATH_SEPARATOR$7 = "/";
3085
3145
  const BIN_FOLDER = "/.bin/";
3086
3146
  const OLD_PACKAGE_FOLDER = `node_modules/${GENERATOR_COMMAND}/`;
3087
- function renameAtEnd(word, name, to) {
3147
+ function renameAtEnd(word, name, to, suffix = "") {
3088
3148
  const at = word.raw.lastIndexOf(name);
3089
3149
  const tail = word.raw.slice(at + name.length);
3090
- if (at === -1 || tail !== "" && !QUOTES$1.has(tail)) {
3150
+ const quote = tail.slice(suffix.length);
3151
+ if (at === -1 || quote !== "" && !QUOTES$1.has(quote)) {
3091
3152
  return void 0;
3092
3153
  }
3093
3154
  return { start: word.start + at, end: word.start + at + name.length, text: to };
@@ -3107,27 +3168,30 @@ function packageFindings(found, locate) {
3107
3168
  const change = { kind: "package-name-renamed", location, from: name, to };
3108
3169
  return edit === void 0 ? [] : [{ offset, edit, change }];
3109
3170
  }
3110
- function programPathFindings(word, location) {
3171
+ function programPathFindings(word, { path, suffix }, location) {
3111
3172
  const offset = word.start;
3112
- if (word.value.includes(OLD_PACKAGE_FOLDER)) {
3113
- return [{ offset, manualStep: { kind: "old-package-file", location, path: word.value } }];
3173
+ if (path.includes(OLD_PACKAGE_FOLDER)) {
3174
+ return [{ offset, manualStep: { kind: "old-package-file", location, path } }];
3114
3175
  }
3115
- const isBin = word.value.endsWith(`${BIN_FOLDER}${GENERATOR_COMMAND}`);
3116
- const edit = isBin ? renameAtEnd(word, GENERATOR_COMMAND, MIGRATED_GENERATOR_COMMAND) : void 0;
3176
+ const isBin = path.endsWith(`${BIN_FOLDER}${GENERATOR_COMMAND}${suffix}`);
3177
+ const to = MIGRATED_GENERATOR_COMMAND;
3178
+ const edit = isBin ? renameAtEnd(word, GENERATOR_COMMAND, to, suffix) : void 0;
3117
3179
  return edit === void 0 ? [] : [{ offset, edit, change: { kind: "command-renamed", location } }];
3118
3180
  }
3119
3181
  function programFindings(word, location) {
3120
- if (word.value.includes(PATH_SEPARATOR$7)) {
3121
- return programPathFindings(word, location);
3182
+ const program = programPath(word);
3183
+ if (program.path.includes(PATH_SEPARATOR$7)) {
3184
+ return programPathFindings(word, program, location);
3122
3185
  }
3123
- const { name, isPinned } = packageReference(word.value);
3186
+ const { path, suffix } = program;
3187
+ const { name, isPinned } = packageReference(path.slice(0, path.length - suffix.length));
3124
3188
  if (name !== GENERATOR_COMMAND) {
3125
3189
  return [];
3126
3190
  }
3127
3191
  if (isPinned) {
3128
3192
  return [{ offset: word.start, manualStep: { kind: "versioned-command", location } }];
3129
3193
  }
3130
- const edit = renameAtEnd(word, GENERATOR_COMMAND, MIGRATED_GENERATOR_COMMAND);
3194
+ const edit = renameAtEnd(word, GENERATOR_COMMAND, MIGRATED_GENERATOR_COMMAND, suffix);
3131
3195
  const change = { kind: "command-renamed", location };
3132
3196
  return edit === void 0 ? [] : [{ offset: word.start, edit, change }];
3133
3197
  }
@@ -4133,7 +4197,8 @@ function interpolationsOf(text) {
4133
4197
  }
4134
4198
 
4135
4199
  const RECIPE_NAME_RE = /^@?[A-Za-z_][A-Za-z0-9_-]*(?=[ \t:])/gm;
4136
- const PARAMETER_RE = /^[+*$]*([A-Za-z_][A-Za-z0-9_-]*)(?:=([\s\S]*))?$/;
4200
+ const PARAMETER_RE = /^([+*$]*)([A-Za-z_][A-Za-z0-9_-]*)(?:=([\s\S]*))?$/;
4201
+ const EXPORT_PREFIX = "$";
4137
4202
  const NAME_RE = /^[A-Za-z_][A-Za-z0-9_-]*$/;
4138
4203
  const COLON = ":";
4139
4204
  const EQUALS = "=";
@@ -4180,14 +4245,15 @@ function parameterWords(text, start, end) {
4180
4245
  function parameterDefault(text, word) {
4181
4246
  const written = text.slice(word.start, word.end);
4182
4247
  const match = PARAMETER_RE.exec(written);
4183
- const value = match?.[2];
4248
+ const value = match?.[3];
4184
4249
  if (match === null || value === void 0) {
4185
4250
  return [];
4186
4251
  }
4187
4252
  const defaultStart = word.end - value.length;
4188
4253
  const literals = literalsBetween(text, defaultStart, word.end);
4189
4254
  const target = NAME_RE.test(value) ? value : void 0;
4190
- return [{ name: match[1], literals, target }];
4255
+ const isExported = match[1].includes(EXPORT_PREFIX);
4256
+ return [{ name: match[2], isExported, literals, target }];
4191
4257
  }
4192
4258
  function recipeHeaders(text) {
4193
4259
  return [...text.matchAll(RECIPE_NAME_RE)].flatMap((match) => {
@@ -4329,7 +4395,9 @@ function shebangRecipe(text, header) {
4329
4395
  }
4330
4396
  const shebangRecipes = (text, headers) => headers.flatMap((header) => shebangRecipe(text, header));
4331
4397
 
4332
- const ASSIGNMENT_RE$1 = /^(?:export[ \t]+)?([A-Za-z_][A-Za-z0-9_-]*)[ \t]*:=[ \t]*/gm;
4398
+ const ASSIGNMENT_RE$1 = /^(export[ \t]+)?([A-Za-z_][A-Za-z0-9_-]*)[ \t]*:=[ \t]*/gm;
4399
+ const SET_EXPORT_RE = /^set[ \t]+export(?:[ \t]*:=[ \t]*true)?[ \t]*(?:#.*)?$/m;
4400
+ const SHELL_VARIABLE_RE = /^[@+-]*"?\$(?:([A-Za-z_][A-Za-z0-9_]*)|\{([A-Za-z_][A-Za-z0-9_]*)\})"?$/;
4333
4401
  const NAME_VALUE_RE = /^[A-Za-z_][A-Za-z0-9_-]*$/;
4334
4402
  const VARIABLE_INTERPOLATION_RE = /^[@+-]*\{\{[ \t]*([A-Za-z_][A-Za-z0-9_-]*)[ \t]*\}\}$/;
4335
4403
  const MASK$1 = "_";
@@ -4339,7 +4407,8 @@ function assignmentsOf$1(text) {
4339
4407
  const valueStart = match.index + match[0].length;
4340
4408
  const { literals, end } = expressionAt(text, valueStart);
4341
4409
  const value = text.slice(valueStart, end).trim();
4342
- return { name: match[1], value, start: match.index, end, literals };
4410
+ const name = match[2];
4411
+ return { name, isExported: match[1] !== void 0, value, start: match.index, end, literals };
4343
4412
  });
4344
4413
  }
4345
4414
  function onlyString({ value, literals }) {
@@ -4400,9 +4469,20 @@ function computedProgram(written) {
4400
4469
  const literals = interpolationsOf(written).flatMap((interpolation) => interpolation.literals);
4401
4470
  return literals.some(stringRunsGenerator) ? "generator-or-other" : void 0;
4402
4471
  }
4403
- function justfileVariables(text, values, programs) {
4472
+ function exportedNames(text, assignments, defaults) {
4473
+ const isAll = SET_EXPORT_RE.test(text);
4474
+ const names = [...assignments, ...defaults].filter((found) => isAll || found.isExported);
4475
+ return new Set(names.map((found) => found.name));
4476
+ }
4477
+ function expandedName(written, exported) {
4478
+ const interpolated = VARIABLE_INTERPOLATION_RE.exec(written)?.[1];
4479
+ const match = SHELL_VARIABLE_RE.exec(written);
4480
+ const shellName = match === null ? void 0 : match[1] ?? match[2];
4481
+ return interpolated ?? (shellName !== void 0 && exported.has(shellName) ? shellName : void 0);
4482
+ }
4483
+ function justfileVariables(text, { values, programs, exported }) {
4404
4484
  const writtenAt = (word) => text.slice(word.start, word.end);
4405
- const nameAt = (word) => VARIABLE_INTERPOLATION_RE.exec(writtenAt(word))?.[1];
4485
+ const nameAt = (word) => expandedName(writtenAt(word), exported);
4406
4486
  return {
4407
4487
  programAt: (word) => {
4408
4488
  const name = nameAt(word);
@@ -4427,7 +4507,11 @@ function migrateJustfile(text, file) {
4427
4507
  ...assignments.flatMap(assignmentDefinitions),
4428
4508
  ...defaults.flatMap(parameterDefinitions)
4429
4509
  ]);
4430
- const variables = justfileVariables(text, variableValues$1(assignments, defaults), programs);
4510
+ const variables = justfileVariables(text, {
4511
+ values: variableValues$1(assignments, defaults),
4512
+ programs,
4513
+ exported: exportedNames(text, assignments, defaults)
4514
+ });
4431
4515
  const scripts = shebangRecipes(text, headers);
4432
4516
  const shell = shellText$1(text, [...assignments, ...headers, ...scripts]);
4433
4517
  const commands = [
@@ -4442,23 +4526,10 @@ function migrateJustfile(text, file) {
4442
4526
  return { text: applyTextEdits(text, edits), changes, manualSteps: steps };
4443
4527
  }
4444
4528
 
4445
- const ASSIGNMENT_RE = new RegExp(
4446
- [
4447
- "^(?:[^\\s:#=][^:#=\\n]*:[ \\t]*)?",
4448
- "(?:(?:export|override|private)[ \\t]+)*",
4449
- "([A-Za-z_][A-Za-z0-9_.-]*)",
4450
- "[ \\t]*(:::=|::=|:=|\\?=|\\+=|!=|=)"
4451
- ].join(""),
4452
- "gm"
4453
- );
4454
- const VARIABLE_REFERENCE_RE = /^\$(?:\(([A-Za-z_][A-Za-z0-9_.-]*)\)|\{([A-Za-z_][A-Za-z0-9_.-]*)\}|([A-Za-z_]))$/;
4455
- const RECIPE_PREFIX_RE = /^[@+-]+/;
4456
4529
  const DOLLAR = "$";
4457
4530
  const CLOSING = { "(": ")", "{": "}" };
4458
- const NOT_LINE_BREAK_RE = /[^\n]/g;
4459
4531
  const MASK = "_";
4460
- const LINE_BREAK = "\n";
4461
- const BACKSLASH = "\\";
4532
+ const ARGUMENT_SEPARATOR = ",";
4462
4533
  function expansionEnd(text, start) {
4463
4534
  const open = text[start + 1] ?? "";
4464
4535
  const close = CLOSING[open];
@@ -4475,9 +4546,8 @@ function expansionEnd(text, start) {
4475
4546
  }
4476
4547
  return void 0;
4477
4548
  }
4478
- function maskExpansions(text) {
4479
- const parts = [];
4480
- let copiedUpTo = 0;
4549
+ function expansionsOf(text) {
4550
+ const found = [];
4481
4551
  for (let index = text.indexOf(DOLLAR); index !== -1; index = text.indexOf(DOLLAR, index + 1)) {
4482
4552
  if (text[index + 1] === DOLLAR) {
4483
4553
  index++;
@@ -4485,15 +4555,75 @@ function maskExpansions(text) {
4485
4555
  }
4486
4556
  const end = expansionEnd(text, index);
4487
4557
  if (end !== void 0) {
4488
- parts.push(text.slice(copiedUpTo, index + 1), MASK.repeat(end - index - 1));
4489
- copiedUpTo = end;
4558
+ found.push({ start: index, end });
4490
4559
  index = end - 1;
4491
4560
  }
4492
4561
  }
4562
+ return found;
4563
+ }
4564
+ function maskExpansions(text) {
4565
+ const parts = [];
4566
+ let copiedUpTo = 0;
4567
+ for (const { start, end } of expansionsOf(text)) {
4568
+ parts.push(text.slice(copiedUpTo, start + 1), MASK.repeat(end - start - 1));
4569
+ copiedUpTo = end;
4570
+ }
4493
4571
  parts.push(text.slice(copiedUpTo));
4494
4572
  return parts.join("");
4495
4573
  }
4574
+ const VALUE_ARGUMENTS = /* @__PURE__ */ new Map([
4575
+ ["if", 1],
4576
+ ["or", 0],
4577
+ ["and", 0]
4578
+ ]);
4579
+ const FUNCTION_HEAD_RE = /^\$[({]([a-z]+)[ \t]+/;
4580
+ const OPENING = new Set(Object.keys(CLOSING));
4581
+ const CLOSINGS = new Set(Object.values(CLOSING));
4582
+ function callArguments(text, start, end) {
4583
+ const found = [];
4584
+ let argumentStart = start;
4585
+ let depth = 0;
4586
+ for (let index = start; index < end; index++) {
4587
+ const char = text[index];
4588
+ depth += OPENING.has(char) ? 1 : CLOSINGS.has(char) ? -1 : 0;
4589
+ if (char === ARGUMENT_SEPARATOR && depth === 0) {
4590
+ found.push({ text: text.slice(argumentStart, index), start: argumentStart });
4591
+ argumentStart = index + 1;
4592
+ }
4593
+ }
4594
+ return [...found, { text: text.slice(argumentStart, end), start: argumentStart }];
4595
+ }
4596
+ function valueArguments(text, { start, end }) {
4597
+ const head = FUNCTION_HEAD_RE.exec(text.slice(start, end));
4598
+ const first = head === null ? void 0 : VALUE_ARGUMENTS.get(head[1]);
4599
+ if (head === null || first === void 0) {
4600
+ return [];
4601
+ }
4602
+ return callArguments(text, start + head[0].length, end - 1).slice(first);
4603
+ }
4604
+ function functionCommands(text, offset = 0) {
4605
+ return expansionsOf(text).flatMap((expansion) => valueArguments(text, expansion)).flatMap((argument) => [
4606
+ ...shellCommandsAt(maskExpansions(argument.text), offset + argument.start),
4607
+ ...functionCommands(argument.text, offset + argument.start)
4608
+ ]);
4609
+ }
4610
+
4611
+ const ASSIGNMENT_RE = new RegExp(
4612
+ [
4613
+ "^(?:[^\\s:#=][^:#=\\n]*:[ \\t]*)?",
4614
+ "(?:(?:export|override|private)[ \\t]+)*",
4615
+ "([A-Za-z_][A-Za-z0-9_.-]*)",
4616
+ "[ \\t]*(:::=|::=|:=|\\?=|\\+=|!=|=)"
4617
+ ].join(""),
4618
+ "gm"
4619
+ );
4620
+ const VARIABLE_REFERENCE_RE = /^\$(?:\(([A-Za-z_][A-Za-z0-9_.-]*)\)|\{([A-Za-z_][A-Za-z0-9_.-]*)\}|([A-Za-z_]))$/;
4621
+ const RECIPE_PREFIX_RE = /^[@+-]+/;
4622
+ const NOT_LINE_BREAK_RE = /[^\n]/g;
4623
+ const LINE_BREAK = "\n";
4624
+ const BACKSLASH = "\\";
4496
4625
  const APPEND_OPERATOR = "+=";
4626
+ const CONDITIONAL_OPERATOR = "?=";
4497
4627
  function logicalLineEnd(text, index) {
4498
4628
  let end = text.indexOf(LINE_BREAK, index);
4499
4629
  while (end !== -1 && text[end - 1] === BACKSLASH) {
@@ -4505,8 +4635,8 @@ const assignmentsOf = (text) => [...text.matchAll(ASSIGNMENT_RE)].map((match) =>
4505
4635
  const valueStart = match.index + match[0].length;
4506
4636
  const valueEnd = logicalLineEnd(text, valueStart);
4507
4637
  const name = match[1];
4508
- const isAppend = match[2] === APPEND_OPERATOR;
4509
- return { name, isAppend, start: match.index, valueStart, valueEnd };
4638
+ const operator = match[2];
4639
+ return { name, operator, start: match.index, valueStart, valueEnd };
4510
4640
  });
4511
4641
  function withoutAssignmentHeads(text, assignments) {
4512
4642
  const parts = [];
@@ -4527,18 +4657,34 @@ function referencedName(written) {
4527
4657
  const match = VARIABLE_REFERENCE_RE.exec(written.trim().replace(RECIPE_PREFIX_RE, ""));
4528
4658
  return match === null ? void 0 : match[1] ?? match[2] ?? match[3];
4529
4659
  }
4660
+ function programWritten(text, command) {
4661
+ const { program } = commandRoles(command);
4662
+ const word = program === void 0 ? void 0 : command[program];
4663
+ return word === void 0 ? "" : text.slice(word.start, word.end);
4664
+ }
4665
+ function valueDefinition(text, { name, valueStart, valueEnd }, commands) {
4666
+ const inValue = commands.filter(
4667
+ ([first2]) => first2 !== void 0 && valueStart <= first2.start && first2.start < valueEnd
4668
+ );
4669
+ const [first] = inValue.sort((left, right) => (left[0]?.start ?? 0) - (right[0]?.start ?? 0));
4670
+ const program = first === void 0 ? "" : programWritten(text, first);
4671
+ const target = referencedName(program);
4672
+ if (target !== void 0) {
4673
+ return { name, kind: "reference", target };
4674
+ }
4675
+ if (isComputed(program)) {
4676
+ return { name, kind: "run-time" };
4677
+ }
4678
+ return { name, kind: "command", runsGenerator: inValue.some(runsGenerator) };
4679
+ }
4530
4680
  function programDefinitions(text, commands, assignments) {
4531
- const generatorStarts = commands.filter(runsGenerator).map((command) => command[0].start);
4532
- return assignments.map(({ name, isAppend, valueStart, valueEnd }) => {
4533
- if (isAppend) {
4534
- return { name, kind: "append" };
4535
- }
4536
- const target = referencedName(text.slice(valueStart, valueEnd));
4537
- if (target !== void 0) {
4538
- return { name, kind: "reference", target };
4681
+ return assignments.flatMap((assignment) => {
4682
+ const { name, operator } = assignment;
4683
+ if (operator === APPEND_OPERATOR) {
4684
+ return [{ name, kind: "append" }];
4539
4685
  }
4540
- const runs = generatorStarts.some((start) => valueStart <= start && start < valueEnd);
4541
- return { name, kind: "command", runsGenerator: runs };
4686
+ const value = valueDefinition(text, assignment, commands);
4687
+ return operator === CONDITIONAL_OPERATOR ? [value, { name, kind: "run-time" }] : [value];
4542
4688
  });
4543
4689
  }
4544
4690
  function variableValues(text, assignments) {
@@ -4573,7 +4719,10 @@ function makefileVariables(text, assignments, programs) {
4573
4719
  function migrateMakefile(text, file) {
4574
4720
  const lineOf = lineLocator(text);
4575
4721
  const assignments = assignmentsOf(text);
4576
- const commands = shellCommands(withoutAssignmentHeads(maskExpansions(text), assignments));
4722
+ const commands = [
4723
+ ...shellCommands(withoutAssignmentHeads(maskExpansions(text), assignments)),
4724
+ ...functionCommands(text)
4725
+ ];
4577
4726
  const programs = variablePrograms(programDefinitions(text, commands, assignments));
4578
4727
  const locate = (offset) => `${file}:${lineOf(offset)}`;
4579
4728
  const variables = makefileVariables(text, assignments, programs);
@@ -4921,6 +5070,31 @@ function oldPackagePatchSteps(fileName) {
4921
5070
  return name === void 0 || to === void 0 ? [] : [{ kind: "old-package-patch", name, to }];
4922
5071
  }
4923
5072
 
5073
+ const INPUTS_KEY = "inputs";
5074
+ const DEFAULT_KEY = "default";
5075
+ const INPUT_DEFAULT_DEPTH = 3;
5076
+ const INPUT_NAME_INDEX = -2;
5077
+ const isInputDefault = (value) => value.path.length >= INPUT_DEFAULT_DEPTH && value.path.at(-1) === DEFAULT_KEY && value.path.at(-INPUT_DEFAULT_DEPTH) === INPUTS_KEY;
5078
+ const INPUT_EXPRESSION_RE = /^"?\$\{\{[ \t]*inputs\.([A-Za-z_][A-Za-z0-9_-]*)[ \t]*\}\}"?$/;
5079
+ function withInputDefaults(variables, strings) {
5080
+ const values = /* @__PURE__ */ new Map();
5081
+ for (const value of strings.filter(isInputDefault)) {
5082
+ const name = String(value.path.at(INPUT_NAME_INDEX));
5083
+ values.set(
5084
+ name,
5085
+ [values.get(name), value.value].filter((part) => part !== void 0).join(" ")
5086
+ );
5087
+ }
5088
+ return {
5089
+ programAt: (program) => variables.programAt(program),
5090
+ referenceAt: (word) => {
5091
+ const name = INPUT_EXPRESSION_RE.exec(word.raw)?.[1];
5092
+ const value = name === void 0 ? void 0 : values.get(name);
5093
+ return variables.referenceAt(word) ?? (value === void 0 ? void 0 : { written: word.raw, value });
5094
+ }
5095
+ };
5096
+ }
5097
+
4924
5098
  const YAML_COMMAND_KEYS = /* @__PURE__ */ new Set([
4925
5099
  "run",
4926
5100
  "script",
@@ -4947,10 +5121,6 @@ const TASKFILE_COMMAND_KEYS = /* @__PURE__ */ new Set([
4947
5121
 
4948
5122
  const ENVIRONMENT_KEYS = /* @__PURE__ */ new Set(["env"]);
4949
5123
  const isEnvironmentValue = (value) => value.path.length >= 2 && ENVIRONMENT_KEYS.has(String(value.path.at(-2)));
4950
- const INPUTS_KEY = "inputs";
4951
- const DEFAULT_KEY = "default";
4952
- const INPUT_DEFAULT_DEPTH = 3;
4953
- const isInputDefault = (value) => value.path.length >= INPUT_DEFAULT_DEPTH && value.path.at(-1) === DEFAULT_KEY && value.path.at(-INPUT_DEFAULT_DEPTH) === INPUTS_KEY;
4954
5124
  function environmentVariables(text, strings) {
4955
5125
  return shellVariables(
4956
5126
  strings.filter(isEnvironmentValue).map((value) => ({
@@ -4978,7 +5148,15 @@ function blockIndent(shell) {
4978
5148
  const indents = lines.map((line) => LEADING_SPACES_RE.exec(line)?.[0].length ?? 0);
4979
5149
  return indents.length === 0 ? 0 : Math.min(...indents);
4980
5150
  }
4981
- const valuesOf = (strings, keys) => strings.filter((string) => keys.has(ownerKey(string.path) ?? ""));
5151
+ function oncePerPlace(strings) {
5152
+ const starts = /* @__PURE__ */ new Set();
5153
+ return strings.filter((string) => {
5154
+ const isFirst = !starts.has(string.start);
5155
+ starts.add(string.start);
5156
+ return isFirst;
5157
+ });
5158
+ }
5159
+ const valuesOf = (strings, keys) => oncePerPlace(strings.filter((string) => keys.has(ownerKey(string.path) ?? "")));
4982
5160
  const EXEC_FORM_KEYS = /* @__PURE__ */ new Set(["command", "entrypoint"]);
4983
5161
  const isExecFormItem = (value) => typeof value.path.at(-1) === "number" && EXEC_FORM_KEYS.has(String(value.path.at(-2)));
4984
5162
  const listOf = (item) => item.path.slice(0, -1).join(".");
@@ -5033,10 +5211,12 @@ function migrateYamlCommands(text, file, strings, keys = YAML_COMMAND_KEYS) {
5033
5211
  const shellOf = stepShells(strings);
5034
5212
  const values = valuesOf(strings, keys).filter((value) => shellOf(value) === void 0);
5035
5213
  const commandValues = new Set(values.filter((value) => !isExecFormItem(value)));
5036
- const shellValues = strings.filter(
5037
- (value) => commandValues.has(value) || isEnvironmentValue(value) || isInputDefault(value)
5214
+ const shellValues = oncePerPlace(
5215
+ strings.filter(
5216
+ (value) => commandValues.has(value) || isEnvironmentValue(value) || isInputDefault(value)
5217
+ )
5038
5218
  );
5039
- const variables = environmentVariables(text, strings);
5219
+ const variables = withInputDefaults(environmentVariables(text, strings), strings);
5040
5220
  return appliedFindings(text, [
5041
5221
  ...shellValues.map((value) => valueFindings(text, value, locate, variables)),
5042
5222
  commandWordFindings(execFormCommands(text, values.filter(isExecFormItem)), locate),
@@ -5210,6 +5390,7 @@ function migrateConfig(text, read, steps) {
5210
5390
  );
5211
5391
  }
5212
5392
  const stringsStep = (migrate) => (text, read) => read.kind === "unreadable" ? unreadableConfig(text, read.offset) : migrate(text, documentStrings(read.documents));
5393
+ const usedStringsStep = (migrate) => (text, read) => read.kind === "unreadable" ? unreadableConfig(text, read.offset) : migrate(text, usedDocumentStrings(read.documents));
5213
5394
  const jsonConfig = (steps) => (text, path, context) => migrateConfig(text, (current) => context.readers.json.read(current), steps(context, path));
5214
5395
  const yamlConfig = (steps) => (text, path, context) => migrateConfig(text, (current) => context.readers.yaml.read(current), steps(context, path));
5215
5396
  const whenNamed = (migrate) => (text, path, context) => namesOriginalPackage(text) ? migrate(text, path, context) : unchanged(text);
@@ -5365,7 +5546,7 @@ const COMMAND_CONFIG_KINDS = [
5365
5546
  matches: (path) => TASKFILE_NAMES.has(baseName(path)),
5366
5547
  migrate: whenNamed(
5367
5548
  yamlConfig((_context, path) => [
5368
- stringsStep(
5549
+ usedStringsStep(
5369
5550
  (text, strings) => migrateYamlCommands(text, path, strings, TASKFILE_COMMAND_KEYS)
5370
5551
  )
5371
5552
  ])
@@ -5380,7 +5561,10 @@ const COMMAND_CONFIG_KINDS = [
5380
5561
  )
5381
5562
  }
5382
5563
  ];
5383
- const yamlCommandsStep = (path, isPart) => (text, read) => isPart || !isCiConfigFile(path) && read.kind === "read" && isApiDescription(read.documents) ? unchanged(text) : stringsStep((current, strings) => migrateYamlCommands(current, path, strings))(text, read);
5564
+ const yamlCommandsStep = (path, isPart) => (text, read) => isPart || !isCiConfigFile(path) && read.kind === "read" && isApiDescription(read.documents) ? unchanged(text) : usedStringsStep((current, strings) => migrateYamlCommands(current, path, strings))(
5565
+ text,
5566
+ read
5567
+ );
5384
5568
  const manifestTarget = ({ version, catalogs, aliases }, path) => ({
5385
5569
  version,
5386
5570
  catalogs,
@@ -6031,6 +6215,7 @@ const NEXT_STEPS = [
6031
6215
  const DRY_RUN_NOTE = "Dry run: nothing was written. Run again with --write to apply.";
6032
6216
  const WRITTEN_NOTE = "Files were written.";
6033
6217
  const NOTHING_FOUND = "Nothing to migrate: no openapi-typescript, openapi-fetch, openapi-react-query or openapi-typescript-helpers found.";
6218
+ const NOTHING_ELSE_FOUND = "Nothing else to migrate: migrate the skipped files above by hand.";
6034
6219
 
6035
6220
  function changesSection(reports) {
6036
6221
  const changed = reports.filter((report) => report.changes.length > 0);
@@ -6086,7 +6271,8 @@ function renderReport(migration) {
6086
6271
  const reports = migration.files;
6087
6272
  const skipped = skippedSection(migration.skipped);
6088
6273
  if (reports.length === 0) {
6089
- return printed([...skipped, NOTHING_FOUND]);
6274
+ const hasBug = migration.skipped.some((file) => file.reason.kind === "migration-bug");
6275
+ return printed([...skipped, hasBug ? NOTHING_ELSE_FOUND : NOTHING_FOUND]);
6090
6276
  }
6091
6277
  const lines = [
6092
6278
  ...changesSection(reports),