@docker-doctor/cli 0.2.1 → 0.3.0
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 +22 -0
- package/dist/cli.cjs +468 -59
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.mjs +418 -10
- package/dist/cli.mjs.map +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts +8 -17
- package/dist/index.d.mts +8 -17
- package/dist/index.mjs +1 -1
- package/dist/{src-DvNFg6Nz.mjs → src-EqtziccA.mjs} +277 -111
- package/dist/src-EqtziccA.mjs.map +1 -0
- package/dist/{src-O8FXMq8O.cjs → src-TEhFWhpk.cjs} +277 -113
- package/dist/src-TEhFWhpk.cjs.map +1 -0
- package/package.json +2 -2
- package/dist/src-DvNFg6Nz.mjs.map +0 -1
- package/dist/src-O8FXMq8O.cjs.map +0 -1
package/dist/cli.cjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
const require_src = require('./src-
|
|
2
|
+
const require_src = require('./src-TEhFWhpk.cjs');
|
|
3
3
|
let node_fs_promises = require("node:fs/promises");
|
|
4
4
|
node_fs_promises = require_src.__toESM(node_fs_promises, 1);
|
|
5
5
|
let node_path = require("node:path");
|
|
@@ -9,10 +9,418 @@ node_os = require_src.__toESM(node_os, 1);
|
|
|
9
9
|
let node_readline = require("node:readline");
|
|
10
10
|
node_readline = require_src.__toESM(node_readline, 1);
|
|
11
11
|
let node_timers_promises = require("node:timers/promises");
|
|
12
|
-
let
|
|
13
|
-
|
|
12
|
+
let node_process = require("node:process");
|
|
13
|
+
node_process = require_src.__toESM(node_process, 1);
|
|
14
|
+
let node_tty = require("node:tty");
|
|
15
|
+
node_tty = require_src.__toESM(node_tty, 1);
|
|
14
16
|
let commander = require("commander");
|
|
15
17
|
|
|
18
|
+
//#region ../../node_modules/.bun/chalk@5.6.2/node_modules/chalk/source/vendor/ansi-styles/index.js
|
|
19
|
+
const ANSI_BACKGROUND_OFFSET = 10;
|
|
20
|
+
const wrapAnsi16 = (offset = 0) => (code) => `\u001B[${code + offset}m`;
|
|
21
|
+
const wrapAnsi256 = (offset = 0) => (code) => `\u001B[${38 + offset};5;${code}m`;
|
|
22
|
+
const wrapAnsi16m = (offset = 0) => (red, green, blue) => `\u001B[${38 + offset};2;${red};${green};${blue}m`;
|
|
23
|
+
const styles$1 = {
|
|
24
|
+
modifier: {
|
|
25
|
+
reset: [0, 0],
|
|
26
|
+
bold: [1, 22],
|
|
27
|
+
dim: [2, 22],
|
|
28
|
+
italic: [3, 23],
|
|
29
|
+
underline: [4, 24],
|
|
30
|
+
overline: [53, 55],
|
|
31
|
+
inverse: [7, 27],
|
|
32
|
+
hidden: [8, 28],
|
|
33
|
+
strikethrough: [9, 29]
|
|
34
|
+
},
|
|
35
|
+
color: {
|
|
36
|
+
black: [30, 39],
|
|
37
|
+
red: [31, 39],
|
|
38
|
+
green: [32, 39],
|
|
39
|
+
yellow: [33, 39],
|
|
40
|
+
blue: [34, 39],
|
|
41
|
+
magenta: [35, 39],
|
|
42
|
+
cyan: [36, 39],
|
|
43
|
+
white: [37, 39],
|
|
44
|
+
blackBright: [90, 39],
|
|
45
|
+
gray: [90, 39],
|
|
46
|
+
grey: [90, 39],
|
|
47
|
+
redBright: [91, 39],
|
|
48
|
+
greenBright: [92, 39],
|
|
49
|
+
yellowBright: [93, 39],
|
|
50
|
+
blueBright: [94, 39],
|
|
51
|
+
magentaBright: [95, 39],
|
|
52
|
+
cyanBright: [96, 39],
|
|
53
|
+
whiteBright: [97, 39]
|
|
54
|
+
},
|
|
55
|
+
bgColor: {
|
|
56
|
+
bgBlack: [40, 49],
|
|
57
|
+
bgRed: [41, 49],
|
|
58
|
+
bgGreen: [42, 49],
|
|
59
|
+
bgYellow: [43, 49],
|
|
60
|
+
bgBlue: [44, 49],
|
|
61
|
+
bgMagenta: [45, 49],
|
|
62
|
+
bgCyan: [46, 49],
|
|
63
|
+
bgWhite: [47, 49],
|
|
64
|
+
bgBlackBright: [100, 49],
|
|
65
|
+
bgGray: [100, 49],
|
|
66
|
+
bgGrey: [100, 49],
|
|
67
|
+
bgRedBright: [101, 49],
|
|
68
|
+
bgGreenBright: [102, 49],
|
|
69
|
+
bgYellowBright: [103, 49],
|
|
70
|
+
bgBlueBright: [104, 49],
|
|
71
|
+
bgMagentaBright: [105, 49],
|
|
72
|
+
bgCyanBright: [106, 49],
|
|
73
|
+
bgWhiteBright: [107, 49]
|
|
74
|
+
}
|
|
75
|
+
};
|
|
76
|
+
const modifierNames = Object.keys(styles$1.modifier);
|
|
77
|
+
const foregroundColorNames = Object.keys(styles$1.color);
|
|
78
|
+
const backgroundColorNames = Object.keys(styles$1.bgColor);
|
|
79
|
+
const colorNames = [...foregroundColorNames, ...backgroundColorNames];
|
|
80
|
+
function assembleStyles() {
|
|
81
|
+
const codes = /* @__PURE__ */ new Map();
|
|
82
|
+
for (const [groupName, group] of Object.entries(styles$1)) {
|
|
83
|
+
for (const [styleName, style] of Object.entries(group)) {
|
|
84
|
+
styles$1[styleName] = {
|
|
85
|
+
open: `\u001B[${style[0]}m`,
|
|
86
|
+
close: `\u001B[${style[1]}m`
|
|
87
|
+
};
|
|
88
|
+
group[styleName] = styles$1[styleName];
|
|
89
|
+
codes.set(style[0], style[1]);
|
|
90
|
+
}
|
|
91
|
+
Object.defineProperty(styles$1, groupName, {
|
|
92
|
+
value: group,
|
|
93
|
+
enumerable: false
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
Object.defineProperty(styles$1, "codes", {
|
|
97
|
+
value: codes,
|
|
98
|
+
enumerable: false
|
|
99
|
+
});
|
|
100
|
+
styles$1.color.close = "\x1B[39m";
|
|
101
|
+
styles$1.bgColor.close = "\x1B[49m";
|
|
102
|
+
styles$1.color.ansi = wrapAnsi16();
|
|
103
|
+
styles$1.color.ansi256 = wrapAnsi256();
|
|
104
|
+
styles$1.color.ansi16m = wrapAnsi16m();
|
|
105
|
+
styles$1.bgColor.ansi = wrapAnsi16(ANSI_BACKGROUND_OFFSET);
|
|
106
|
+
styles$1.bgColor.ansi256 = wrapAnsi256(ANSI_BACKGROUND_OFFSET);
|
|
107
|
+
styles$1.bgColor.ansi16m = wrapAnsi16m(ANSI_BACKGROUND_OFFSET);
|
|
108
|
+
Object.defineProperties(styles$1, {
|
|
109
|
+
rgbToAnsi256: {
|
|
110
|
+
value(red, green, blue) {
|
|
111
|
+
if (red === green && green === blue) {
|
|
112
|
+
if (red < 8) return 16;
|
|
113
|
+
if (red > 248) return 231;
|
|
114
|
+
return Math.round((red - 8) / 247 * 24) + 232;
|
|
115
|
+
}
|
|
116
|
+
return 16 + 36 * Math.round(red / 255 * 5) + 6 * Math.round(green / 255 * 5) + Math.round(blue / 255 * 5);
|
|
117
|
+
},
|
|
118
|
+
enumerable: false
|
|
119
|
+
},
|
|
120
|
+
hexToRgb: {
|
|
121
|
+
value(hex) {
|
|
122
|
+
const matches = /[a-f\d]{6}|[a-f\d]{3}/i.exec(hex.toString(16));
|
|
123
|
+
if (!matches) return [
|
|
124
|
+
0,
|
|
125
|
+
0,
|
|
126
|
+
0
|
|
127
|
+
];
|
|
128
|
+
let [colorString] = matches;
|
|
129
|
+
if (colorString.length === 3) colorString = [...colorString].map((character) => character + character).join("");
|
|
130
|
+
const integer = Number.parseInt(colorString, 16);
|
|
131
|
+
return [
|
|
132
|
+
integer >> 16 & 255,
|
|
133
|
+
integer >> 8 & 255,
|
|
134
|
+
integer & 255
|
|
135
|
+
];
|
|
136
|
+
},
|
|
137
|
+
enumerable: false
|
|
138
|
+
},
|
|
139
|
+
hexToAnsi256: {
|
|
140
|
+
value: (hex) => styles$1.rgbToAnsi256(...styles$1.hexToRgb(hex)),
|
|
141
|
+
enumerable: false
|
|
142
|
+
},
|
|
143
|
+
ansi256ToAnsi: {
|
|
144
|
+
value(code) {
|
|
145
|
+
if (code < 8) return 30 + code;
|
|
146
|
+
if (code < 16) return 90 + (code - 8);
|
|
147
|
+
let red;
|
|
148
|
+
let green;
|
|
149
|
+
let blue;
|
|
150
|
+
if (code >= 232) {
|
|
151
|
+
red = ((code - 232) * 10 + 8) / 255;
|
|
152
|
+
green = red;
|
|
153
|
+
blue = red;
|
|
154
|
+
} else {
|
|
155
|
+
code -= 16;
|
|
156
|
+
const remainder = code % 36;
|
|
157
|
+
red = Math.floor(code / 36) / 5;
|
|
158
|
+
green = Math.floor(remainder / 6) / 5;
|
|
159
|
+
blue = remainder % 6 / 5;
|
|
160
|
+
}
|
|
161
|
+
const value = Math.max(red, green, blue) * 2;
|
|
162
|
+
if (value === 0) return 30;
|
|
163
|
+
let result = 30 + (Math.round(blue) << 2 | Math.round(green) << 1 | Math.round(red));
|
|
164
|
+
if (value === 2) result += 60;
|
|
165
|
+
return result;
|
|
166
|
+
},
|
|
167
|
+
enumerable: false
|
|
168
|
+
},
|
|
169
|
+
rgbToAnsi: {
|
|
170
|
+
value: (red, green, blue) => styles$1.ansi256ToAnsi(styles$1.rgbToAnsi256(red, green, blue)),
|
|
171
|
+
enumerable: false
|
|
172
|
+
},
|
|
173
|
+
hexToAnsi: {
|
|
174
|
+
value: (hex) => styles$1.ansi256ToAnsi(styles$1.hexToAnsi256(hex)),
|
|
175
|
+
enumerable: false
|
|
176
|
+
}
|
|
177
|
+
});
|
|
178
|
+
return styles$1;
|
|
179
|
+
}
|
|
180
|
+
const ansiStyles = assembleStyles();
|
|
181
|
+
|
|
182
|
+
//#endregion
|
|
183
|
+
//#region ../../node_modules/.bun/chalk@5.6.2/node_modules/chalk/source/vendor/supports-color/index.js
|
|
184
|
+
function hasFlag(flag, argv = globalThis.Deno ? globalThis.Deno.args : node_process.default.argv) {
|
|
185
|
+
const prefix = flag.startsWith("-") ? "" : flag.length === 1 ? "-" : "--";
|
|
186
|
+
const position = argv.indexOf(prefix + flag);
|
|
187
|
+
const terminatorPosition = argv.indexOf("--");
|
|
188
|
+
return position !== -1 && (terminatorPosition === -1 || position < terminatorPosition);
|
|
189
|
+
}
|
|
190
|
+
const { env } = node_process.default;
|
|
191
|
+
let flagForceColor;
|
|
192
|
+
if (hasFlag("no-color") || hasFlag("no-colors") || hasFlag("color=false") || hasFlag("color=never")) flagForceColor = 0;
|
|
193
|
+
else if (hasFlag("color") || hasFlag("colors") || hasFlag("color=true") || hasFlag("color=always")) flagForceColor = 1;
|
|
194
|
+
function envForceColor() {
|
|
195
|
+
if ("FORCE_COLOR" in env) {
|
|
196
|
+
if (env.FORCE_COLOR === "true") return 1;
|
|
197
|
+
if (env.FORCE_COLOR === "false") return 0;
|
|
198
|
+
return env.FORCE_COLOR.length === 0 ? 1 : Math.min(Number.parseInt(env.FORCE_COLOR, 10), 3);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
function translateLevel(level) {
|
|
202
|
+
if (level === 0) return false;
|
|
203
|
+
return {
|
|
204
|
+
level,
|
|
205
|
+
hasBasic: true,
|
|
206
|
+
has256: level >= 2,
|
|
207
|
+
has16m: level >= 3
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
function _supportsColor(haveStream, { streamIsTTY, sniffFlags = true } = {}) {
|
|
211
|
+
const noFlagForceColor = envForceColor();
|
|
212
|
+
if (noFlagForceColor !== void 0) flagForceColor = noFlagForceColor;
|
|
213
|
+
const forceColor = sniffFlags ? flagForceColor : noFlagForceColor;
|
|
214
|
+
if (forceColor === 0) return 0;
|
|
215
|
+
if (sniffFlags) {
|
|
216
|
+
if (hasFlag("color=16m") || hasFlag("color=full") || hasFlag("color=truecolor")) return 3;
|
|
217
|
+
if (hasFlag("color=256")) return 2;
|
|
218
|
+
}
|
|
219
|
+
if ("TF_BUILD" in env && "AGENT_NAME" in env) return 1;
|
|
220
|
+
if (haveStream && !streamIsTTY && forceColor === void 0) return 0;
|
|
221
|
+
const min = forceColor || 0;
|
|
222
|
+
if (env.TERM === "dumb") return min;
|
|
223
|
+
if (node_process.default.platform === "win32") {
|
|
224
|
+
const osRelease = node_os.default.release().split(".");
|
|
225
|
+
if (Number(osRelease[0]) >= 10 && Number(osRelease[2]) >= 10586) return Number(osRelease[2]) >= 14931 ? 3 : 2;
|
|
226
|
+
return 1;
|
|
227
|
+
}
|
|
228
|
+
if ("CI" in env) {
|
|
229
|
+
if ([
|
|
230
|
+
"GITHUB_ACTIONS",
|
|
231
|
+
"GITEA_ACTIONS",
|
|
232
|
+
"CIRCLECI"
|
|
233
|
+
].some((key) => key in env)) return 3;
|
|
234
|
+
if ([
|
|
235
|
+
"TRAVIS",
|
|
236
|
+
"APPVEYOR",
|
|
237
|
+
"GITLAB_CI",
|
|
238
|
+
"BUILDKITE",
|
|
239
|
+
"DRONE"
|
|
240
|
+
].some((sign) => sign in env) || env.CI_NAME === "codeship") return 1;
|
|
241
|
+
return min;
|
|
242
|
+
}
|
|
243
|
+
if ("TEAMCITY_VERSION" in env) return /^(9\.(0*[1-9]\d*)\.|\d{2,}\.)/.test(env.TEAMCITY_VERSION) ? 1 : 0;
|
|
244
|
+
if (env.COLORTERM === "truecolor") return 3;
|
|
245
|
+
if (env.TERM === "xterm-kitty") return 3;
|
|
246
|
+
if (env.TERM === "xterm-ghostty") return 3;
|
|
247
|
+
if (env.TERM === "wezterm") return 3;
|
|
248
|
+
if ("TERM_PROGRAM" in env) {
|
|
249
|
+
const version = Number.parseInt((env.TERM_PROGRAM_VERSION || "").split(".")[0], 10);
|
|
250
|
+
switch (env.TERM_PROGRAM) {
|
|
251
|
+
case "iTerm.app": return version >= 3 ? 3 : 2;
|
|
252
|
+
case "Apple_Terminal": return 2;
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
if (/-256(color)?$/i.test(env.TERM)) return 2;
|
|
256
|
+
if (/^screen|^xterm|^vt100|^vt220|^rxvt|color|ansi|cygwin|linux/i.test(env.TERM)) return 1;
|
|
257
|
+
if ("COLORTERM" in env) return 1;
|
|
258
|
+
return min;
|
|
259
|
+
}
|
|
260
|
+
function createSupportsColor(stream, options = {}) {
|
|
261
|
+
return translateLevel(_supportsColor(stream, {
|
|
262
|
+
streamIsTTY: stream && stream.isTTY,
|
|
263
|
+
...options
|
|
264
|
+
}));
|
|
265
|
+
}
|
|
266
|
+
const supportsColor = {
|
|
267
|
+
stdout: createSupportsColor({ isTTY: node_tty.default.isatty(1) }),
|
|
268
|
+
stderr: createSupportsColor({ isTTY: node_tty.default.isatty(2) })
|
|
269
|
+
};
|
|
270
|
+
|
|
271
|
+
//#endregion
|
|
272
|
+
//#region ../../node_modules/.bun/chalk@5.6.2/node_modules/chalk/source/utilities.js
|
|
273
|
+
function stringReplaceAll(string, substring, replacer) {
|
|
274
|
+
let index = string.indexOf(substring);
|
|
275
|
+
if (index === -1) return string;
|
|
276
|
+
const substringLength = substring.length;
|
|
277
|
+
let endIndex = 0;
|
|
278
|
+
let returnValue = "";
|
|
279
|
+
do {
|
|
280
|
+
returnValue += string.slice(endIndex, index) + substring + replacer;
|
|
281
|
+
endIndex = index + substringLength;
|
|
282
|
+
index = string.indexOf(substring, endIndex);
|
|
283
|
+
} while (index !== -1);
|
|
284
|
+
returnValue += string.slice(endIndex);
|
|
285
|
+
return returnValue;
|
|
286
|
+
}
|
|
287
|
+
function stringEncaseCRLFWithFirstIndex(string, prefix, postfix, index) {
|
|
288
|
+
let endIndex = 0;
|
|
289
|
+
let returnValue = "";
|
|
290
|
+
do {
|
|
291
|
+
const gotCR = string[index - 1] === "\r";
|
|
292
|
+
returnValue += string.slice(endIndex, gotCR ? index - 1 : index) + prefix + (gotCR ? "\r\n" : "\n") + postfix;
|
|
293
|
+
endIndex = index + 1;
|
|
294
|
+
index = string.indexOf("\n", endIndex);
|
|
295
|
+
} while (index !== -1);
|
|
296
|
+
returnValue += string.slice(endIndex);
|
|
297
|
+
return returnValue;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
//#endregion
|
|
301
|
+
//#region ../../node_modules/.bun/chalk@5.6.2/node_modules/chalk/source/index.js
|
|
302
|
+
const { stdout: stdoutColor, stderr: stderrColor } = supportsColor;
|
|
303
|
+
const GENERATOR = Symbol("GENERATOR");
|
|
304
|
+
const STYLER = Symbol("STYLER");
|
|
305
|
+
const IS_EMPTY = Symbol("IS_EMPTY");
|
|
306
|
+
const levelMapping = [
|
|
307
|
+
"ansi",
|
|
308
|
+
"ansi",
|
|
309
|
+
"ansi256",
|
|
310
|
+
"ansi16m"
|
|
311
|
+
];
|
|
312
|
+
const styles = Object.create(null);
|
|
313
|
+
const applyOptions = (object, options = {}) => {
|
|
314
|
+
if (options.level && !(Number.isInteger(options.level) && options.level >= 0 && options.level <= 3)) throw new Error("The `level` option should be an integer from 0 to 3");
|
|
315
|
+
const colorLevel = stdoutColor ? stdoutColor.level : 0;
|
|
316
|
+
object.level = options.level === void 0 ? colorLevel : options.level;
|
|
317
|
+
};
|
|
318
|
+
const chalkFactory = (options) => {
|
|
319
|
+
const chalk = (...strings) => strings.join(" ");
|
|
320
|
+
applyOptions(chalk, options);
|
|
321
|
+
Object.setPrototypeOf(chalk, createChalk.prototype);
|
|
322
|
+
return chalk;
|
|
323
|
+
};
|
|
324
|
+
function createChalk(options) {
|
|
325
|
+
return chalkFactory(options);
|
|
326
|
+
}
|
|
327
|
+
Object.setPrototypeOf(createChalk.prototype, Function.prototype);
|
|
328
|
+
for (const [styleName, style] of Object.entries(ansiStyles)) styles[styleName] = { get() {
|
|
329
|
+
const builder = createBuilder(this, createStyler(style.open, style.close, this[STYLER]), this[IS_EMPTY]);
|
|
330
|
+
Object.defineProperty(this, styleName, { value: builder });
|
|
331
|
+
return builder;
|
|
332
|
+
} };
|
|
333
|
+
styles.visible = { get() {
|
|
334
|
+
const builder = createBuilder(this, this[STYLER], true);
|
|
335
|
+
Object.defineProperty(this, "visible", { value: builder });
|
|
336
|
+
return builder;
|
|
337
|
+
} };
|
|
338
|
+
const getModelAnsi = (model, level, type, ...arguments_) => {
|
|
339
|
+
if (model === "rgb") {
|
|
340
|
+
if (level === "ansi16m") return ansiStyles[type].ansi16m(...arguments_);
|
|
341
|
+
if (level === "ansi256") return ansiStyles[type].ansi256(ansiStyles.rgbToAnsi256(...arguments_));
|
|
342
|
+
return ansiStyles[type].ansi(ansiStyles.rgbToAnsi(...arguments_));
|
|
343
|
+
}
|
|
344
|
+
if (model === "hex") return getModelAnsi("rgb", level, type, ...ansiStyles.hexToRgb(...arguments_));
|
|
345
|
+
return ansiStyles[type][model](...arguments_);
|
|
346
|
+
};
|
|
347
|
+
for (const model of [
|
|
348
|
+
"rgb",
|
|
349
|
+
"hex",
|
|
350
|
+
"ansi256"
|
|
351
|
+
]) {
|
|
352
|
+
styles[model] = { get() {
|
|
353
|
+
const { level } = this;
|
|
354
|
+
return function(...arguments_) {
|
|
355
|
+
const styler = createStyler(getModelAnsi(model, levelMapping[level], "color", ...arguments_), ansiStyles.color.close, this[STYLER]);
|
|
356
|
+
return createBuilder(this, styler, this[IS_EMPTY]);
|
|
357
|
+
};
|
|
358
|
+
} };
|
|
359
|
+
const bgModel = "bg" + model[0].toUpperCase() + model.slice(1);
|
|
360
|
+
styles[bgModel] = { get() {
|
|
361
|
+
const { level } = this;
|
|
362
|
+
return function(...arguments_) {
|
|
363
|
+
const styler = createStyler(getModelAnsi(model, levelMapping[level], "bgColor", ...arguments_), ansiStyles.bgColor.close, this[STYLER]);
|
|
364
|
+
return createBuilder(this, styler, this[IS_EMPTY]);
|
|
365
|
+
};
|
|
366
|
+
} };
|
|
367
|
+
}
|
|
368
|
+
const proto = Object.defineProperties(() => {}, {
|
|
369
|
+
...styles,
|
|
370
|
+
level: {
|
|
371
|
+
enumerable: true,
|
|
372
|
+
get() {
|
|
373
|
+
return this[GENERATOR].level;
|
|
374
|
+
},
|
|
375
|
+
set(level) {
|
|
376
|
+
this[GENERATOR].level = level;
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
});
|
|
380
|
+
const createStyler = (open, close, parent) => {
|
|
381
|
+
let openAll;
|
|
382
|
+
let closeAll;
|
|
383
|
+
if (parent === void 0) {
|
|
384
|
+
openAll = open;
|
|
385
|
+
closeAll = close;
|
|
386
|
+
} else {
|
|
387
|
+
openAll = parent.openAll + open;
|
|
388
|
+
closeAll = close + parent.closeAll;
|
|
389
|
+
}
|
|
390
|
+
return {
|
|
391
|
+
open,
|
|
392
|
+
close,
|
|
393
|
+
openAll,
|
|
394
|
+
closeAll,
|
|
395
|
+
parent
|
|
396
|
+
};
|
|
397
|
+
};
|
|
398
|
+
const createBuilder = (self, _styler, _isEmpty) => {
|
|
399
|
+
const builder = (...arguments_) => applyStyle(builder, arguments_.length === 1 ? "" + arguments_[0] : arguments_.join(" "));
|
|
400
|
+
Object.setPrototypeOf(builder, proto);
|
|
401
|
+
builder[GENERATOR] = self;
|
|
402
|
+
builder[STYLER] = _styler;
|
|
403
|
+
builder[IS_EMPTY] = _isEmpty;
|
|
404
|
+
return builder;
|
|
405
|
+
};
|
|
406
|
+
const applyStyle = (self, string) => {
|
|
407
|
+
if (self.level <= 0 || !string) return self[IS_EMPTY] ? "" : string;
|
|
408
|
+
let styler = self[STYLER];
|
|
409
|
+
if (styler === void 0) return string;
|
|
410
|
+
const { openAll, closeAll } = styler;
|
|
411
|
+
if (string.includes("\x1B")) while (styler !== void 0) {
|
|
412
|
+
string = stringReplaceAll(string, styler.close, styler.open);
|
|
413
|
+
styler = styler.parent;
|
|
414
|
+
}
|
|
415
|
+
const lfIndex = string.indexOf("\n");
|
|
416
|
+
if (lfIndex !== -1) string = stringEncaseCRLFWithFirstIndex(string, closeAll, openAll, lfIndex);
|
|
417
|
+
return openAll + string + closeAll;
|
|
418
|
+
};
|
|
419
|
+
Object.defineProperties(createChalk.prototype, styles);
|
|
420
|
+
const chalk = createChalk();
|
|
421
|
+
const chalkStderr = createChalk({ level: stderrColor ? stderrColor.level : 0 });
|
|
422
|
+
|
|
423
|
+
//#endregion
|
|
16
424
|
//#region src/formatters/terminal.ts
|
|
17
425
|
const printCodeFrame = (content, line, severityColor) => {
|
|
18
426
|
if (!content || !line) return;
|
|
@@ -23,23 +431,23 @@ const printCodeFrame = (content, line, severityColor) => {
|
|
|
23
431
|
const rawLine = lines[i - 1];
|
|
24
432
|
const isTarget = i === line;
|
|
25
433
|
const lineNumberStr = String(i).padStart(5, " ");
|
|
26
|
-
if (isTarget) console.log(` ${severityColor(">")} ${chalk.
|
|
27
|
-
else console.log(` ${chalk.
|
|
434
|
+
if (isTarget) console.log(` ${severityColor(">")} ${chalk.bold(lineNumberStr)} │ ${chalk.white(rawLine)}`);
|
|
435
|
+
else console.log(` ${chalk.dim(lineNumberStr)} │ ${chalk.dim(rawLine)}`);
|
|
28
436
|
}
|
|
29
437
|
console.log();
|
|
30
438
|
};
|
|
31
439
|
const printDiscoveredFiles = (project) => {
|
|
32
440
|
console.log(`\nDiscovered Files:`);
|
|
33
|
-
console.log(` Dockerfile(s): ${project.dockerfiles.length ? project.dockerfiles.map((f) => chalk.
|
|
34
|
-
console.log(` Compose file(s): ${project.composeFiles.length ? project.composeFiles.map((f) => chalk.
|
|
441
|
+
console.log(` Dockerfile(s): ${project.dockerfiles.length ? project.dockerfiles.map((f) => chalk.cyan(f)).join(", ") : chalk.dim("None")}`);
|
|
442
|
+
console.log(` Compose file(s): ${project.composeFiles.length ? project.composeFiles.map((f) => chalk.cyan(f)).join(", ") : chalk.dim("None")}`);
|
|
35
443
|
};
|
|
36
444
|
const printDiagnostics = (diagnostics, verbose, fileContents, categoryIssueCounts) => {
|
|
37
445
|
if (diagnostics.length === 0) {
|
|
38
|
-
console.log(`\n${chalk.
|
|
446
|
+
console.log(`\n${chalk.green.bold("✔ No issues found! Your Docker setup looks healthy.")}`);
|
|
39
447
|
return;
|
|
40
448
|
}
|
|
41
449
|
if (!verbose) {
|
|
42
|
-
console.log(`\n All ${chalk.
|
|
450
|
+
console.log(`\n All ${chalk.bold(diagnostics.length)} issues\n`);
|
|
43
451
|
for (const cat of [
|
|
44
452
|
"Security",
|
|
45
453
|
"Performance",
|
|
@@ -49,16 +457,16 @@ const printDiagnostics = (diagnostics, verbose, fileContents, categoryIssueCount
|
|
|
49
457
|
]) {
|
|
50
458
|
const count = categoryIssueCounts[cat];
|
|
51
459
|
const issueLabel = count === 1 ? "1 issue" : `${count} issues`;
|
|
52
|
-
console.log(` ${cat} › ${chalk.
|
|
460
|
+
console.log(` ${cat} › ${chalk.dim(issueLabel)}`);
|
|
53
461
|
}
|
|
54
|
-
console.log(`\n Run ${chalk.
|
|
462
|
+
console.log(`\n Run ${chalk.cyan("docker-doctor --verbose")} to list every error and warning`);
|
|
55
463
|
const ruleCounts = {};
|
|
56
464
|
for (const d of diagnostics) ruleCounts[d.rule] = (ruleCounts[d.rule] || 0) + 1;
|
|
57
465
|
const migrationRules = Object.entries(ruleCounts).filter(([_, count]) => count >= 5);
|
|
58
466
|
if (migrationRules.length > 0) {
|
|
59
467
|
console.log();
|
|
60
|
-
console.log(` ${chalk.
|
|
61
|
-
for (const [rule, count] of migrationRules) console.log(` ${chalk.
|
|
468
|
+
console.log(` ${chalk.yellow("⚠ Migration-scale change: sample before you sweep")}`);
|
|
469
|
+
for (const [rule, count] of migrationRules) console.log(` ${chalk.cyan(rule)} ×${count} across ${count} files`);
|
|
62
470
|
console.log(` Fixing all of them at once is hard to review and prone to`);
|
|
63
471
|
console.log(` subtle mistakes across the whole repo. Fix a representative`);
|
|
64
472
|
console.log(` few first and confirm the recipe holds. Then get the code`);
|
|
@@ -67,30 +475,30 @@ const printDiagnostics = (diagnostics, verbose, fileContents, categoryIssueCount
|
|
|
67
475
|
}
|
|
68
476
|
return;
|
|
69
477
|
}
|
|
70
|
-
console.log(`\nFound ${chalk.
|
|
478
|
+
console.log(`\nFound ${chalk.bold(diagnostics.length)} issue(s):`);
|
|
71
479
|
const filesGrouped = {};
|
|
72
480
|
for (const d of diagnostics) {
|
|
73
481
|
if (!filesGrouped[d.file]) filesGrouped[d.file] = [];
|
|
74
482
|
filesGrouped[d.file].push(d);
|
|
75
483
|
}
|
|
76
484
|
for (const [file, fileDiags] of Object.entries(filesGrouped)) {
|
|
77
|
-
console.log(`\n${chalk.
|
|
485
|
+
console.log(`\n${chalk.underline.bold(file)}`);
|
|
78
486
|
for (const d of fileDiags) {
|
|
79
|
-
let sevColor = chalk.
|
|
487
|
+
let sevColor = chalk.cyan;
|
|
80
488
|
let prefix = "ℹ INFO";
|
|
81
489
|
if (d.severity === "error") {
|
|
82
|
-
sevColor = chalk.
|
|
490
|
+
sevColor = chalk.red.bold;
|
|
83
491
|
prefix = "✖ ERROR";
|
|
84
492
|
} else if (d.severity === "warning") {
|
|
85
|
-
sevColor = chalk.
|
|
493
|
+
sevColor = chalk.yellow;
|
|
86
494
|
prefix = "⚠ WARN";
|
|
87
495
|
}
|
|
88
496
|
const lineInfo = d.line ? `:${d.line}` : "";
|
|
89
|
-
console.log(` ${sevColor(prefix)} [${chalk.
|
|
497
|
+
console.log(` ${sevColor(prefix)} [${chalk.dim(d.rule)}]${lineInfo}`);
|
|
90
498
|
const content = fileContents[file];
|
|
91
499
|
printCodeFrame(content, d.line, sevColor);
|
|
92
|
-
console.log(` ${chalk.
|
|
93
|
-
console.log(` ${chalk.
|
|
500
|
+
console.log(` ${chalk.white(d.message)}`);
|
|
501
|
+
console.log(` ${chalk.dim("Help:")} ${d.help}`);
|
|
94
502
|
console.log();
|
|
95
503
|
}
|
|
96
504
|
}
|
|
@@ -100,10 +508,10 @@ const getWhaleMascot = (score, border) => {
|
|
|
100
508
|
let spout = " ";
|
|
101
509
|
if (score >= 75) {
|
|
102
510
|
eyes = "◠ ◠";
|
|
103
|
-
spout = chalk.
|
|
511
|
+
spout = chalk.cyan(" \":\" ");
|
|
104
512
|
} else if (score >= 50) {
|
|
105
513
|
eyes = "• •";
|
|
106
|
-
spout = chalk.
|
|
514
|
+
spout = chalk.cyan(" . ");
|
|
107
515
|
}
|
|
108
516
|
return [
|
|
109
517
|
spout,
|
|
@@ -116,10 +524,10 @@ const easeOutCubic = (x) => 1 - (1 - x) ** 3;
|
|
|
116
524
|
const printScoreBox = async (score, label, categoryIssueCounts, warningsCount, errorsCount) => {
|
|
117
525
|
const { isTTY } = process.stdout;
|
|
118
526
|
const shouldAnimate = isTTY && !process.env.CI && !process.env.NO_ANIMATION && process.env.TERM !== "dumb" && process.env.NODE_ENV !== "test";
|
|
119
|
-
let scoreColor = chalk.
|
|
120
|
-
if (score >= 90) scoreColor = chalk.
|
|
121
|
-
else if (score >= 75) scoreColor = chalk.
|
|
122
|
-
else if (score >= 50) scoreColor = chalk.
|
|
527
|
+
let scoreColor = chalk.red.bold;
|
|
528
|
+
if (score >= 90) scoreColor = chalk.green.bold;
|
|
529
|
+
else if (score >= 75) scoreColor = chalk.yellow.bold;
|
|
530
|
+
else if (score >= 50) scoreColor = chalk.magenta.bold;
|
|
123
531
|
const whaleLines = getWhaleMascot(score, scoreColor);
|
|
124
532
|
const shareUrl = `https://docker-doctor.vercel.app/share?s=${score}&w=${warningsCount}&e=${errorsCount}`;
|
|
125
533
|
if (shouldAnimate) {
|
|
@@ -132,10 +540,10 @@ const printScoreBox = async (score, label, categoryIssueCounts, warningsCount, e
|
|
|
132
540
|
const currentScore = Math.round(score * progress);
|
|
133
541
|
const filledBlocks = Math.round(currentScore / 2);
|
|
134
542
|
const emptyBlocks = 50 - filledBlocks;
|
|
135
|
-
const bar = scoreColor("█".repeat(filledBlocks)) + chalk.
|
|
543
|
+
const bar = scoreColor("█".repeat(filledBlocks)) + chalk.dim("░".repeat(emptyBlocks));
|
|
136
544
|
if (frame > 0) process.stdout.write("\x1B[4A\r");
|
|
137
545
|
else console.log();
|
|
138
|
-
process.stdout.write(` ${whaleLines[0]} ${scoreColor(`${currentScore} / 100`)} ${scoreColor(label)}\n ${whaleLines[1]} ${bar}\n ${whaleLines[2]} ${chalk.
|
|
546
|
+
process.stdout.write(` ${whaleLines[0]} ${scoreColor(`${currentScore} / 100`)} ${scoreColor(label)}\n ${whaleLines[1]} ${bar}\n ${whaleLines[2]} ${chalk.dim("Docker Doctor (https://docker-doctor.vercel.app)")}\n ${whaleLines[3]}\n`);
|
|
139
547
|
if (frame < frameCount) await (0, node_timers_promises.setTimeout)(frameDelay);
|
|
140
548
|
}
|
|
141
549
|
} finally {
|
|
@@ -144,24 +552,24 @@ const printScoreBox = async (score, label, categoryIssueCounts, warningsCount, e
|
|
|
144
552
|
} else {
|
|
145
553
|
const filledBlocks = Math.round(score / 2);
|
|
146
554
|
const emptyBlocks = 50 - filledBlocks;
|
|
147
|
-
const bar = scoreColor("█".repeat(filledBlocks)) + chalk.
|
|
555
|
+
const bar = scoreColor("█".repeat(filledBlocks)) + chalk.dim("░".repeat(emptyBlocks));
|
|
148
556
|
console.log(`\n ${whaleLines[0]} ${scoreColor(`${score} / 100`)} ${scoreColor(label)}`);
|
|
149
557
|
console.log(` ${whaleLines[1]} ${bar}`);
|
|
150
|
-
console.log(` ${whaleLines[2]} ${chalk.
|
|
558
|
+
console.log(` ${whaleLines[2]} ${chalk.dim("Docker Doctor (https://docker-doctor.vercel.app)")}`);
|
|
151
559
|
console.log(` ${whaleLines[3]}`);
|
|
152
560
|
}
|
|
153
|
-
console.log(`\n ${chalk.
|
|
154
|
-
console.log(` Share: ${chalk.
|
|
561
|
+
console.log(`\n ${chalk.dim("────────────────────────────────────────────────────────────")}\n`);
|
|
562
|
+
console.log(` Share: ${chalk.cyan(shareUrl)}`);
|
|
155
563
|
console.log(` Tell others how you did on socials\n`);
|
|
156
|
-
console.log(` Docs: ${chalk.
|
|
564
|
+
console.log(` Docs: ${chalk.cyan("https://docker-doctor.vercel.app")}`);
|
|
157
565
|
console.log(` Learn more about fixing issues, setting up CI/CD, and`);
|
|
158
566
|
console.log(` configuring rules with a config file\n`);
|
|
159
|
-
console.log(` GitHub: ${chalk.
|
|
567
|
+
console.log(` GitHub: ${chalk.cyan("https://github.com/PunGrumpy/docker-doctor")}`);
|
|
160
568
|
console.log(` Report issues and star the repository!`);
|
|
161
569
|
};
|
|
162
570
|
const formatTerminal = async (diagnostics, score, label, project, verbose = false, fileContents = {}) => {
|
|
163
571
|
if (verbose) {
|
|
164
|
-
console.log(`\n${chalk.
|
|
572
|
+
console.log(`\n${chalk.bold("Docker Doctor Diagnostics")}`);
|
|
165
573
|
console.log(`=================================`);
|
|
166
574
|
printDiscoveredFiles(project);
|
|
167
575
|
}
|
|
@@ -196,12 +604,12 @@ const askConfirm = (question, defaultYes = false) => {
|
|
|
196
604
|
process.stdout.write("\x1B[?25l");
|
|
197
605
|
const render = (firstTime = false) => {
|
|
198
606
|
if (!firstTime) process.stdout.write("\x1B[3A\r");
|
|
199
|
-
process.stdout.write(`\r\u001B[K ${chalk.
|
|
200
|
-
const yesPrefix = value ? chalk.
|
|
201
|
-
const yesText = value ? chalk.
|
|
607
|
+
process.stdout.write(`\r\u001B[K ${chalk.green("✔")} ${chalk.bold(question)}\n`);
|
|
608
|
+
const yesPrefix = value ? chalk.cyan("❯ ") : " ";
|
|
609
|
+
const yesText = value ? chalk.cyan.bold("Yes") : chalk.dim("Yes");
|
|
202
610
|
process.stdout.write(`\r\u001B[K${yesPrefix}${yesText}\n`);
|
|
203
|
-
const noPrefix = value ? " " : chalk.
|
|
204
|
-
const noText = value ? chalk.
|
|
611
|
+
const noPrefix = value ? " " : chalk.cyan("❯ ");
|
|
612
|
+
const noText = value ? chalk.dim("No") : chalk.cyan.bold("No");
|
|
205
613
|
process.stdout.write(`\r\u001B[K${noPrefix}${noText}\n`);
|
|
206
614
|
};
|
|
207
615
|
render(true);
|
|
@@ -224,7 +632,7 @@ const askConfirm = (question, defaultYes = false) => {
|
|
|
224
632
|
} else if (key.name === "return" || key.name === "enter" || str === "\r" || str === "\n") {
|
|
225
633
|
cleanup();
|
|
226
634
|
process.stdout.write("\x1B[3A\r\x1B[K");
|
|
227
|
-
process.stdout.write(` ${chalk.
|
|
635
|
+
process.stdout.write(` ${chalk.green("✔")} ${chalk.bold(question)} › ${value ? chalk.cyan("Yes") : chalk.dim("No")}\n`);
|
|
228
636
|
process.stdout.write("\r\x1B[K\n");
|
|
229
637
|
process.stdout.write("\r\x1B[K\n");
|
|
230
638
|
process.stdout.write("\x1B[2A");
|
|
@@ -248,12 +656,12 @@ const askSelect = (question, options, defaultIndex = 0) => {
|
|
|
248
656
|
process.stdout.write("\x1B[?25l");
|
|
249
657
|
const render = (firstTime = false) => {
|
|
250
658
|
if (!firstTime) process.stdout.write(`\u001B[${options.length + 1}A\r`);
|
|
251
|
-
process.stdout.write(`\r\u001B[K ${chalk.
|
|
659
|
+
process.stdout.write(`\r\u001B[K ${chalk.green("✔")} ${chalk.bold(question)}\n`);
|
|
252
660
|
let i = 0;
|
|
253
661
|
for (const option of options) {
|
|
254
662
|
const isSelected = i === index;
|
|
255
|
-
const prefix = isSelected ? chalk.
|
|
256
|
-
const text = isSelected ? chalk.
|
|
663
|
+
const prefix = isSelected ? chalk.cyan("❯ ") : " ";
|
|
664
|
+
const text = isSelected ? chalk.cyan.bold(option) : chalk.dim(option);
|
|
257
665
|
process.stdout.write(`\r\u001B[K${prefix}${text}\n`);
|
|
258
666
|
i += 1;
|
|
259
667
|
}
|
|
@@ -275,7 +683,7 @@ const askSelect = (question, options, defaultIndex = 0) => {
|
|
|
275
683
|
} else if (key.name === "return" || key.name === "enter" || str === "\r" || str === "\n") {
|
|
276
684
|
cleanup();
|
|
277
685
|
process.stdout.write(`\u001B[${options.length + 1}A\r\u001B[K`);
|
|
278
|
-
process.stdout.write(` ${chalk.
|
|
686
|
+
process.stdout.write(` ${chalk.green("✔")} ${chalk.bold(question)} › ${chalk.cyan(options[index])}\n`);
|
|
279
687
|
for (const _ of options) process.stdout.write("\r\x1B[K\n");
|
|
280
688
|
process.stdout.write(`\u001B[${options.length}A`);
|
|
281
689
|
resolve(index);
|
|
@@ -312,12 +720,12 @@ jobs:
|
|
|
312
720
|
- name: Run docker-doctor
|
|
313
721
|
run: bunx docker-doctor .
|
|
314
722
|
`, "utf-8");
|
|
315
|
-
console.log(`\n ${chalk.
|
|
723
|
+
console.log(`\n ${chalk.green("✨")} Created ${chalk.cyan(".github/workflows/docker-doctor.yml")}!`);
|
|
316
724
|
console.log(` Scan every pull request to prevent new Docker issues while you fix the backlog.`);
|
|
317
725
|
}
|
|
318
726
|
if (await askSelect("What would you like to do next?", ["View rules list", "Skip"]) === 0) {
|
|
319
|
-
console.log(`\n ${chalk.
|
|
320
|
-
for (const r of require_src.allRules) console.log(` - ${chalk.
|
|
727
|
+
console.log(`\n ${chalk.bold("Available Rules:")}`);
|
|
728
|
+
for (const r of require_src.allRules) console.log(` - ${chalk.cyan(r.key)}: ${r.message} (${chalk.dim(r.category)})`);
|
|
321
729
|
}
|
|
322
730
|
} catch {}
|
|
323
731
|
};
|
|
@@ -409,9 +817,9 @@ program.argument("[dir]", "directory to scan", ".").option("-v, --verbose", "sho
|
|
|
409
817
|
};
|
|
410
818
|
if (process.stdout.isTTY && !isSilent) {
|
|
411
819
|
process.stdout.write("\x1B[?25l");
|
|
412
|
-
process.stdout.write(`${chalk.
|
|
820
|
+
process.stdout.write(`${chalk.cyan(spinnerFrames[0])} ${statusText}`);
|
|
413
821
|
spinnerInterval = setInterval(() => {
|
|
414
|
-
process.stdout.write(`\r\u001B[K${chalk.
|
|
822
|
+
process.stdout.write(`\r\u001B[K${chalk.cyan(spinnerFrames[frameIndex])} ${statusText}`);
|
|
415
823
|
frameIndex = (frameIndex + 1) % spinnerFrames.length;
|
|
416
824
|
}, 80);
|
|
417
825
|
}
|
|
@@ -437,21 +845,22 @@ program.argument("[dir]", "directory to scan", ".").option("-v, --verbose", "sho
|
|
|
437
845
|
spinnerInterval = null;
|
|
438
846
|
process.stdout.write("\r\x1B[K\x1B[?25h");
|
|
439
847
|
}
|
|
440
|
-
if (process.stdout.isTTY && !isSilent) console.log(`${chalk.
|
|
848
|
+
if (process.stdout.isTTY && !isSilent) console.log(`${chalk.green("✔")} Scanned ${projectFilesList.length} files in ${duration}s [~${concurrency} workers]`);
|
|
441
849
|
if (options.score) {
|
|
442
850
|
console.log(score);
|
|
443
|
-
process.
|
|
851
|
+
process.exitCode = score < 50 ? 1 : 0;
|
|
852
|
+
return;
|
|
444
853
|
} else if (options.json) {
|
|
445
854
|
const report = require_src.toJsonReport(filteredDiagnostics, score, label, project);
|
|
446
855
|
console.log(JSON.stringify(report, null, 2));
|
|
447
856
|
const hasErrors = filteredDiagnostics.some((d) => d.severity === "error");
|
|
448
|
-
process.
|
|
449
|
-
|
|
450
|
-
await formatTerminal(filteredDiagnostics, score, label, project, options.verbose, fileContents);
|
|
451
|
-
const hasErrors = filteredDiagnostics.some((d) => d.severity === "error");
|
|
452
|
-
if (process.stdout.isTTY && process.stdin.isTTY) await runInteractiveWizard();
|
|
453
|
-
process.exit(hasErrors ? 1 : 0);
|
|
857
|
+
process.exitCode = hasErrors ? 1 : 0;
|
|
858
|
+
return;
|
|
454
859
|
}
|
|
860
|
+
await formatTerminal(filteredDiagnostics, score, label, project, options.verbose, fileContents);
|
|
861
|
+
const hasErrors = filteredDiagnostics.some((d) => d.severity === "error");
|
|
862
|
+
if (process.stdout.isTTY && process.stdin.isTTY) await runInteractiveWizard();
|
|
863
|
+
process.exitCode = hasErrors ? 1 : 0;
|
|
455
864
|
} finally {
|
|
456
865
|
if (spinnerInterval !== null) {
|
|
457
866
|
clearInterval(spinnerInterval);
|