ymmv-cli 0.11.1 → 0.11.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -3
- package/dist/cli.js +170 -51
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -46,7 +46,8 @@ via npm Trusted Publishing, with provenance.
|
|
|
46
46
|
|
|
47
47
|
## Commands
|
|
48
48
|
|
|
49
|
-
- `ymmv` detects, confirms, and publishes (re-run any time to update
|
|
49
|
+
- `ymmv` detects, confirms, and publishes (re-run any time to update: the preview marks values
|
|
50
|
+
your environment now detects differently and `d` takes them; `ymmv publish` is the same command)
|
|
50
51
|
- `ymmv <handle>` views a profile, or diffs it against yours when you're logged in
|
|
51
52
|
- `ymmv set editor Neovim` changes one value
|
|
52
53
|
- `ymmv set --extra "Keyboard=HHKB"` adds a free-form line of your own (`-e` works too)
|
|
@@ -58,8 +59,8 @@ via npm Trusted Publishing, with provenance.
|
|
|
58
59
|
the commands to run by hand)
|
|
59
60
|
- `ymmv version` prints the CLI version (and notes a newer release when one is known)
|
|
60
61
|
|
|
61
|
-
Values are capped at 256 characters and extra labels at 64
|
|
62
|
-
to 32 extras.
|
|
62
|
+
Values are capped at 256 characters and extra labels at 64, and each needs at
|
|
63
|
+
least one visible character; a profile holds up to 32 extras.
|
|
63
64
|
|
|
64
65
|
Every profile is open JSON too: `GET https://ymmv.fyi/api/v1/u/<handle>`. Full contract
|
|
65
66
|
(shape, statuses, caching, CORS):
|
package/dist/cli.js
CHANGED
|
@@ -393,6 +393,12 @@ function isValidHandle(handle) {
|
|
|
393
393
|
return handle.length >= 1 && handle.length <= 39 && HANDLE_RE.test(handle);
|
|
394
394
|
}
|
|
395
395
|
|
|
396
|
+
// ../shared/dist/visible.js
|
|
397
|
+
var VISIBLE_RE = /[^\s\p{Default_Ignorable_Code_Point}\p{Cc}]/u;
|
|
398
|
+
function hasVisibleContent(s) {
|
|
399
|
+
return VISIBLE_RE.test(s);
|
|
400
|
+
}
|
|
401
|
+
|
|
396
402
|
// src/render.ts
|
|
397
403
|
var ESC = String.fromCharCode(27);
|
|
398
404
|
var CSI = `${ESC}[`;
|
|
@@ -425,6 +431,12 @@ var BIDI_RE = new RegExp("\\p{Bidi_Control}", "gu");
|
|
|
425
431
|
function sanitizeValue(value) {
|
|
426
432
|
return value.replace(ANSI_RE, "").replace(CTRL_RE, "").replace(BIDI_RE, "");
|
|
427
433
|
}
|
|
434
|
+
function shownValue(value) {
|
|
435
|
+
return sanitizeValue(value).trim();
|
|
436
|
+
}
|
|
437
|
+
function showsVisibleText(value) {
|
|
438
|
+
return hasVisibleContent(sanitizeValue(value));
|
|
439
|
+
}
|
|
428
440
|
function useColor(env, isTTY) {
|
|
429
441
|
if (env.NO_COLOR !== void 0) return false;
|
|
430
442
|
if (env.FORCE_COLOR !== void 0) {
|
|
@@ -473,7 +485,13 @@ function renderProfile(profile, opts) {
|
|
|
473
485
|
const rows = CURATED_KEYS.flatMap((key) => {
|
|
474
486
|
const value = byKey.get(key);
|
|
475
487
|
if (value === void 0 && !preview) return [];
|
|
476
|
-
return [
|
|
488
|
+
return [
|
|
489
|
+
{
|
|
490
|
+
label: KEY_LABELS[key],
|
|
491
|
+
value: value === void 0 ? null : sanitizeValue(value),
|
|
492
|
+
note: preview && value !== void 0 ? opts.disagreements?.get(key) : void 0
|
|
493
|
+
}
|
|
494
|
+
];
|
|
477
495
|
});
|
|
478
496
|
const extras = (profile.extras ?? []).map((x) => ({
|
|
479
497
|
label: sanitizeValue(x.label),
|
|
@@ -492,9 +510,12 @@ function renderProfile(profile, opts) {
|
|
|
492
510
|
if (rows.length) {
|
|
493
511
|
lines.push("");
|
|
494
512
|
for (const r of rows) {
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
513
|
+
if (r.value === null) {
|
|
514
|
+
lines.push(` ${c.faint}${r.label.padEnd(labelW)} ${MISSING}${c.reset}`);
|
|
515
|
+
continue;
|
|
516
|
+
}
|
|
517
|
+
const note = r.note ? ` ${c.faint}(detected: ${sanitizeValue(r.note)})${c.reset}` : "";
|
|
518
|
+
lines.push(` ${c.faint}${r.label.padEnd(labelW)}${c.reset} ${val(r.value)}${note}`);
|
|
498
519
|
}
|
|
499
520
|
}
|
|
500
521
|
if (extras.length) {
|
|
@@ -597,10 +618,16 @@ function causeText(err) {
|
|
|
597
618
|
return sanitizeValue(text);
|
|
598
619
|
}
|
|
599
620
|
function wireText(text) {
|
|
600
|
-
|
|
601
|
-
|
|
621
|
+
return capped(sanitizeValue(String(text)));
|
|
622
|
+
}
|
|
623
|
+
var WIRE_TEXT_CAP = 200;
|
|
624
|
+
function head(clean) {
|
|
625
|
+
return [...clean.slice(0, WIRE_TEXT_CAP * 2)].slice(0, WIRE_TEXT_CAP).join("");
|
|
626
|
+
}
|
|
627
|
+
function capped(clean) {
|
|
628
|
+
const kept = head(clean);
|
|
629
|
+
return kept.length < clean.length ? `${kept}\u2026` : clean;
|
|
602
630
|
}
|
|
603
|
-
var INVISIBLE_RE = new RegExp("\\p{Default_Ignorable_Code_Point}", "gu");
|
|
604
631
|
async function wireBody(res) {
|
|
605
632
|
try {
|
|
606
633
|
return await res.text();
|
|
@@ -615,8 +642,8 @@ function wireErrorBody(raw) {
|
|
|
615
642
|
const out = {};
|
|
616
643
|
if (typeof body?.error === "string") out.slug = body.error;
|
|
617
644
|
if (typeof body?.message === "string") {
|
|
618
|
-
const clean =
|
|
619
|
-
if (
|
|
645
|
+
const clean = sanitizeValue(body.message);
|
|
646
|
+
if (hasVisibleContent(head(clean))) out.message = capped(clean).trim();
|
|
620
647
|
}
|
|
621
648
|
return out;
|
|
622
649
|
} catch {
|
|
@@ -1539,6 +1566,17 @@ function buildDefaults(existing, detected) {
|
|
|
1539
1566
|
}
|
|
1540
1567
|
return out;
|
|
1541
1568
|
}
|
|
1569
|
+
function detectionDisagreements(values, detected, decided = /* @__PURE__ */ new Set()) {
|
|
1570
|
+
const out = /* @__PURE__ */ new Map();
|
|
1571
|
+
for (const key of CURATED_KEYS) {
|
|
1572
|
+
const current = values.get(key);
|
|
1573
|
+
const fresh = detected.get(key);
|
|
1574
|
+
if (current === void 0 || fresh === void 0 || decided.has(key)) continue;
|
|
1575
|
+
const take = shownValue(fresh);
|
|
1576
|
+
if (take && canonical(key, shownValue(current)) !== canonical(key, take)) out.set(key, take);
|
|
1577
|
+
}
|
|
1578
|
+
return out;
|
|
1579
|
+
}
|
|
1542
1580
|
function entriesFromMap(map) {
|
|
1543
1581
|
return CURATED_KEYS.flatMap((key) => {
|
|
1544
1582
|
const value = map.get(key);
|
|
@@ -1712,7 +1750,31 @@ function pagePointer(handle) {
|
|
|
1712
1750
|
const c = palette(color);
|
|
1713
1751
|
return ` ${c.faint}\u2192 ${color ? displayUrl(BASE) : BASE}/${handle}${c.reset}`;
|
|
1714
1752
|
}
|
|
1715
|
-
|
|
1753
|
+
function writeRuleRefusal(entries, existing) {
|
|
1754
|
+
const saved = savedKeys(existing);
|
|
1755
|
+
for (const { key, value } of entries) {
|
|
1756
|
+
if (!isCuratedKey(key)) continue;
|
|
1757
|
+
const problem = valueProblem(value);
|
|
1758
|
+
if (problem === void 0) continue;
|
|
1759
|
+
const remedy = problem === "invisible" ? "Set one" : "Set a shorter one";
|
|
1760
|
+
const source = saved.has(key) ? "saved" : "detected";
|
|
1761
|
+
const remove = problem === "invisible" && source === "saved" ? `, or remove it: ymmv unset ${key}` : "";
|
|
1762
|
+
return `The ${source} ${KEY_LABELS[key]} value ${ruleClause(problem, value)}. ${remedy}: ymmv set ${key} <value>${remove}.`;
|
|
1763
|
+
}
|
|
1764
|
+
return void 0;
|
|
1765
|
+
}
|
|
1766
|
+
function valueProblem(value) {
|
|
1767
|
+
if (!showsVisibleText(value)) return "invisible";
|
|
1768
|
+
if (value.length > MAX_VALUE) return "over-cap";
|
|
1769
|
+
return void 0;
|
|
1770
|
+
}
|
|
1771
|
+
function ruleClause(problem, value) {
|
|
1772
|
+
return problem === "invisible" ? "has no visible text" : `is ${value.length} characters; the cap is ${MAX_VALUE}`;
|
|
1773
|
+
}
|
|
1774
|
+
function savedKeys(existing) {
|
|
1775
|
+
return new Set((existing?.entries ?? []).map((e) => e.key));
|
|
1776
|
+
}
|
|
1777
|
+
async function promptEntries(defaults, saved, prompter) {
|
|
1716
1778
|
const c = palette(colorEnabled());
|
|
1717
1779
|
console.log(message(`${c.faint}Enter to keep, "-" to clear${c.reset}`));
|
|
1718
1780
|
const chosen = /* @__PURE__ */ new Map();
|
|
@@ -1720,13 +1782,15 @@ async function promptEntries(defaults, prompter) {
|
|
|
1720
1782
|
for (; ; ) {
|
|
1721
1783
|
const answer = (await prompter.ask(KEY_LABELS[key], defaults.get(key))).trim();
|
|
1722
1784
|
const value = answer === "-" ? "" : answer;
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
);
|
|
1785
|
+
const rawDefault = defaults.get(key) ?? "";
|
|
1786
|
+
const isDefault = value === shownValue(rawDefault);
|
|
1787
|
+
const emptiedDefault = answer === "" && rawDefault !== "";
|
|
1788
|
+
const problem = emptiedDefault ? "invisible" : value === "" ? void 0 : valueProblem(value);
|
|
1789
|
+
if (problem !== void 0) {
|
|
1790
|
+
const which = `the ${saved.has(key) ? "saved" : "detected"} value`;
|
|
1791
|
+
const clause = ruleClause(problem, value);
|
|
1792
|
+
const note = isDefault ? `${which} ${clause}. Type a ${problem === "invisible" ? "value" : "shorter value"} or - to clear` : `that value ${clause}`;
|
|
1793
|
+
console.log(message(`${c.faint}${note}${c.reset}`));
|
|
1730
1794
|
continue;
|
|
1731
1795
|
}
|
|
1732
1796
|
if (value) chosen.set(key, value);
|
|
@@ -1762,9 +1826,16 @@ async function publish(io) {
|
|
|
1762
1826
|
let ifMatch = own?.etag;
|
|
1763
1827
|
const color = colorEnabled();
|
|
1764
1828
|
const site = displayUrl(BASE);
|
|
1765
|
-
|
|
1829
|
+
let cardShown = false;
|
|
1830
|
+
const showCard = (entries, disagreements) => {
|
|
1831
|
+
cardShown = true;
|
|
1766
1832
|
console.log(
|
|
1767
|
-
renderProfile(newProfile(handle, entries, extras), {
|
|
1833
|
+
renderProfile(newProfile(handle, entries, extras), {
|
|
1834
|
+
color,
|
|
1835
|
+
site,
|
|
1836
|
+
mode: "preview",
|
|
1837
|
+
disagreements
|
|
1838
|
+
})
|
|
1768
1839
|
);
|
|
1769
1840
|
const notes = [];
|
|
1770
1841
|
if (carried.length > 0) {
|
|
@@ -1788,27 +1859,39 @@ async function publish(io) {
|
|
|
1788
1859
|
let values = defaults;
|
|
1789
1860
|
const assemble = () => [...entriesFromMap(values), ...carried];
|
|
1790
1861
|
const edits = /* @__PURE__ */ new Map();
|
|
1862
|
+
const kept = /* @__PURE__ */ new Map();
|
|
1863
|
+
let saved = savedKeys(existing);
|
|
1864
|
+
const disagreeing = () => {
|
|
1865
|
+
const out = detectionDisagreements(
|
|
1866
|
+
values,
|
|
1867
|
+
detected,
|
|
1868
|
+
/* @__PURE__ */ new Set([...edits.keys(), ...kept.keys()])
|
|
1869
|
+
);
|
|
1870
|
+
for (const [key, value] of out) if (valueProblem(value) !== void 0) out.delete(key);
|
|
1871
|
+
return out;
|
|
1872
|
+
};
|
|
1791
1873
|
const prompt = async (prompter) => {
|
|
1792
1874
|
const before = values;
|
|
1793
|
-
|
|
1875
|
+
const marked = cardShown ? disagreeing() : /* @__PURE__ */ new Map();
|
|
1876
|
+
values = await promptEntries(values, saved, prompter);
|
|
1794
1877
|
for (const key of CURATED_KEYS) {
|
|
1795
1878
|
const after = values.get(key);
|
|
1796
1879
|
if (after !== before.get(key)) edits.set(key, after);
|
|
1797
1880
|
}
|
|
1881
|
+
for (const key of marked.keys()) {
|
|
1882
|
+
const value = values.get(key);
|
|
1883
|
+
if (!edits.has(key) && value !== void 0) kept.set(key, value);
|
|
1884
|
+
}
|
|
1798
1885
|
};
|
|
1799
1886
|
if (!io.interactive || !io.prompter || io.yes) {
|
|
1800
|
-
const
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
`The detected ${KEY_LABELS[over[0]]} value is ${over[1].length} characters; the cap is ${MAX_VALUE}. Set a shorter one: ymmv set ${over[0]} <value>.`
|
|
1805
|
-
)
|
|
1806
|
-
);
|
|
1887
|
+
const entries = assemble();
|
|
1888
|
+
const refusal = writeRuleRefusal(entries, existing);
|
|
1889
|
+
if (refusal !== void 0) {
|
|
1890
|
+
console.error(message(refusal));
|
|
1807
1891
|
process.exitCode = 1;
|
|
1808
1892
|
return;
|
|
1809
1893
|
}
|
|
1810
|
-
|
|
1811
|
-
showCard(entries);
|
|
1894
|
+
showCard(entries, /* @__PURE__ */ new Map());
|
|
1812
1895
|
printPublished(
|
|
1813
1896
|
await publishProfile(newProfile(handle, entries, extras), cred, { ifMatch }),
|
|
1814
1897
|
color
|
|
@@ -1817,14 +1900,18 @@ async function publish(io) {
|
|
|
1817
1900
|
}
|
|
1818
1901
|
try {
|
|
1819
1902
|
if (!existing) await prompt(io.prompter);
|
|
1903
|
+
const failsRule = ([, v]) => valueProblem(v) !== void 0;
|
|
1820
1904
|
for (; ; ) {
|
|
1905
|
+
if ([...values].some(failsRule)) await prompt(io.prompter);
|
|
1821
1906
|
const entries = assemble();
|
|
1822
|
-
|
|
1907
|
+
const disagreements = disagreeing();
|
|
1908
|
+
showCard(entries, disagreements);
|
|
1909
|
+
const offerD = disagreements.size > 0;
|
|
1823
1910
|
const ans = await io.prompter.choice(
|
|
1824
1911
|
`Publish to ${site}/${sanitizeValue(handle)}?`,
|
|
1825
|
-
["y", "n", "e"],
|
|
1912
|
+
offerD ? ["y", "n", "e", "d"] : ["y", "n", "e"],
|
|
1826
1913
|
"y",
|
|
1827
|
-
"Y/n/e=edit"
|
|
1914
|
+
offerD ? "Y/n/e=edit/d=detected" : "Y/n/e=edit"
|
|
1828
1915
|
);
|
|
1829
1916
|
if (ans === "y") {
|
|
1830
1917
|
try {
|
|
@@ -1854,6 +1941,9 @@ async function publish(io) {
|
|
|
1854
1941
|
else rebased.set(key, value);
|
|
1855
1942
|
}
|
|
1856
1943
|
values = rebased;
|
|
1944
|
+
for (const [key, value] of kept) if (rebased.get(key) !== value) kept.delete(key);
|
|
1945
|
+
cardShown = false;
|
|
1946
|
+
saved = savedKeys(fresh.profile);
|
|
1857
1947
|
carried = unknownEntries(fresh.profile);
|
|
1858
1948
|
extras = fresh.profile.extras;
|
|
1859
1949
|
ifMatch = fresh.etag;
|
|
@@ -1874,6 +1964,14 @@ ${ambiguous ? "The publish may not have completed. Your answers are kept." : "No
|
|
|
1874
1964
|
console.log(message("Aborted. Nothing published."));
|
|
1875
1965
|
return;
|
|
1876
1966
|
}
|
|
1967
|
+
if (ans === "d") {
|
|
1968
|
+
values = new Map(values);
|
|
1969
|
+
for (const [key, value] of disagreements) {
|
|
1970
|
+
values.set(key, value);
|
|
1971
|
+
edits.set(key, value);
|
|
1972
|
+
}
|
|
1973
|
+
continue;
|
|
1974
|
+
}
|
|
1877
1975
|
await prompt(io.prompter);
|
|
1878
1976
|
}
|
|
1879
1977
|
} catch (e) {
|
|
@@ -1954,18 +2052,24 @@ async function runSet(target) {
|
|
|
1954
2052
|
process.exitCode = 1;
|
|
1955
2053
|
return;
|
|
1956
2054
|
}
|
|
2055
|
+
const refusal = writeRuleRefusal(entries, existing);
|
|
2056
|
+
if (refusal !== void 0) {
|
|
2057
|
+
console.error(message(refusal));
|
|
2058
|
+
process.exitCode = 1;
|
|
2059
|
+
return;
|
|
2060
|
+
}
|
|
1957
2061
|
const res = await publishProfile(newProfile(handle, entries, extras), cred, {
|
|
1958
2062
|
ifMatch: own?.etag
|
|
1959
2063
|
});
|
|
1960
|
-
const line = target.kind === "curated" ? `Set ${KEY_LABELS[target.key]} = ${target.value}.` : `Set extra ${target.label} = ${target.value}.`;
|
|
2064
|
+
const line = target.kind === "curated" ? `Set ${KEY_LABELS[target.key]} = ${sanitizeValue(target.value)}.` : `Set extra ${sanitizeValue(target.label)} = ${sanitizeValue(target.value)}.`;
|
|
1961
2065
|
console.log(message(`${line}${pagePointer(res.handle)}`));
|
|
1962
2066
|
}
|
|
1963
2067
|
var PASTE_SAFE_LABEL = /^[\p{L}\p{N} _.+/:-]+$/u;
|
|
1964
2068
|
function extraHint(existing, label) {
|
|
1965
2069
|
const eq = label.indexOf("=");
|
|
1966
|
-
const
|
|
1967
|
-
if (!
|
|
1968
|
-
const shown = PASTE_SAFE_LABEL.test(
|
|
2070
|
+
const head2 = eq > 0 ? label.slice(0, eq).trim() : "";
|
|
2071
|
+
if (!head2 || !applyUnset(existing, { kind: "extra", label: head2 }).removed) return "";
|
|
2072
|
+
const shown = PASTE_SAFE_LABEL.test(head2) ? head2 : "Label";
|
|
1969
2073
|
return `
|
|
1970
2074
|
(unset takes just the label: ymmv unset --extra "${shown}")`;
|
|
1971
2075
|
}
|
|
@@ -1986,6 +2090,12 @@ async function runUnset(target) {
|
|
|
1986
2090
|
console.log(message(line2));
|
|
1987
2091
|
return;
|
|
1988
2092
|
}
|
|
2093
|
+
const refusal = writeRuleRefusal(entries, existing);
|
|
2094
|
+
if (refusal !== void 0) {
|
|
2095
|
+
console.error(message(refusal));
|
|
2096
|
+
process.exitCode = 1;
|
|
2097
|
+
return;
|
|
2098
|
+
}
|
|
1989
2099
|
const res = await publishProfile(newProfile(handle, entries, extras), cred, {
|
|
1990
2100
|
ifMatch: own?.etag
|
|
1991
2101
|
});
|
|
@@ -2034,10 +2144,10 @@ var SET_USAGE = `usage: ymmv set <key> <value> | ${SET_EXTRA}`;
|
|
|
2034
2144
|
var EXTRA_USAGE = `usage: ${SET_EXTRA}`;
|
|
2035
2145
|
var UNSET_USAGE = `usage: ymmv unset <key> | ${UNSET_EXTRA}`;
|
|
2036
2146
|
var VIEW_USAGE = "usage: ymmv view <handle>";
|
|
2037
|
-
function invalidKeyError(
|
|
2147
|
+
function invalidKeyError(head2, hint) {
|
|
2038
2148
|
return {
|
|
2039
2149
|
kind: "error",
|
|
2040
|
-
message: `"${sanitizeValue(
|
|
2150
|
+
message: `"${sanitizeValue(head2)}" is not a curated key. Valid keys: ${CURATED_KEYS.join(", ")}.
|
|
2041
2151
|
For anything else, use: ${hint}.`
|
|
2042
2152
|
};
|
|
2043
2153
|
}
|
|
@@ -2061,9 +2171,15 @@ function valueCapError(value) {
|
|
|
2061
2171
|
message: `That value is ${value.length} characters; the cap is ${MAX_VALUE}.`
|
|
2062
2172
|
};
|
|
2063
2173
|
}
|
|
2174
|
+
function labelInvisibleError() {
|
|
2175
|
+
return { kind: "error", message: "That label has no visible text." };
|
|
2176
|
+
}
|
|
2177
|
+
function valueInvisibleError() {
|
|
2178
|
+
return { kind: "error", message: "That value has no visible text." };
|
|
2179
|
+
}
|
|
2064
2180
|
function parseSet(rest) {
|
|
2065
|
-
const
|
|
2066
|
-
if (
|
|
2181
|
+
const head2 = rest[0];
|
|
2182
|
+
if (head2 === "--extra" || head2 === "-e") {
|
|
2067
2183
|
const spec = rest.slice(1).join(" ").trim();
|
|
2068
2184
|
const eq = spec.indexOf("=");
|
|
2069
2185
|
if (eq <= 0) return { kind: "error", message: EXTRA_USAGE };
|
|
@@ -2071,30 +2187,33 @@ function parseSet(rest) {
|
|
|
2071
2187
|
const value2 = spec.slice(eq + 1).trim();
|
|
2072
2188
|
if (!label || !value2) return { kind: "error", message: EXTRA_USAGE };
|
|
2073
2189
|
if (value2 === "-") return { kind: "unset", target: { kind: "extra", label } };
|
|
2190
|
+
if (!showsVisibleText(label)) return labelInvisibleError();
|
|
2191
|
+
if (!showsVisibleText(value2)) return valueInvisibleError();
|
|
2074
2192
|
if (label.length > MAX_LABEL) return labelCapError(label);
|
|
2075
2193
|
if (value2.length > MAX_VALUE) return valueCapError(value2);
|
|
2076
2194
|
return { kind: "set", target: { kind: "extra", label, value: value2 } };
|
|
2077
2195
|
}
|
|
2078
|
-
if (!
|
|
2079
|
-
if (!isCuratedKey(
|
|
2196
|
+
if (!head2) return { kind: "error", message: SET_USAGE };
|
|
2197
|
+
if (!isCuratedKey(head2)) return invalidKeyError(head2, SET_EXTRA);
|
|
2080
2198
|
const value = rest.slice(1).join(" ").trim();
|
|
2081
|
-
if (!value) return { kind: "error", message: `usage: ymmv set ${
|
|
2082
|
-
if (value === "-") return { kind: "unset", target: { kind: "curated", key:
|
|
2199
|
+
if (!value) return { kind: "error", message: `usage: ymmv set ${head2} <value>` };
|
|
2200
|
+
if (value === "-") return { kind: "unset", target: { kind: "curated", key: head2 } };
|
|
2201
|
+
if (!showsVisibleText(value)) return valueInvisibleError();
|
|
2083
2202
|
if (value.length > MAX_VALUE) return valueCapError(value);
|
|
2084
|
-
return { kind: "set", target: { kind: "curated", key:
|
|
2203
|
+
return { kind: "set", target: { kind: "curated", key: head2, value } };
|
|
2085
2204
|
}
|
|
2086
2205
|
function parseUnset(rest) {
|
|
2087
|
-
const
|
|
2088
|
-
if (
|
|
2206
|
+
const head2 = rest[0];
|
|
2207
|
+
if (head2 === "--extra" || head2 === "-e") {
|
|
2089
2208
|
const label = rest.slice(1).join(" ").trim();
|
|
2090
2209
|
if (!label) return { kind: "error", message: `usage: ${UNSET_EXTRA}` };
|
|
2091
2210
|
if (label.length > MAX_LABEL) return labelCapError(label);
|
|
2092
2211
|
return { kind: "unset", target: { kind: "extra", label } };
|
|
2093
2212
|
}
|
|
2094
|
-
if (!
|
|
2095
|
-
if (!isCuratedKey(
|
|
2096
|
-
if (rest.length > 1) return { kind: "error", message: `usage: ymmv unset ${
|
|
2097
|
-
return { kind: "unset", target: { kind: "curated", key:
|
|
2213
|
+
if (!head2) return { kind: "error", message: UNSET_USAGE };
|
|
2214
|
+
if (!isCuratedKey(head2)) return invalidKeyError(head2, UNSET_EXTRA);
|
|
2215
|
+
if (rest.length > 1) return { kind: "error", message: `usage: ymmv unset ${head2}` };
|
|
2216
|
+
return { kind: "unset", target: { kind: "curated", key: head2 } };
|
|
2098
2217
|
}
|
|
2099
2218
|
function resolveArg(argv) {
|
|
2100
2219
|
const first = argv[0];
|