pollen-css
Version:
Utility-first CSS for the future
1,843 lines (1,670 loc) • 1.48 MB
JavaScript
#!/usr/bin/env node
import require$$0 from 'node:events';
import require$$1 from 'node:child_process';
import require$$2 from 'node:path';
import require$$3 from 'node:fs';
import require$$4 from 'node:process';
import fs6, { realpathSync, statSync, promises } from 'fs';
import * as path9 from 'path';
import path9__default, { dirname } from 'path';
import require$$2$1 from 'os';
import { createRequire, builtinModules } from 'module';
import url, { fileURLToPath, pathToFileURL, URL as URL$1 } from 'url';
import process3 from 'process';
import tty from 'tty';
import fs$2 from 'fs/promises';
import assert2 from 'assert';
import v8 from 'v8';
import { format as format$1, inspect } from 'util';
const isObject$2 = value => typeof value === 'object' && value !== null;
// Customized for this use-case
const isObjectCustom = value =>
isObject$2(value)
&& !(value instanceof RegExp)
&& !(value instanceof Error)
&& !(value instanceof Date)
&& !(globalThis.Blob && value instanceof globalThis.Blob);
const mapObjectSkip = Symbol('mapObjectSkip');
const _mapObject = (object, mapper, options, isSeen = new WeakMap()) => {
options = {
deep: false,
target: {},
...options,
};
if (isSeen.has(object)) {
return isSeen.get(object);
}
isSeen.set(object, options.target);
const {target} = options;
delete options.target;
const mapArray = array => array.map(element => isObjectCustom(element) ? _mapObject(element, mapper, options, isSeen) : element);
if (Array.isArray(object)) {
return mapArray(object);
}
for (const [key, value] of Object.entries(object)) {
const mapResult = mapper(key, value, object);
if (mapResult === mapObjectSkip) {
continue;
}
let [newKey, newValue, {shouldRecurse = true} = {}] = mapResult;
// Drop `__proto__` keys.
if (newKey === '__proto__') {
continue;
}
if (options.deep && shouldRecurse && isObjectCustom(newValue)) {
newValue = Array.isArray(newValue)
? mapArray(newValue)
: _mapObject(newValue, mapper, options, isSeen);
}
target[newKey] = newValue;
}
return target;
};
function mapObject(object, mapper, options) {
if (!isObject$2(object)) {
throw new TypeError(`Expected an object, got \`${object}\` (${typeof object})`);
}
if (Array.isArray(object)) {
throw new TypeError('Expected an object, got an array');
}
return _mapObject(object, mapper, options);
}
/**
* Colors
* For rapid visual prototyping
*/
var colors = {
color: {
black: "#000",
white: "#fff",
/* Grey */
"grey-50": "#f9fafb",
"grey-100": "#f3f4f6",
"grey-200": "#e5e7eb",
"grey-300": "#d1d5db",
"grey-400": "#9ca3af",
"grey-500": "#6b7280",
"grey-600": "#4b5563",
"grey-700": "#374151",
"grey-800": "#1f2937",
"grey-900": "#111827",
"grey-950": "#030712",
grey: "var(--color-gray-500)",
/* Slate */
"slate-50": "#f8fafc",
"slate-100": "#f1f5f9",
"slate-200": "#e2e8f0",
"slate-300": "#cbd5e1",
"slate-400": "#94a3b8",
"slate-500": "#64748b",
"slate-600": "#475569",
"slate-700": "#334155",
"slate-800": "#1e293b",
"slate-900": "#0f172a",
"slate-950": "#020617",
slate: "var(--color-slate-500)",
/* Zinc */
"zinc-50": "#fafafa",
"zinc-100": "#f4f4f5",
"zinc-200": "#e4e4e7",
"zinc-300": "#d4d4d8",
"zinc-400": "#a1a1aa",
"zinc-500": "#71717a",
"zinc-600": "#52525b",
"zinc-700": "#3f3f46",
"zinc-800": "#27272a",
"zinc-900": "#18181b",
"zinc-950": "#09090b",
zinc: "var(--color-zinc-500)",
/* Stone */
"stone-50": "#fafaf9",
"stone-100": "#f5f5f4",
"stone-200": "#e7e5e4",
"stone-300": "#d6d3d1",
"stone-400": "#a8a29e",
"stone-500": "#78716c",
"stone-600": "#57534e",
"stone-700": "#44403c",
"stone-800": "#292524",
"stone-900": "#1c1917",
"stone-950": "#0c0a09",
stone: "var(--color-stone-500)",
/* Red */
"red-50": "#fef2f2",
"red-100": "#fee2e2",
"red-200": "#fecaca",
"red-300": "#fca5a5",
"red-400": "#f87171",
"red-500": "#ef4444",
"red-600": "#dc2626",
"red-700": "#b91c1c",
"red-800": "#991b1b",
"red-900": "#7f1d1d",
"red-950": "#450a0a",
red: "var(--color-red-500)",
/* Orange */
"orange-50": "#fff7ed",
"orange-100": "#ffedd5",
"orange-200": "#fed7aa",
"orange-300": "#fdba74",
"orange-400": "#fb923c",
"orange-500": "#f97316",
"orange-600": "#ea580c",
"orange-700": "#c2410c",
"orange-800": "#9a3412",
"orange-900": "#7c2d12",
"orange-950": "#431407",
orange: "var(--color-orange-500)",
/* Amber */
"amber-50": "#fffbeb",
"amber-100": "#fef3c7",
"amber-200": "#fde68a",
"amber-300": "#fcd34d",
"amber-400": "#fbbf24",
"amber-500": "#f59e0b",
"amber-600": "#d97706",
"amber-700": "#b45309",
"amber-800": "#92400e",
"amber-900": "#78350f",
"amber-950": "#451a03",
amber: "var(--color-amber-500)",
/* Yellow */
"yellow-50": "#fefce8",
"yellow-100": "#fef9c3",
"yellow-200": "#fef08a",
"yellow-300": "#fde047",
"yellow-400": "#facc15",
"yellow-500": "#eab308",
"yellow-600": "#ca8a04",
"yellow-700": "#a16207",
"yellow-800": "#854d0e",
"yellow-900": "#713f12",
"yellow-950": "#422006",
yellow: "var(--color-yellow-500)",
/* Lime */
"lime-50": "#f7fee7",
"lime-100": "#ecfccb",
"lime-200": "#d9f99d",
"lime-300": "#bef264",
"lime-400": "#a3e635",
"lime-500": "#84cc16",
"lime-600": "#65a30d",
"lime-700": "#4d7c0f",
"lime-800": "#3f6212",
"lime-900": "#365314",
"lime-950": "#1a2e05",
lime: "var(--color-lime-500)",
/* Green */
"green-50": "#f0fdf4",
"green-100": "#dcfce7",
"green-200": "#bbf7d0",
"green-300": "#86efac",
"green-400": "#4ade80",
"green-500": "#22c55e",
"green-600": "#16a34a",
"green-700": "#15803d",
"green-800": "#166534",
"green-900": "#14532d",
"green-950": "#052e16",
green: "var(--color-green-500)",
/* Teal */
"teal-50": "#f0fdfa",
"teal-100": "#ccfbf1",
"teal-200": "#99f6e4",
"teal-300": "#5eead4",
"teal-400": "#2dd4bf",
"teal-500": "#14b8a6",
"teal-600": "#0d9488",
"teal-700": "#0f766e",
"teal-800": "#115e59",
"teal-900": "#134e4a",
"teal-950": "#042f2e",
teal: "var(--color-teal-500)",
/* Cyan */
"cyan-50": "#ecfeff",
"cyan-100": "#cffafe",
"cyan-200": "#a5f3fc",
"cyan-300": "#67e8f9",
"cyan-400": "#22d3ee",
"cyan-500": "#06b6d4",
"cyan-600": "#0891b2",
"cyan-700": "#0e7490",
"cyan-800": "#155e75",
"cyan-900": "#164e63",
"cyan-950": "#083344",
cyan: "var(--color-cyan-500)",
/* Sky */
"sky-50": "#f0f9ff",
"sky-100": "#e0f2fe",
"sky-200": "#bae6fd",
"sky-300": "#7dd3fc",
"sky-400": "#38bdf8",
"sky-500": "#0ea5e9",
"sky-600": "#0284c7",
"sky-700": "#0369a1",
"sky-800": "#075985",
"sky-900": "#0c4a6e",
"sky-950": "#082f49",
sky: "var(--color-sky-500)",
/* Blue */
"blue-50": "#eff6ff",
"blue-100": "#dbeafe",
"blue-200": "#bfdbfe",
"blue-300": "#93c5fd",
"blue-400": "#60a5fa",
"blue-500": "#3b82f6",
"blue-600": "#2563eb",
"blue-700": "#1d4ed8",
"blue-800": "#1e40af",
"blue-900": "#1e3a8a",
"blue-950": "#172554",
blue: "var(--color-blue-500)",
/* Indigo */
"indigo-50": "#eef2ff",
"indigo-100": "#e0e7ff",
"indigo-200": "#c7d2fe",
"indigo-300": "#a5b4fc",
"indigo-400": "#818cf8",
"indigo-500": "#6366f1",
"indigo-600": "#4f46e5",
"indigo-700": "#4338ca",
"indigo-800": "#3730a3",
"indigo-900": "#312e81",
"indigo-950": "#1e1b4b",
indigo: "var(--color-indigo-500)",
/* Violet */
"violet-50": "#f5f3ff",
"violet-100": "#ede9fe",
"violet-200": "#ddd6fe",
"violet-300": "#c4b5fd",
"violet-400": "#a78bfa",
"violet-500": "#8b5cf6",
"violet-600": "#7c3aed",
"violet-700": "#6d28d9",
"violet-800": "#5b21b6",
"violet-900": "#4c1d95",
"violet-950": "#2e1065",
violet: "var(--color-violet-500)",
/* Purple */
"purple-50": "#faf5ff",
"purple-100": "#f3e8ff",
"purple-200": "#e9d5ff",
"purple-300": "#d8b4fe",
"purple-400": "#c084fc",
"purple-500": "#a855f7",
"purple-600": "#9333ea",
"purple-700": "#7e22ce",
"purple-800": "#6b21a8",
"purple-900": "#581c87",
"purple-950": "#3b0764",
purple: "var(--color-purple-500)",
/* Fuchsia */
"fuchsia-50": "#fdf4ff",
"fuchsia-100": "#fae8ff",
"fuchsia-200": "#f5d0fe",
"fuchsia-300": "#f0abfc",
"fuchsia-400": "#e879f9",
"fuchsia-500": "#d946ef",
"fuchsia-600": "#c026d3",
"fuchsia-700": "#a21caf",
"fuchsia-800": "#86198f",
"fuchsia-900": "#701a75",
"fuchsia-950": "#4a044e",
fuchsia: "var(--color-fuchsia-500)",
/* Pink */
"pink-50": "#fdf2f8",
"pink-100": "#fce7f3",
"pink-200": "#fbcfe8",
"pink-300": "#f9a8d4",
"pink-400": "#f472b6",
"pink-500": "#ec4899",
"pink-600": "#db2777",
"pink-700": "#be185d",
"pink-800": "#9d174d",
"pink-900": "#831843",
"pink-950": "#500724",
pink: "var(--color-pink-500)",
/* Rose */
"rose-50": "#fff1f2",
"rose-100": "#ffe4e6",
"rose-200": "#fecdd3",
"rose-300": "#fda4af",
"rose-400": "#fb7185",
"rose-500": "#f43f5e",
"rose-600": "#e11d48",
"rose-700": "#be123c",
"rose-800": "#9f1239",
"rose-900": "#881337",
"rose-950": "#4c0519",
rose: "var(--color-rose-500)",
},
};
/**
* Grid
* Grid system helpers
*/
var grid = {
grid: {
/**
* Page Grid
* Applied to grid-template-columns
*/
"page-width": "var(--width-xl)",
"page-gutter": "5vw",
"page-main": "2 / 3",
page: "minmax(var(--grid-page-gutter), 1fr) minmax(0, var(--grid-page-width)) minmax(var(--grid-page-gutter), 1fr)",
/**
* Template Shorthands
* Applied to grid-template-[columns/rows]
*/
2: "repeat(2, minmax(0, 1fr))",
3: "repeat(3, minmax(0, 1fr))",
4: "repeat(4, minmax(0, 1fr))",
5: "repeat(5, minmax(0, 1fr))",
6: "repeat(6, minmax(0, 1fr))",
7: "repeat(7, minmax(0, 1fr))",
8: "repeat(8, minmax(0, 1fr))",
9: "repeat(9, minmax(0, 1fr))",
10: "repeat(10, minmax(0, 1fr))",
11: "repeat(11, minmax(0, 1fr))",
12: "repeat(12, minmax(0, 1fr))",
},
};
var layout = {
/**
* Size scale
* Applied to sizing properties
* Eg: margin, padding, width, height
*/
size: {
px: "1px",
1: "4px",
2: "8px",
3: "12px",
4: "16px",
5: "20px",
6: "24px",
7: "28px",
8: "32px",
9: "36px",
10: "40px",
11: "44px",
12: "48px",
14: "56px",
16: "64px",
20: "80px",
24: "96px",
28: "112px",
32: "128px",
36: "144px",
40: "160px",
44: "176px",
48: "192px",
52: "208px",
56: "224px",
60: "240px",
64: "256px",
72: "288px",
80: "320px",
96: "384px",
full: "100%",
screen: "100vw",
min: "min-content",
max: "max-content",
},
/**
* Container widths
* Applied as max-width
*/
width: {
xs: "480px",
sm: "640px",
md: "768px",
lg: "1024px",
xl: "1280px",
},
/**
* Aspect ratios
* Applied as aspect-ratio
*/
ratio: {
square: "1/1",
portrait: "3/4",
landscape: "4/3",
tall: "2/3",
wide: "3/2",
widescreen: "16/9",
golden: "1.618/1",
},
};
/**
* Fluid size utility
*/
function fluid(minSize, maxSize, minWidth = 480, maxWidth = 1280) {
const slope = (maxSize - minSize) / (maxWidth - minWidth);
const yAxisIntersection = -minWidth * slope + minSize;
return `clamp(${minSize / 16}rem, ${yAxisIntersection / 16}rem + ${slope * 100}vw, ${maxSize / 16}rem)`;
}
/**
* Typography
* For a foundation in type
*/
var typography = {
/**
* Modular scale
* Applied as font-size
*/
scale: {
"000": "0.75rem" /* 12px */,
"00": "0.875rem" /* 14px */,
"0": "1rem" /* 16px */,
"1": "1.125rem" /* 18px */,
"2": "1.25rem" /* 20px */,
"3": "1.5rem" /* 24px */,
"4": "1.875rem" /* 30px */,
"5": "2.25rem" /* 36px */,
"6": "3rem" /* 48px */,
"7": "3.75rem" /* 60px */,
"8": "4.5rem" /* 72px */,
"9": "6rem" /* 96px */,
"10": "8rem" /* 128px */,
},
/**
* Fluid type scale using generated clamp()
* Applied as font-size
*/
"scale-fluid": {
"000": fluid(10, 12),
"00": fluid(12, 14),
"0": fluid(14, 16),
"1": fluid(16, 18),
"2": fluid(18, 20),
"3": fluid(20, 24),
"4": fluid(24, 30),
"5": fluid(30, 36),
"6": fluid(36, 48),
"7": fluid(48, 60),
"8": fluid(60, 72),
"9": fluid(72, 96),
"10": fluid(96, 128),
},
/**
* Fonts
* Applied as font-family and font-weight
*/
font: {
sans: `ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"`,
serif: `ui-serif, Georgia, Cambria, "Times New Roman", Times, serif`,
mono: 'ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace',
},
weight: {
light: "300",
regular: "400",
medium: "500",
semibold: "600",
bold: "700",
extrabold: "800",
black: "900",
},
/**
* Line Heights
*/
line: {
none: 1,
xs: 1.125,
sm: 1.275,
md: 1.5,
lg: 1.625,
xl: 2,
},
/**
* Letter spacing
*/
letter: {
xs: "-0.05em",
sm: "-0.025em",
none: "0em",
lg: "0.025em",
xl: "0.05em",
},
/**
* Prose measure
* Applied as max-width
*/
prose: {
xs: "45ch",
sm: "55ch",
md: "65ch",
lg: "75ch",
xl: "85ch",
},
};
/**
* UI library
* For consistency across UI and motion
*/
var ui = {
/**
* Radiuses
* Applied as border-radius
*/
radius: {
xs: "3px",
sm: "6px",
md: "8px",
lg: "12px",
xl: "16px",
100: "100%",
full: "9999px",
},
/**
* Blurs
* Applied as backdrop-filter
*/
blur: {
xs: "blur(4px)",
sm: "blur(8px)",
md: "blur(16px)",
lg: "blur(24px)",
xl: "blur(40px)",
},
/**
* Layers
* Applied as z-index
*/
layer: {
below: -1,
1: 10,
2: 20,
3: 30,
4: 40,
5: 50,
top: 2147483647,
},
/**
* Shadow
* Applied as box-shadow
*/
shadow: {
xs: "0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px 0 rgba(0, 0, 0, 0.06)",
sm: "0 4px 6px -2px rgba(0, 0, 0, 0.1), 0 2px 4px -2px rgba(0, 0, 0, 0.06)",
md: "0 12px 16px -4px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05)",
lg: "0 20px 24px -4px rgba(0, 0, 0, 0.1), 0 8px 8px -4px rgba(0, 0, 0, 0.04)",
xl: "0 24px 48px -12px rgba(0, 0, 0, 0.25)",
},
/**
* Motion easing curves
* Appplied in transitions and animations
*/
ease: {
"in-sine": "cubic-bezier(0.47, 0, 0.745, 0.715)",
"out-sine": "cubic-bezier(0.39, 0.575, 0.565, 1)",
"in-out-sine": "cubic-bezier(0.445, 0.05, 0.55, 0.95)",
"in-quad": "cubic-bezier(0.55, 0.085, 0.68, 0.53)",
"out-quad": "cubic-bezier(0.25, 0.46, 0.45, 0.94)",
"in-out-quad": "cubic-bezier(0.455, 0.03, 0.515, 0.955)",
"in-cubic": "cubic-bezier(0.55, 0.055, 0.675, 0.19)",
"out-cubic": "cubic-bezier(0.215, 0.61, 0.355, 1)",
"in-out-cubic": "cubic-bezier(0.645, 0.045, 0.355, 1)",
"in-quart": "cubic-bezier(0.895, 0.03, 0.685, 0.22)",
"out-quart": "cubic-bezier(0.165, 0.84, 0.44, 1)",
"in-out-quart": "cubic-bezier(0.77, 0, 0.175, 1)",
"in-quint": "cubic-bezier(0.755, 0.05, 0.855, 0.06)",
"out-quint": "cubic-bezier(0.23, 1, 0.32, 1)",
"in-out-quint": "cubic-bezier(0.86, 0, 0.07, 1)",
"in-expo": "cubic-bezier(0.95, 0.05, 0.795, 0.035)",
"out-expo": "cubic-bezier(0.19, 1, 0.22, 1)",
"in-out-expo": "cubic-bezier(1, 0, 0, 1)",
"in-circ": "cubic-bezier(0.6, 0.04, 0.98, 0.335)",
"out-circ": "cubic-bezier(0.075, 0.82, 0.165, 1)",
"in-out-circ": "cubic-bezier(0.785, 0.135, 0.15, 0.86)",
"in-back": "cubic-bezier(0.6, -0.28, 0.735, 0.045)",
"out-back": "cubic-bezier(0.175, 0.885, 0.32, 1.275)",
"in-out-back": "cubic-bezier(0.68, -0.55, 0.265, 1.55)",
},
};
var modules = {
...typography,
...layout,
...ui,
...colors,
...grid,
};
var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
var commander = {};
var argument = {};
var error = {};
/**
* CommanderError class
*/
let CommanderError$3 = class CommanderError extends Error {
/**
* Constructs the CommanderError class
* @param {number} exitCode suggested exit code which could be used with process.exit
* @param {string} code an id string representing the error
* @param {string} message human-readable description of the error
*/
constructor(exitCode, code, message) {
super(message);
// properly capture stack trace in Node.js
Error.captureStackTrace(this, this.constructor);
this.name = this.constructor.name;
this.code = code;
this.exitCode = exitCode;
this.nestedError = undefined;
}
};
/**
* InvalidArgumentError class
*/
let InvalidArgumentError$4 = class InvalidArgumentError extends CommanderError$3 {
/**
* Constructs the InvalidArgumentError class
* @param {string} [message] explanation of why argument is invalid
*/
constructor(message) {
super(1, 'commander.invalidArgument', message);
// properly capture stack trace in Node.js
Error.captureStackTrace(this, this.constructor);
this.name = this.constructor.name;
}
};
error.CommanderError = CommanderError$3;
error.InvalidArgumentError = InvalidArgumentError$4;
const { InvalidArgumentError: InvalidArgumentError$3 } = error;
let Argument$3 = class Argument {
/**
* Initialize a new command argument with the given name and description.
* The default is that the argument is required, and you can explicitly
* indicate this with <> around the name. Put [] around the name for an optional argument.
*
* @param {string} name
* @param {string} [description]
*/
constructor(name, description) {
this.description = description || '';
this.variadic = false;
this.parseArg = undefined;
this.defaultValue = undefined;
this.defaultValueDescription = undefined;
this.argChoices = undefined;
switch (name[0]) {
case '<': // e.g. <required>
this.required = true;
this._name = name.slice(1, -1);
break;
case '[': // e.g. [optional]
this.required = false;
this._name = name.slice(1, -1);
break;
default:
this.required = true;
this._name = name;
break;
}
if (this._name.length > 3 && this._name.slice(-3) === '...') {
this.variadic = true;
this._name = this._name.slice(0, -3);
}
}
/**
* Return argument name.
*
* @return {string}
*/
name() {
return this._name;
}
/**
* @package
*/
_concatValue(value, previous) {
if (previous === this.defaultValue || !Array.isArray(previous)) {
return [value];
}
return previous.concat(value);
}
/**
* Set the default value, and optionally supply the description to be displayed in the help.
*
* @param {*} value
* @param {string} [description]
* @return {Argument}
*/
default(value, description) {
this.defaultValue = value;
this.defaultValueDescription = description;
return this;
}
/**
* Set the custom handler for processing CLI command arguments into argument values.
*
* @param {Function} [fn]
* @return {Argument}
*/
argParser(fn) {
this.parseArg = fn;
return this;
}
/**
* Only allow argument value to be one of choices.
*
* @param {string[]} values
* @return {Argument}
*/
choices(values) {
this.argChoices = values.slice();
this.parseArg = (arg, previous) => {
if (!this.argChoices.includes(arg)) {
throw new InvalidArgumentError$3(
`Allowed choices are ${this.argChoices.join(', ')}.`,
);
}
if (this.variadic) {
return this._concatValue(arg, previous);
}
return arg;
};
return this;
}
/**
* Make argument required.
*
* @returns {Argument}
*/
argRequired() {
this.required = true;
return this;
}
/**
* Make argument optional.
*
* @returns {Argument}
*/
argOptional() {
this.required = false;
return this;
}
};
/**
* Takes an argument and returns its human readable equivalent for help usage.
*
* @param {Argument} arg
* @return {string}
* @private
*/
function humanReadableArgName$2(arg) {
const nameOutput = arg.name() + (arg.variadic === true ? '...' : '');
return arg.required ? '<' + nameOutput + '>' : '[' + nameOutput + ']';
}
argument.Argument = Argument$3;
argument.humanReadableArgName = humanReadableArgName$2;
var command = {};
var help = {};
const { humanReadableArgName: humanReadableArgName$1 } = argument;
/**
* TypeScript import types for JSDoc, used by Visual Studio Code IntelliSense and `npm run typescript-checkJS`
* https://www.typescriptlang.org/docs/handbook/jsdoc-supported-types.html#import-types
* @typedef { import("./argument.js").Argument } Argument
* @typedef { import("./command.js").Command } Command
* @typedef { import("./option.js").Option } Option
*/
// Although this is a class, methods are static in style to allow override using subclass or just functions.
let Help$3 = class Help {
constructor() {
this.helpWidth = undefined;
this.sortSubcommands = false;
this.sortOptions = false;
this.showGlobalOptions = false;
}
/**
* Get an array of the visible subcommands. Includes a placeholder for the implicit help command, if there is one.
*
* @param {Command} cmd
* @returns {Command[]}
*/
visibleCommands(cmd) {
const visibleCommands = cmd.commands.filter((cmd) => !cmd._hidden);
const helpCommand = cmd._getHelpCommand();
if (helpCommand && !helpCommand._hidden) {
visibleCommands.push(helpCommand);
}
if (this.sortSubcommands) {
visibleCommands.sort((a, b) => {
// @ts-ignore: because overloaded return type
return a.name().localeCompare(b.name());
});
}
return visibleCommands;
}
/**
* Compare options for sort.
*
* @param {Option} a
* @param {Option} b
* @returns {number}
*/
compareOptions(a, b) {
const getSortKey = (option) => {
// WYSIWYG for order displayed in help. Short used for comparison if present. No special handling for negated.
return option.short
? option.short.replace(/^-/, '')
: option.long.replace(/^--/, '');
};
return getSortKey(a).localeCompare(getSortKey(b));
}
/**
* Get an array of the visible options. Includes a placeholder for the implicit help option, if there is one.
*
* @param {Command} cmd
* @returns {Option[]}
*/
visibleOptions(cmd) {
const visibleOptions = cmd.options.filter((option) => !option.hidden);
// Built-in help option.
const helpOption = cmd._getHelpOption();
if (helpOption && !helpOption.hidden) {
// Automatically hide conflicting flags. Bit dubious but a historical behaviour that is convenient for single-command programs.
const removeShort = helpOption.short && cmd._findOption(helpOption.short);
const removeLong = helpOption.long && cmd._findOption(helpOption.long);
if (!removeShort && !removeLong) {
visibleOptions.push(helpOption); // no changes needed
} else if (helpOption.long && !removeLong) {
visibleOptions.push(
cmd.createOption(helpOption.long, helpOption.description),
);
} else if (helpOption.short && !removeShort) {
visibleOptions.push(
cmd.createOption(helpOption.short, helpOption.description),
);
}
}
if (this.sortOptions) {
visibleOptions.sort(this.compareOptions);
}
return visibleOptions;
}
/**
* Get an array of the visible global options. (Not including help.)
*
* @param {Command} cmd
* @returns {Option[]}
*/
visibleGlobalOptions(cmd) {
if (!this.showGlobalOptions) return [];
const globalOptions = [];
for (
let ancestorCmd = cmd.parent;
ancestorCmd;
ancestorCmd = ancestorCmd.parent
) {
const visibleOptions = ancestorCmd.options.filter(
(option) => !option.hidden,
);
globalOptions.push(...visibleOptions);
}
if (this.sortOptions) {
globalOptions.sort(this.compareOptions);
}
return globalOptions;
}
/**
* Get an array of the arguments if any have a description.
*
* @param {Command} cmd
* @returns {Argument[]}
*/
visibleArguments(cmd) {
// Side effect! Apply the legacy descriptions before the arguments are displayed.
if (cmd._argsDescription) {
cmd.registeredArguments.forEach((argument) => {
argument.description =
argument.description || cmd._argsDescription[argument.name()] || '';
});
}
// If there are any arguments with a description then return all the arguments.
if (cmd.registeredArguments.find((argument) => argument.description)) {
return cmd.registeredArguments;
}
return [];
}
/**
* Get the command term to show in the list of subcommands.
*
* @param {Command} cmd
* @returns {string}
*/
subcommandTerm(cmd) {
// Legacy. Ignores custom usage string, and nested commands.
const args = cmd.registeredArguments
.map((arg) => humanReadableArgName$1(arg))
.join(' ');
return (
cmd._name +
(cmd._aliases[0] ? '|' + cmd._aliases[0] : '') +
(cmd.options.length ? ' [options]' : '') + // simplistic check for non-help option
(args ? ' ' + args : '')
);
}
/**
* Get the option term to show in the list of options.
*
* @param {Option} option
* @returns {string}
*/
optionTerm(option) {
return option.flags;
}
/**
* Get the argument term to show in the list of arguments.
*
* @param {Argument} argument
* @returns {string}
*/
argumentTerm(argument) {
return argument.name();
}
/**
* Get the longest command term length.
*
* @param {Command} cmd
* @param {Help} helper
* @returns {number}
*/
longestSubcommandTermLength(cmd, helper) {
return helper.visibleCommands(cmd).reduce((max, command) => {
return Math.max(max, helper.subcommandTerm(command).length);
}, 0);
}
/**
* Get the longest option term length.
*
* @param {Command} cmd
* @param {Help} helper
* @returns {number}
*/
longestOptionTermLength(cmd, helper) {
return helper.visibleOptions(cmd).reduce((max, option) => {
return Math.max(max, helper.optionTerm(option).length);
}, 0);
}
/**
* Get the longest global option term length.
*
* @param {Command} cmd
* @param {Help} helper
* @returns {number}
*/
longestGlobalOptionTermLength(cmd, helper) {
return helper.visibleGlobalOptions(cmd).reduce((max, option) => {
return Math.max(max, helper.optionTerm(option).length);
}, 0);
}
/**
* Get the longest argument term length.
*
* @param {Command} cmd
* @param {Help} helper
* @returns {number}
*/
longestArgumentTermLength(cmd, helper) {
return helper.visibleArguments(cmd).reduce((max, argument) => {
return Math.max(max, helper.argumentTerm(argument).length);
}, 0);
}
/**
* Get the command usage to be displayed at the top of the built-in help.
*
* @param {Command} cmd
* @returns {string}
*/
commandUsage(cmd) {
// Usage
let cmdName = cmd._name;
if (cmd._aliases[0]) {
cmdName = cmdName + '|' + cmd._aliases[0];
}
let ancestorCmdNames = '';
for (
let ancestorCmd = cmd.parent;
ancestorCmd;
ancestorCmd = ancestorCmd.parent
) {
ancestorCmdNames = ancestorCmd.name() + ' ' + ancestorCmdNames;
}
return ancestorCmdNames + cmdName + ' ' + cmd.usage();
}
/**
* Get the description for the command.
*
* @param {Command} cmd
* @returns {string}
*/
commandDescription(cmd) {
// @ts-ignore: because overloaded return type
return cmd.description();
}
/**
* Get the subcommand summary to show in the list of subcommands.
* (Fallback to description for backwards compatibility.)
*
* @param {Command} cmd
* @returns {string}
*/
subcommandDescription(cmd) {
// @ts-ignore: because overloaded return type
return cmd.summary() || cmd.description();
}
/**
* Get the option description to show in the list of options.
*
* @param {Option} option
* @return {string}
*/
optionDescription(option) {
const extraInfo = [];
if (option.argChoices) {
extraInfo.push(
// use stringify to match the display of the default value
`choices: ${option.argChoices.map((choice) => JSON.stringify(choice)).join(', ')}`,
);
}
if (option.defaultValue !== undefined) {
// default for boolean and negated more for programmer than end user,
// but show true/false for boolean option as may be for hand-rolled env or config processing.
const showDefault =
option.required ||
option.optional ||
(option.isBoolean() && typeof option.defaultValue === 'boolean');
if (showDefault) {
extraInfo.push(
`default: ${option.defaultValueDescription || JSON.stringify(option.defaultValue)}`,
);
}
}
// preset for boolean and negated are more for programmer than end user
if (option.presetArg !== undefined && option.optional) {
extraInfo.push(`preset: ${JSON.stringify(option.presetArg)}`);
}
if (option.envVar !== undefined) {
extraInfo.push(`env: ${option.envVar}`);
}
if (extraInfo.length > 0) {
return `${option.description} (${extraInfo.join(', ')})`;
}
return option.description;
}
/**
* Get the argument description to show in the list of arguments.
*
* @param {Argument} argument
* @return {string}
*/
argumentDescription(argument) {
const extraInfo = [];
if (argument.argChoices) {
extraInfo.push(
// use stringify to match the display of the default value
`choices: ${argument.argChoices.map((choice) => JSON.stringify(choice)).join(', ')}`,
);
}
if (argument.defaultValue !== undefined) {
extraInfo.push(
`default: ${argument.defaultValueDescription || JSON.stringify(argument.defaultValue)}`,
);
}
if (extraInfo.length > 0) {
const extraDescripton = `(${extraInfo.join(', ')})`;
if (argument.description) {
return `${argument.description} ${extraDescripton}`;
}
return extraDescripton;
}
return argument.description;
}
/**
* Generate the built-in help text.
*
* @param {Command} cmd
* @param {Help} helper
* @returns {string}
*/
formatHelp(cmd, helper) {
const termWidth = helper.padWidth(cmd, helper);
const helpWidth = helper.helpWidth || 80;
const itemIndentWidth = 2;
const itemSeparatorWidth = 2; // between term and description
function formatItem(term, description) {
if (description) {
const fullText = `${term.padEnd(termWidth + itemSeparatorWidth)}${description}`;
return helper.wrap(
fullText,
helpWidth - itemIndentWidth,
termWidth + itemSeparatorWidth,
);
}
return term;
}
function formatList(textArray) {
return textArray.join('\n').replace(/^/gm, ' '.repeat(itemIndentWidth));
}
// Usage
let output = [`Usage: ${helper.commandUsage(cmd)}`, ''];
// Description
const commandDescription = helper.commandDescription(cmd);
if (commandDescription.length > 0) {
output = output.concat([
helper.wrap(commandDescription, helpWidth, 0),
'',
]);
}
// Arguments
const argumentList = helper.visibleArguments(cmd).map((argument) => {
return formatItem(
helper.argumentTerm(argument),
helper.argumentDescription(argument),
);
});
if (argumentList.length > 0) {
output = output.concat(['Arguments:', formatList(argumentList), '']);
}
// Options
const optionList = helper.visibleOptions(cmd).map((option) => {
return formatItem(
helper.optionTerm(option),
helper.optionDescription(option),
);
});
if (optionList.length > 0) {
output = output.concat(['Options:', formatList(optionList), '']);
}
if (this.showGlobalOptions) {
const globalOptionList = helper
.visibleGlobalOptions(cmd)
.map((option) => {
return formatItem(
helper.optionTerm(option),
helper.optionDescription(option),
);
});
if (globalOptionList.length > 0) {
output = output.concat([
'Global Options:',
formatList(globalOptionList),
'',
]);
}
}
// Commands
const commandList = helper.visibleCommands(cmd).map((cmd) => {
return formatItem(
helper.subcommandTerm(cmd),
helper.subcommandDescription(cmd),
);
});
if (commandList.length > 0) {
output = output.concat(['Commands:', formatList(commandList), '']);
}
return output.join('\n');
}
/**
* Calculate the pad width from the maximum term length.
*
* @param {Command} cmd
* @param {Help} helper
* @returns {number}
*/
padWidth(cmd, helper) {
return Math.max(
helper.longestOptionTermLength(cmd, helper),
helper.longestGlobalOptionTermLength(cmd, helper),
helper.longestSubcommandTermLength(cmd, helper),
helper.longestArgumentTermLength(cmd, helper),
);
}
/**
* Wrap the given string to width characters per line, with lines after the first indented.
* Do not wrap if insufficient room for wrapping (minColumnWidth), or string is manually formatted.
*
* @param {string} str
* @param {number} width
* @param {number} indent
* @param {number} [minColumnWidth=40]
* @return {string}
*
*/
wrap(str, width, indent, minColumnWidth = 40) {
// Full \s characters, minus the linefeeds.
const indents =
' \\f\\t\\v\u00a0\u1680\u2000-\u200a\u202f\u205f\u3000\ufeff';
// Detect manually wrapped and indented strings by searching for line break followed by spaces.
const manualIndent = new RegExp(`[\\n][${indents}]+`);
if (str.match(manualIndent)) return str;
// Do not wrap if not enough room for a wrapped column of text (as could end up with a word per line).
const columnWidth = width - indent;
if (columnWidth < minColumnWidth) return str;
const leadingStr = str.slice(0, indent);
const columnText = str.slice(indent).replace('\r\n', '\n');
const indentString = ' '.repeat(indent);
const zeroWidthSpace = '\u200B';
const breaks = `\\s${zeroWidthSpace}`;
// Match line end (so empty lines don't collapse),
// or as much text as will fit in column, or excess text up to first break.
const regex = new RegExp(
`\n|.{1,${columnWidth - 1}}([${breaks}]|$)|[^${breaks}]+?([${breaks}]|$)`,
'g',
);
const lines = columnText.match(regex) || [];
return (
leadingStr +
lines
.map((line, i) => {
if (line === '\n') return ''; // preserve empty lines
return (i > 0 ? indentString : '') + line.trimEnd();
})
.join('\n')
);
}
};
help.Help = Help$3;
var option = {};
const { InvalidArgumentError: InvalidArgumentError$2 } = error;
let Option$3 = class Option {
/**
* Initialize a new `Option` with the given `flags` and `description`.
*
* @param {string} flags
* @param {string} [description]
*/
constructor(flags, description) {
this.flags = flags;
this.description = description || '';
this.required = flags.includes('<'); // A value must be supplied when the option is specified.
this.optional = flags.includes('['); // A value is optional when the option is specified.
// variadic test ignores <value,...> et al which might be used to describe custom splitting of single argument
this.variadic = /\w\.\.\.[>\]]$/.test(flags); // The option can take multiple values.
this.mandatory = false; // The option must have a value after parsing, which usually means it must be specified on command line.
const optionFlags = splitOptionFlags(flags);
this.short = optionFlags.shortFlag;
this.long = optionFlags.longFlag;
this.negate = false;
if (this.long) {
this.negate = this.long.startsWith('--no-');
}
this.defaultValue = undefined;
this.defaultValueDescription = undefined;
this.presetArg = undefined;
this.envVar = undefined;
this.parseArg = undefined;
this.hidden = false;
this.argChoices = undefined;
this.conflictsWith = [];
this.implied = undefined;
}
/**
* Set the default value, and optionally supply the description to be displayed in the help.
*
* @param {*} value
* @param {string} [description]
* @return {Option}
*/
default(value, description) {
this.defaultValue = value;
this.defaultValueDescription = description;
return this;
}
/**
* Preset to use when option used without option-argument, especially optional but also boolean and negated.
* The custom processing (parseArg) is called.
*
* @example
* new Option('--color').default('GREYSCALE').preset('RGB');
* new Option('--donate [amount]').preset('20').argParser(parseFloat);
*
* @param {*} arg
* @return {Option}
*/
preset(arg) {
this.presetArg = arg;
return this;
}
/**
* Add option name(s) that conflict with this option.
* An error will be displayed if conflicting options are found during parsing.
*
* @example
* new Option('--rgb').conflicts('cmyk');
* new Option('--js').conflicts(['ts', 'jsx']);
*
* @param {(string | string[])} names
* @return {Option}
*/
conflicts(names) {
this.conflictsWith = this.conflictsWith.concat(names);
return this;
}
/**
* Specify implied option values for when this option is set and the implied options are not.
*
* The custom processing (parseArg) is not called on the implied values.
*
* @example
* program
* .addOption(new Option('--log', 'write logging information to file'))
* .addOption(new Option('--trace', 'log extra details').implies({ log: 'trace.txt' }));
*
* @param {object} impliedOptionValues
* @return {Option}
*/
implies(impliedOptionValues) {
let newImplied = impliedOptionValues;
if (typeof impliedOptionValues === 'string') {
// string is not documented, but easy mistake and we can do what user probably intended.
newImplied = { [impliedOptionValues]: true };
}
this.implied = Object.assign(this.implied || {}, newImplied);
return this;
}
/**
* Set environment variable to check for option value.
*
* An environment variable is only used if when processed the current option value is
* undefined, or the source of the current value is 'default' or 'config' or 'env'.
*
* @param {string} name
* @return {Option}
*/
env(name) {
this.envVar = name;
return this;
}
/**
* Set the custom handler for processing CLI option arguments into option values.
*
* @param {Function} [fn]
* @return {Option}
*/
argParser(fn) {
this.parseArg = fn;
return this;
}
/**
* Whether the option is mandatory and must have a value after parsing.
*
* @param {boolean} [mandatory=true]
* @return {Option}
*/
makeOptionMandatory(mandatory = true) {
this.mandatory = !!mandatory;
return this;
}
/**
* Hide option in help.
*
* @param {boolean} [hide=true]
* @return {Option}
*/
hideHelp(hide = true) {
this.hidden = !!hide;
return this;
}
/**
* @package
*/
_concatValue(value, previous) {
if (previous === this.defaultValue || !Array.isArray(previous)) {
return [value];
}
return previous.concat(value);
}
/**
* Only allow option value to be one of choices.
*
* @param {string[]} values
* @return {Option}
*/
choices(values) {
this.argChoices = values.slice();
this.parseArg = (arg, previous) => {
if (!this.argChoices.includes(arg)) {
throw new InvalidArgumentError$2(
`Allowed choices are ${this.argChoices.join(', ')}.`,
);
}
if (this.variadic) {
return this._concatValue(arg, previous);
}
return arg;
};
return this;
}
/**
* Return option name.
*
* @return {string}
*/
name() {
if (this.long) {
return this.long.replace(/^--/, '');
}
return this.short.replace(/^-/, '');
}
/**
* Return option name, in a camelcase format that can be used
* as a object attribute key.
*
* @return {string}
*/
attributeName() {
return camelcase(this.name().replace(/^no-/, ''));
}
/**
* Check if `arg` matches the short or long flag.
*
* @param {string} arg
* @return {boolean}
* @package
*/
is(arg) {
return this.short === arg || this.long === arg;
}
/**
* Return whether a boolean option.
*
* Options are one of boolean, negated, required argument, or optional argument.
*
* @return {boolean}
* @package
*/
isBoolean() {
return !this.required && !this.optional && !this.negate;
}
};
/**
* This class is to make it easier to work with dual options, without changing the existing
* implementation. We support separate dual options for separate positive and negative options,
* like `--build` and `--no-build`, which share a single option value. This works nicely for some
* use cases, but is tricky for others where we want separate behaviours despite
* the single shared option value.
*/
let DualOptions$1 = class DualOptions {
/**
* @param {Option[]} options
*/
constructor(options) {
this.positiveOptions = new Map();
this.negativeOptions = new Map();
this.dualOptions = new Set();
options.forEach((option) => {
if (option.negate) {
this.negativeOptions.set(option.attributeName(), option);
} else {
this.positiveOptions.set(option.attributeName(), option);
}
});
this.negativeOptions.forEach((value, key) => {
if (this.positiveOptions.has(key)) {
this.dualOptions.add(key);
}
});
}
/**
* Did the value come from the option, and not from possible matching dual option?
*
* @param {*} value
* @param {Option} option
* @returns {boolean}
*/
valueFromOption(value, option) {
const optionKey = option.attributeName();
if (!this.dualOptions.has(optionKey)) return true;
// Use the value to deduce if (probably) came from the option.
const preset = this.negativeOptions.get(optionKey).presetArg;
const negativeValue = preset !== undefined ? preset : false;
return option.negate === (negativeValue === value);
}
};
/**
* Convert string from kebab-case to camelCase.
*
* @param {string} str
* @return {string}
* @private
*/
function camelcase(str) {
return str.split('-').reduce((str, word) => {
return str + word[0].toUpperCase() + word.slice(1);
});
}
/**
* Split the short and long flag out of something like '-m,--mixed <value>'
*
* @private
*/
function splitOptionFlags(flags) {
let shortFlag;
let longFlag;
// Use original very loose parsing to maintain backwards compatibility for now,
// which allowed for example unintended `-sw, --short-word` [sic].
const flagParts = flags.split(/[ |,]+/);
if (flagParts.length > 1 && !/^[[<]/.test(flagParts[1]))
shortFlag = flagParts.shift();
longFlag = flagParts.shift();
// Add support for lone short flag without significantly changing parsing!
if (!shortFlag && /^-[^-]$/.test(longFlag)) {
shortFlag = longFlag;
longFlag = undefined;
}
return { shortFlag, longFlag };
}
option.Option = Option$3;
option.DualOptions = DualOptions$1;
var suggestSimilar$2 = {};
const maxDistance = 3;
function editDistance(a, b) {
// https://en.wikipedia.org/wiki/Damerau–Levenshtein_distance
// Calculating optimal string alignment distance, no substring is edited more than once.
// (Simple implementation.)
// Quick early exit, return worst case.
if (Math.abs(a.length - b.length) > maxDistance)
return Math.max(a.length, b.length);
// distance between prefix substrings of a and b
const d = [];
// pure deletions turn a into empty string
for (let i = 0; i <= a.length; i++) {
d[i] = [i];
}
// pure insertions turn empty string into b
for (let j = 0; j <= b.length; j++) {
d[0][j] = j;
}
// fill matrix
for (let j = 1; j <= b.length; j++) {
for (let i = 1; i <= a.length; i++) {
let cost = 1;
if (a[i - 1] === b[j - 1]) {
cost = 0;
} else {
cost = 1;
}
d[i][j] = Math.min(
d[i - 1][j] + 1, // deletion
d[i][j - 1] + 1, // insertion
d[i - 1][j - 1] + cost, // substitution
);
// transposition
if (i > 1 && j > 1 && a[i - 1] === b[j - 2] && a[i - 2] === b[j - 1]) {
d[i][j] = Math.min(d[i][j], d[i - 2][j - 2] + 1);
}
}
}
return d[a.length][b.length];
}
/**
* Find close matches, restricted to same number of edits.
*
* @param {string} word
* @param {string[]} candidates
* @returns {string}
*/
function suggestSimilar$1(word, candidates) {
if (!candidates || candidates.length === 0) return '';
// remove possible duplicates
candidates = Array.from(new Set(candidates));
const searchingOptions = word.startsWith('--');
if (searchingOptions) {
word = word.slice(2);
candidates = candidates.map((candidate) => candidate.slice(2));
}
let similar = [];
let bestDistance = maxDistance;
const minSimilarity = 0.4;
candidates.forEach((candidate) => {
if (candidate.length <= 1) return; // no one character guesses
const distance = editDistance(word, candidate);
const length = Math.max(word.length, candidate.length);
const similarity = (length - distance) / length;
if (similarity > minSimilarity) {
if (distance < bestDistance) {
// better edit distance, throw away previous worse matches
bestDistance = distance;
similar = [candidate];
} else if (distance === bestDistance) {
similar.push(candidate);
}
}
});
similar.sort((a, b) => a.localeCompare(b));
if (searchingOptions) {
similar = similar.map((candidate) => `--${candidate}`);
}
if (similar.length > 1) {
return `\n(Did you mean one of ${similar.join(', ')}?)`;
}
if (similar.length === 1) {
return `\n(Did you mean ${similar[0]}?)`;
}
return '';
}
suggestSimilar$2.suggestSimilar = suggestSimilar$1;
const EventEmitter = require$$0.EventEmitter;
const childProcess = require$$1;
const path$1 = require$$2;
const fs$1 = require$$3;
const process$1 = require$$4;
const { Argument: Argument$2, humanReadableArgName } = argument;
const { CommanderError: CommanderError$2 } = error;
const { Help: Help$2 } = help;
const { Option: Option$2, DualOptions } = option;
const { suggestSimilar } = suggestSimilar$2;
let Command$2 = class Command extends EventEmitter {
/**
* Initialize a new `Command`.
*
* @param {string} [name]
*/
constructor(name) {
super();
/** @type {Command[]} */
this.commands = [];
/** @type {Option[]} *