cssprobe-cli 0.1.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/AGENTS.md +77 -0
- package/LICENSE +21 -0
- package/README.md +218 -0
- package/bin/cssprobe-cli.js +6 -0
- package/dist/browser/launcher.d.ts +25 -0
- package/dist/browser/launcher.js +213 -0
- package/dist/cli/command.d.ts +27 -0
- package/dist/cli/command.js +84 -0
- package/dist/cli/commands.d.ts +42 -0
- package/dist/cli/commands.js +166 -0
- package/dist/cli/minimist.d.ts +9 -0
- package/dist/cli/minimist.js +120 -0
- package/dist/cli/output.d.ts +26 -0
- package/dist/cli/output.js +80 -0
- package/dist/cli/program.d.ts +1 -0
- package/dist/cli/program.js +381 -0
- package/dist/collector-bundle.js +342 -0
- package/dist/config/config.d.ts +23 -0
- package/dist/config/config.js +128 -0
- package/dist/config/helpGenerator.d.ts +10 -0
- package/dist/config/helpGenerator.js +156 -0
- package/dist/engine/analyzer.d.ts +2 -0
- package/dist/engine/analyzer.js +385 -0
- package/dist/engine/collector.d.ts +3 -0
- package/dist/engine/collector.js +291 -0
- package/dist/engine/renderer.d.ts +3 -0
- package/dist/engine/renderer.js +159 -0
- package/dist/engine/types.d.ts +130 -0
- package/dist/engine/types.js +4 -0
- package/dist/help.json +107 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +6 -0
- package/dist/installer/index.d.ts +3 -0
- package/dist/installer/index.js +12 -0
- package/dist/installer/skill-template.d.ts +9 -0
- package/dist/installer/skill-template.js +274 -0
- package/dist/installer/targets/registry.d.ts +9 -0
- package/dist/installer/targets/registry.js +121 -0
- package/dist/installer/targets/shared.d.ts +9 -0
- package/dist/installer/targets/shared.js +112 -0
- package/dist/installer/targets/types.d.ts +22 -0
- package/dist/installer/targets/types.js +3 -0
- package/docs/guide/installation.md +230 -0
- package/package.json +51 -0
|
@@ -0,0 +1,342 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __cssprobe_cli = (() => {
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
+
var __export = (target, all) => {
|
|
8
|
+
for (var name in all)
|
|
9
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
10
|
+
};
|
|
11
|
+
var __copyProps = (to, from, except, desc) => {
|
|
12
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
13
|
+
for (let key of __getOwnPropNames(from))
|
|
14
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
15
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
16
|
+
}
|
|
17
|
+
return to;
|
|
18
|
+
};
|
|
19
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
20
|
+
|
|
21
|
+
// src/engine/collector.ts
|
|
22
|
+
var collector_exports = {};
|
|
23
|
+
__export(collector_exports, {
|
|
24
|
+
classifyShape: () => classifyShape,
|
|
25
|
+
collect: () => collect
|
|
26
|
+
});
|
|
27
|
+
var WANTED_PROPS = [
|
|
28
|
+
// layout
|
|
29
|
+
"height",
|
|
30
|
+
"max-height",
|
|
31
|
+
"min-height",
|
|
32
|
+
"width",
|
|
33
|
+
"max-width",
|
|
34
|
+
"min-width",
|
|
35
|
+
"overflow",
|
|
36
|
+
"overflow-x",
|
|
37
|
+
"overflow-y",
|
|
38
|
+
"position",
|
|
39
|
+
"display",
|
|
40
|
+
"box-sizing",
|
|
41
|
+
"flex",
|
|
42
|
+
"flex-grow",
|
|
43
|
+
"flex-shrink",
|
|
44
|
+
"flex-basis",
|
|
45
|
+
"flex-direction",
|
|
46
|
+
"align-items",
|
|
47
|
+
"justify-content",
|
|
48
|
+
"align-self",
|
|
49
|
+
"grid-template-columns",
|
|
50
|
+
"grid-template-rows",
|
|
51
|
+
"top",
|
|
52
|
+
"left",
|
|
53
|
+
"right",
|
|
54
|
+
"bottom",
|
|
55
|
+
"margin",
|
|
56
|
+
"margin-top",
|
|
57
|
+
"margin-bottom",
|
|
58
|
+
"margin-left",
|
|
59
|
+
"margin-right",
|
|
60
|
+
"padding",
|
|
61
|
+
"padding-top",
|
|
62
|
+
"padding-bottom",
|
|
63
|
+
"transform",
|
|
64
|
+
"filter",
|
|
65
|
+
"perspective",
|
|
66
|
+
"will-change",
|
|
67
|
+
"contain",
|
|
68
|
+
"z-index",
|
|
69
|
+
"visibility",
|
|
70
|
+
"opacity",
|
|
71
|
+
// visual (colors / backgrounds / fonts)
|
|
72
|
+
"color",
|
|
73
|
+
"background",
|
|
74
|
+
"background-color",
|
|
75
|
+
"background-image",
|
|
76
|
+
"background-size",
|
|
77
|
+
"background-position",
|
|
78
|
+
"background-repeat",
|
|
79
|
+
"font-family",
|
|
80
|
+
"font-size",
|
|
81
|
+
"font-weight",
|
|
82
|
+
"font-style",
|
|
83
|
+
"line-height",
|
|
84
|
+
"text-align",
|
|
85
|
+
"letter-spacing",
|
|
86
|
+
"text-transform"
|
|
87
|
+
];
|
|
88
|
+
function matchDeclarations(el, wantedProps, crossOriginBlocked, blockedSheetUrls) {
|
|
89
|
+
const out = {};
|
|
90
|
+
let scanned = 0;
|
|
91
|
+
for (const sheet of Array.from(document.styleSheets)) {
|
|
92
|
+
let rules = null;
|
|
93
|
+
let accessible = true;
|
|
94
|
+
try {
|
|
95
|
+
rules = sheet.cssRules;
|
|
96
|
+
} catch (_e) {
|
|
97
|
+
accessible = false;
|
|
98
|
+
crossOriginBlocked.count++;
|
|
99
|
+
const short = (sheet.href || "unknown").split("/").pop() || "unknown";
|
|
100
|
+
if (!blockedSheetUrls.includes(short)) blockedSheetUrls.push(short);
|
|
101
|
+
continue;
|
|
102
|
+
}
|
|
103
|
+
if (!rules) continue;
|
|
104
|
+
for (const rule of Array.from(rules)) {
|
|
105
|
+
const styleRule = rule;
|
|
106
|
+
if (styleRule.selectorText && el.matches && el.matches(styleRule.selectorText)) {
|
|
107
|
+
const decls = styleRule.style;
|
|
108
|
+
for (const p of wantedProps) {
|
|
109
|
+
const v = decls.getPropertyValue(p);
|
|
110
|
+
if (v) {
|
|
111
|
+
(out[p] = out[p] || []).push({
|
|
112
|
+
selector: styleRule.selectorText,
|
|
113
|
+
value: v.trim(),
|
|
114
|
+
href: (sheet.href || "").split("/").slice(-2).join("/"),
|
|
115
|
+
accessible
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
scanned += 1;
|
|
121
|
+
if (scanned > 8e3) return out;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
for (const p of wantedProps) {
|
|
125
|
+
const iv = el.style.getPropertyValue(p);
|
|
126
|
+
if (iv && !(out[p] || []).some((d) => d.selector === "inline")) {
|
|
127
|
+
(out[p] = out[p] || []).push({ selector: "inline", value: iv.trim(), href: "", accessible: true });
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
return out;
|
|
131
|
+
}
|
|
132
|
+
function classifyShape(cs, declared) {
|
|
133
|
+
const display = cs.display;
|
|
134
|
+
const position = cs.position;
|
|
135
|
+
const flexDir = cs.flexDirection;
|
|
136
|
+
const overflowY = cs.overflowY;
|
|
137
|
+
const overflowX = cs.overflowX;
|
|
138
|
+
let role = "block";
|
|
139
|
+
if (position === "fixed") role = "fixed";
|
|
140
|
+
else if (position === "absolute") role = "absolute";
|
|
141
|
+
else if (position === "sticky") role = "sticky";
|
|
142
|
+
else if (display === "grid" || display === "inline-grid") role = "grid";
|
|
143
|
+
else if (display === "flex" || display === "inline-flex") {
|
|
144
|
+
role = flexDir === "column" ? "flex-col" : "flex-row";
|
|
145
|
+
} else if (display === "inline" || display === "inline-block") role = "inline";
|
|
146
|
+
const isScrollY = overflowY === "auto" || overflowY === "scroll";
|
|
147
|
+
const isScrollX = overflowX === "auto" || overflowX === "scroll";
|
|
148
|
+
const scrollTag = isScrollY ? isScrollX ? "scroll-xy" : "scroll-y" : isScrollX ? "scroll-x" : "";
|
|
149
|
+
const getDeclared = (prop) => {
|
|
150
|
+
const arr = declared && declared[prop];
|
|
151
|
+
if (!arr || arr.length === 0) return null;
|
|
152
|
+
const inline = arr.find((d) => d.selector === "inline");
|
|
153
|
+
return inline ? inline.value : arr[0].value;
|
|
154
|
+
};
|
|
155
|
+
const sizeClass = (prop, maxProp) => {
|
|
156
|
+
const val = getDeclared(prop);
|
|
157
|
+
const maxVal = getDeclared(maxProp);
|
|
158
|
+
if (val) {
|
|
159
|
+
if (/^(0|[1-9]\d*)(\.\d+)?(px|pt|cm|mm|in)$/.test(val)) return "fixed";
|
|
160
|
+
if (/^(0|[1-9]\d*)(\.\d+)?(vh|vw|vmin|vmax)$/.test(val)) return "viewport";
|
|
161
|
+
if (val.endsWith("%")) return "percent";
|
|
162
|
+
if (/^calc\(/.test(val)) return "calc";
|
|
163
|
+
if (val === "min-content" || val === "max-content" || val === "fit-content") return "content";
|
|
164
|
+
}
|
|
165
|
+
if (maxVal && maxVal !== "none" && maxVal !== "auto") return "constrained";
|
|
166
|
+
return "content";
|
|
167
|
+
};
|
|
168
|
+
const heightStrategy = sizeClass("height", "max-height");
|
|
169
|
+
const widthStrategy = sizeClass("width", "max-width");
|
|
170
|
+
const isFlexChild = !!(getDeclared("flex-grow") || getDeclared("flex-shrink") || getDeclared("flex-basis") || getDeclared("flex"));
|
|
171
|
+
return { role, scrollTag, heightStrategy, widthStrategy, isFlexChild };
|
|
172
|
+
}
|
|
173
|
+
var CB_PROPS = ["transform", "filter", "perspective", "willChange", "contain"];
|
|
174
|
+
function collectNode(el, maxText, crossOriginBlocked, blockedSheetUrls) {
|
|
175
|
+
try {
|
|
176
|
+
const cs = getComputedStyle(el);
|
|
177
|
+
const rect = el.getBoundingClientRect();
|
|
178
|
+
if (!rect) return null;
|
|
179
|
+
const props = {};
|
|
180
|
+
const LAYOUT_PROPS = [
|
|
181
|
+
"position",
|
|
182
|
+
"display",
|
|
183
|
+
"height",
|
|
184
|
+
"width",
|
|
185
|
+
"minHeight",
|
|
186
|
+
"maxHeight",
|
|
187
|
+
"overflowX",
|
|
188
|
+
"overflowY",
|
|
189
|
+
"boxSizing",
|
|
190
|
+
"margin",
|
|
191
|
+
"padding",
|
|
192
|
+
"flexDirection",
|
|
193
|
+
"flexGrow",
|
|
194
|
+
"flexShrink",
|
|
195
|
+
"flexBasis",
|
|
196
|
+
"alignItems",
|
|
197
|
+
"justifyContent",
|
|
198
|
+
"transform",
|
|
199
|
+
"filter",
|
|
200
|
+
"perspective",
|
|
201
|
+
"willChange",
|
|
202
|
+
"contain",
|
|
203
|
+
"zIndex",
|
|
204
|
+
"top",
|
|
205
|
+
"left",
|
|
206
|
+
"right",
|
|
207
|
+
"bottom",
|
|
208
|
+
"visibility",
|
|
209
|
+
"opacity"
|
|
210
|
+
];
|
|
211
|
+
for (const p of LAYOUT_PROPS) props[p] = cs[p] ?? "";
|
|
212
|
+
const text = (el.textContent || "").replace(/\s+/g, " ").trim().slice(0, maxText);
|
|
213
|
+
const declared = matchDeclarations(el, WANTED_PROPS, crossOriginBlocked, blockedSheetUrls);
|
|
214
|
+
const shape = classifyShape(cs, declared);
|
|
215
|
+
const rawClass = el.getAttribute("class") || "";
|
|
216
|
+
return {
|
|
217
|
+
tag: el.tagName.toLowerCase(),
|
|
218
|
+
id: el.id || null,
|
|
219
|
+
classes: rawClass.split(/\s+/).filter(Boolean),
|
|
220
|
+
inlineStyle: el.getAttribute("style") || null,
|
|
221
|
+
text,
|
|
222
|
+
props,
|
|
223
|
+
declared,
|
|
224
|
+
shape,
|
|
225
|
+
metrics: {
|
|
226
|
+
rect: {
|
|
227
|
+
x: +rect.x.toFixed(1),
|
|
228
|
+
y: +rect.y.toFixed(1),
|
|
229
|
+
width: +rect.width.toFixed(1),
|
|
230
|
+
height: +rect.height.toFixed(1)
|
|
231
|
+
},
|
|
232
|
+
rectBottom: +rect.bottom.toFixed(1),
|
|
233
|
+
rectRight: +rect.right.toFixed(1),
|
|
234
|
+
offsetHeight: el.offsetHeight,
|
|
235
|
+
clientHeight: el.clientHeight,
|
|
236
|
+
scrollHeight: el.scrollHeight,
|
|
237
|
+
clientWidth: el.clientWidth,
|
|
238
|
+
scrollWidth: el.scrollWidth
|
|
239
|
+
},
|
|
240
|
+
flags: {
|
|
241
|
+
overflowsViewport: rect.bottom > innerHeight + 1 || rect.right > innerWidth + 1,
|
|
242
|
+
overflowsParent: rect.bottom > (el.parentElement ? el.parentElement.getBoundingClientRect().bottom + 1 : innerHeight),
|
|
243
|
+
hasScrollY: el.scrollHeight > el.clientHeight + 1,
|
|
244
|
+
hasScrollX: el.scrollWidth > el.clientWidth + 1,
|
|
245
|
+
scrollable: (cs.overflowY === "auto" || cs.overflowY === "scroll") && el.scrollHeight > el.clientHeight + 1 && el.clientHeight > 0
|
|
246
|
+
},
|
|
247
|
+
containingBlockModifiers: CB_PROPS.filter((p) => {
|
|
248
|
+
const v = cs[p];
|
|
249
|
+
return v && v !== "none" && v !== "auto" && v !== "normal" && v !== "visible" && v !== "false";
|
|
250
|
+
}).map((p) => `${p}: ${cs[p]}`)
|
|
251
|
+
};
|
|
252
|
+
} catch (_e) {
|
|
253
|
+
return null;
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
function isSameShape(a, b) {
|
|
257
|
+
return !!a && !!b && a.tagName === b.tagName && a.id === b.id && (a.getAttribute("class") || "") === (b.getAttribute("class") || "");
|
|
258
|
+
}
|
|
259
|
+
function buildTree(el, depth, state, maxNodes, crossOriginBlocked, blockedSheetUrls) {
|
|
260
|
+
if (!el || state.count >= maxNodes || depth < 0) return null;
|
|
261
|
+
state.count += 1;
|
|
262
|
+
const collected = collectNode(el, 40, crossOriginBlocked, blockedSheetUrls);
|
|
263
|
+
if (!collected) return null;
|
|
264
|
+
const node = { ...collected, children: [] };
|
|
265
|
+
const kids = Array.from(el.children);
|
|
266
|
+
if (depth > 0) {
|
|
267
|
+
let i = 0;
|
|
268
|
+
while (i < kids.length) {
|
|
269
|
+
const run = [kids[i]];
|
|
270
|
+
let j = i + 1;
|
|
271
|
+
while (j < kids.length && isSameShape(kids[i], kids[j])) {
|
|
272
|
+
run.push(kids[j]);
|
|
273
|
+
j += 1;
|
|
274
|
+
}
|
|
275
|
+
const rep = buildTree(run[0], depth - 1, state, maxNodes, crossOriginBlocked, blockedSheetUrls);
|
|
276
|
+
if (rep) {
|
|
277
|
+
node.children.push({ ...rep, repeat: run.length });
|
|
278
|
+
}
|
|
279
|
+
i = j;
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
return node;
|
|
283
|
+
}
|
|
284
|
+
function walkUp(el, stopTag) {
|
|
285
|
+
const chain = [];
|
|
286
|
+
let cur = el;
|
|
287
|
+
while (cur && cur.tagName.toLowerCase() !== stopTag) {
|
|
288
|
+
chain.unshift(cur);
|
|
289
|
+
cur = cur.parentElement;
|
|
290
|
+
}
|
|
291
|
+
if (cur) chain.unshift(cur);
|
|
292
|
+
return chain;
|
|
293
|
+
}
|
|
294
|
+
function collect(cfg) {
|
|
295
|
+
const crossOriginBlocked = { count: 0 };
|
|
296
|
+
const blockedSheetUrls = [];
|
|
297
|
+
const viewport = { width: window.innerWidth, height: window.innerHeight };
|
|
298
|
+
const root = document.querySelector(cfg.rootSelector);
|
|
299
|
+
if (!root) {
|
|
300
|
+
const candidates = Array.from(document.querySelectorAll('.s-kit-modal, [class*="dialog"], [class*="modal"], [class*="popup"]')).slice(0, 5).map((el) => `${el.tagName}.${(el.getAttribute("class") || "").split(/\s+/).filter(Boolean).join(".")}`);
|
|
301
|
+
return {
|
|
302
|
+
rootSelector: cfg.rootSelector,
|
|
303
|
+
upTo: cfg.upTo,
|
|
304
|
+
downDepth: cfg.downDepth,
|
|
305
|
+
maxNodes: cfg.maxNodes,
|
|
306
|
+
nodeCount: 0,
|
|
307
|
+
viewport,
|
|
308
|
+
ancestors: [],
|
|
309
|
+
tree: null,
|
|
310
|
+
crossOriginBlocked: crossOriginBlocked.count,
|
|
311
|
+
blockedSheetUrls: blockedSheetUrls.slice(0, 5),
|
|
312
|
+
error: `\u672A\u627E\u5230 ${cfg.rootSelector}`,
|
|
313
|
+
candidates
|
|
314
|
+
};
|
|
315
|
+
}
|
|
316
|
+
const ancestors = walkUp(root, cfg.upTo).map((el) => collectNode(el, 30, crossOriginBlocked, blockedSheetUrls)).filter((n) => n !== null).map((n) => ({
|
|
317
|
+
label: `${n.tag}.${n.classes.join(".")}`,
|
|
318
|
+
props: n.props,
|
|
319
|
+
metrics: n.metrics,
|
|
320
|
+
flags: n.flags,
|
|
321
|
+
declared: n.declared,
|
|
322
|
+
shape: n.shape,
|
|
323
|
+
containingBlockModifiers: n.containingBlockModifiers,
|
|
324
|
+
inlineStyle: n.inlineStyle
|
|
325
|
+
}));
|
|
326
|
+
const state = { count: 0 };
|
|
327
|
+
const tree = buildTree(root, cfg.downDepth, state, cfg.maxNodes, crossOriginBlocked, blockedSheetUrls);
|
|
328
|
+
return {
|
|
329
|
+
rootSelector: cfg.rootSelector,
|
|
330
|
+
upTo: cfg.upTo,
|
|
331
|
+
downDepth: cfg.downDepth,
|
|
332
|
+
maxNodes: cfg.maxNodes,
|
|
333
|
+
nodeCount: state.count,
|
|
334
|
+
viewport,
|
|
335
|
+
ancestors,
|
|
336
|
+
tree,
|
|
337
|
+
crossOriginBlocked: crossOriginBlocked.count,
|
|
338
|
+
blockedSheetUrls: blockedSheetUrls.slice(0, 5)
|
|
339
|
+
};
|
|
340
|
+
}
|
|
341
|
+
return __toCommonJS(collector_exports);
|
|
342
|
+
})();
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { MinimistArgs } from '../cli/minimist';
|
|
2
|
+
export interface ProfileConfig {
|
|
3
|
+
browser?: string;
|
|
4
|
+
depth?: string;
|
|
5
|
+
headed?: string;
|
|
6
|
+
}
|
|
7
|
+
export interface Config {
|
|
8
|
+
browser: string;
|
|
9
|
+
depth: number;
|
|
10
|
+
headed: boolean;
|
|
11
|
+
output: 'text' | 'json';
|
|
12
|
+
raw: boolean;
|
|
13
|
+
}
|
|
14
|
+
export declare const rcFilePath: string;
|
|
15
|
+
export declare function loadConfig(args: MinimistArgs): Config;
|
|
16
|
+
export declare function maskConfig(config: Config): Record<string, string>;
|
|
17
|
+
export declare function writeRcConfig(key: string, value: string, profileName?: string): Record<string, string>;
|
|
18
|
+
export declare function getRcConfig(): {
|
|
19
|
+
active: string;
|
|
20
|
+
profiles: Record<string, ProfileConfig>;
|
|
21
|
+
};
|
|
22
|
+
export declare function setActiveProfile(name: string): void;
|
|
23
|
+
export declare function createProfile(name: string): void;
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.rcFilePath = void 0;
|
|
37
|
+
exports.loadConfig = loadConfig;
|
|
38
|
+
exports.maskConfig = maskConfig;
|
|
39
|
+
exports.writeRcConfig = writeRcConfig;
|
|
40
|
+
exports.getRcConfig = getRcConfig;
|
|
41
|
+
exports.setActiveProfile = setActiveProfile;
|
|
42
|
+
exports.createProfile = createProfile;
|
|
43
|
+
const fs = __importStar(require("fs"));
|
|
44
|
+
const path = __importStar(require("path"));
|
|
45
|
+
const os = __importStar(require("os"));
|
|
46
|
+
exports.rcFilePath = path.join(os.homedir(), '.cssprobe-clirc');
|
|
47
|
+
let cachedRc = null;
|
|
48
|
+
function readRcFile() {
|
|
49
|
+
try {
|
|
50
|
+
const stat = fs.statSync(exports.rcFilePath);
|
|
51
|
+
if (cachedRc && cachedRc.mtime === stat.mtimeMs)
|
|
52
|
+
return cachedRc.rc;
|
|
53
|
+
const content = fs.readFileSync(exports.rcFilePath, 'utf-8');
|
|
54
|
+
const rc = JSON.parse(content);
|
|
55
|
+
cachedRc = { rc, mtime: stat.mtimeMs };
|
|
56
|
+
return rc;
|
|
57
|
+
}
|
|
58
|
+
catch {
|
|
59
|
+
return { active: 'default', profiles: {} };
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
function writeRcFile(rc) {
|
|
63
|
+
fs.writeFileSync(exports.rcFilePath, JSON.stringify(rc, null, 2) + '\n');
|
|
64
|
+
cachedRc = null;
|
|
65
|
+
}
|
|
66
|
+
function resolveProfileName(args) {
|
|
67
|
+
const fromArgs = args.p || args.profile;
|
|
68
|
+
const fromEnv = process.env.CSSPROBE_PROFILE;
|
|
69
|
+
if (fromArgs)
|
|
70
|
+
return fromArgs;
|
|
71
|
+
if (fromEnv)
|
|
72
|
+
return fromEnv;
|
|
73
|
+
return readRcFile().active;
|
|
74
|
+
}
|
|
75
|
+
function resolveProfile(args) {
|
|
76
|
+
const name = resolveProfileName(args);
|
|
77
|
+
const rc = readRcFile();
|
|
78
|
+
return rc.profiles[name] || {};
|
|
79
|
+
}
|
|
80
|
+
function loadConfig(args) {
|
|
81
|
+
const profile = resolveProfile(args);
|
|
82
|
+
const browser = args.browser || process.env.CSSPROBE_BROWSER || profile.browser || 'chromium';
|
|
83
|
+
const depthRaw = args.depth ?? process.env.CSSPROBE_DEPTH ?? profile.depth;
|
|
84
|
+
const depth = depthRaw ? Number(depthRaw) : 6;
|
|
85
|
+
const headed = !!(args.headed || process.env.CSSPROBE_HEADED === 'true' || profile.headed === 'true');
|
|
86
|
+
return {
|
|
87
|
+
browser,
|
|
88
|
+
depth: Number.isNaN(depth) ? 6 : depth,
|
|
89
|
+
headed,
|
|
90
|
+
output: args.json ? 'json' : 'text',
|
|
91
|
+
raw: !!args.raw,
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
function maskConfig(config) {
|
|
95
|
+
return {
|
|
96
|
+
browser: config.browser,
|
|
97
|
+
depth: String(config.depth),
|
|
98
|
+
headed: String(config.headed),
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
function writeRcConfig(key, value, profileName) {
|
|
102
|
+
const rc = readRcFile();
|
|
103
|
+
const name = profileName || rc.active;
|
|
104
|
+
if (!rc.profiles[name])
|
|
105
|
+
rc.profiles[name] = {};
|
|
106
|
+
rc.profiles[name][key] = value;
|
|
107
|
+
writeRcFile(rc);
|
|
108
|
+
return { profile: name, [key]: value };
|
|
109
|
+
}
|
|
110
|
+
function getRcConfig() {
|
|
111
|
+
const rc = readRcFile();
|
|
112
|
+
return { active: rc.active, profiles: rc.profiles };
|
|
113
|
+
}
|
|
114
|
+
function setActiveProfile(name) {
|
|
115
|
+
const rc = readRcFile();
|
|
116
|
+
if (!rc.profiles[name])
|
|
117
|
+
throw new Error(`Profile '${name}' not found`);
|
|
118
|
+
rc.active = name;
|
|
119
|
+
writeRcFile(rc);
|
|
120
|
+
}
|
|
121
|
+
function createProfile(name) {
|
|
122
|
+
const rc = readRcFile();
|
|
123
|
+
if (rc.profiles[name])
|
|
124
|
+
throw new Error(`Profile '${name}' already exists`);
|
|
125
|
+
rc.profiles[name] = {};
|
|
126
|
+
writeRcFile(rc);
|
|
127
|
+
}
|
|
128
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export declare function generateHelp(): string;
|
|
2
|
+
export declare function generateHelpJSON(): {
|
|
3
|
+
global: string;
|
|
4
|
+
commands: Record<string, {
|
|
5
|
+
help: string;
|
|
6
|
+
flags: Record<string, "boolean" | "string">;
|
|
7
|
+
args: string[];
|
|
8
|
+
}>;
|
|
9
|
+
booleanOptions: string[];
|
|
10
|
+
};
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.generateHelp = generateHelp;
|
|
37
|
+
exports.generateHelpJSON = generateHelpJSON;
|
|
38
|
+
const z = __importStar(require("zod"));
|
|
39
|
+
const commands_1 = require("../cli/commands");
|
|
40
|
+
function commandArgs(command) {
|
|
41
|
+
const args = [];
|
|
42
|
+
const shape = command.args ? command.args.shape : {};
|
|
43
|
+
for (const [name, schema] of Object.entries(shape)) {
|
|
44
|
+
const zodSchema = schema;
|
|
45
|
+
const description = zodSchema.description ?? '';
|
|
46
|
+
args.push({ name, description, optional: zodSchema.safeParse(undefined).success });
|
|
47
|
+
}
|
|
48
|
+
return args;
|
|
49
|
+
}
|
|
50
|
+
function commandArgsText(args) {
|
|
51
|
+
return args.map(a => a.optional ? `[${a.name}]` : `<${a.name}>`).join(' ');
|
|
52
|
+
}
|
|
53
|
+
function generateCommandHelp(command) {
|
|
54
|
+
const args = commandArgs(command);
|
|
55
|
+
const lines = [
|
|
56
|
+
`cssprobe-cli ${command.name} ${commandArgsText(args)}`,
|
|
57
|
+
'',
|
|
58
|
+
command.description,
|
|
59
|
+
'',
|
|
60
|
+
];
|
|
61
|
+
if (args.length) {
|
|
62
|
+
lines.push('Arguments:');
|
|
63
|
+
lines.push(...args.map(a => formatWithGap(` ${a.optional ? `[${a.name}]` : `<${a.name}>`}`, a.description.toLowerCase())));
|
|
64
|
+
}
|
|
65
|
+
if (command.options) {
|
|
66
|
+
lines.push('Options:');
|
|
67
|
+
const optionsShape = command.options.shape;
|
|
68
|
+
for (const [name, schema] of Object.entries(optionsShape)) {
|
|
69
|
+
const zodSchema = schema;
|
|
70
|
+
const description = (zodSchema.description ?? '').toLowerCase();
|
|
71
|
+
lines.push(formatWithGap(` --${name}`, description));
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
if (command.category !== 'config') {
|
|
75
|
+
lines.push('');
|
|
76
|
+
lines.push('Global options:');
|
|
77
|
+
lines.push(formatWithGap(' --json', 'output as JSON'));
|
|
78
|
+
lines.push(formatWithGap(' --profile, -p <name>', 'use named profile'));
|
|
79
|
+
}
|
|
80
|
+
return lines.join('\n');
|
|
81
|
+
}
|
|
82
|
+
const categories = [
|
|
83
|
+
{ name: 'core', title: 'Inspection' },
|
|
84
|
+
{ name: 'config', title: 'Configuration' },
|
|
85
|
+
{ name: 'skill', title: 'Agent Skills' },
|
|
86
|
+
];
|
|
87
|
+
function generateHelp() {
|
|
88
|
+
const lines = [];
|
|
89
|
+
lines.push('Usage: cssprobe-cli <command> [args] [options]');
|
|
90
|
+
lines.push('');
|
|
91
|
+
const commandsByCategory = new Map();
|
|
92
|
+
for (const c of categories)
|
|
93
|
+
commandsByCategory.set(c.name, []);
|
|
94
|
+
for (const command of Object.values(commands_1.commands)) {
|
|
95
|
+
if (command.hidden)
|
|
96
|
+
continue;
|
|
97
|
+
commandsByCategory.get(command.category).push(command);
|
|
98
|
+
}
|
|
99
|
+
for (const c of categories) {
|
|
100
|
+
const cc = commandsByCategory.get(c.name);
|
|
101
|
+
if (!cc.length)
|
|
102
|
+
continue;
|
|
103
|
+
lines.push(`\n${c.title}:`);
|
|
104
|
+
for (const command of cc)
|
|
105
|
+
lines.push(generateHelpEntry(command));
|
|
106
|
+
}
|
|
107
|
+
lines.push('\nGlobal options:');
|
|
108
|
+
lines.push(formatWithGap(' --help [command]', 'print help'));
|
|
109
|
+
lines.push(formatWithGap(' --json', 'output response as JSON'));
|
|
110
|
+
lines.push(formatWithGap(' --raw', 'output only the result value'));
|
|
111
|
+
lines.push(formatWithGap(' --version', 'print version'));
|
|
112
|
+
lines.push(formatWithGap(' -p, --profile <name>', 'use named profile (or CSSPROBE_PROFILE env)'));
|
|
113
|
+
return lines.join('\n');
|
|
114
|
+
}
|
|
115
|
+
function generateHelpEntry(command) {
|
|
116
|
+
const args = commandArgs(command);
|
|
117
|
+
const prefix = ` ${command.name} ${commandArgsText(args)}`;
|
|
118
|
+
const suffix = command.description.toLowerCase();
|
|
119
|
+
return formatWithGap(prefix, suffix);
|
|
120
|
+
}
|
|
121
|
+
function unwrapZodType(schema) {
|
|
122
|
+
if ('unwrap' in schema && typeof schema.unwrap === 'function')
|
|
123
|
+
return unwrapZodType(schema.unwrap());
|
|
124
|
+
return schema;
|
|
125
|
+
}
|
|
126
|
+
function isBooleanSchema(schema) {
|
|
127
|
+
return unwrapZodType(schema) instanceof z.ZodBoolean;
|
|
128
|
+
}
|
|
129
|
+
function generateHelpJSON() {
|
|
130
|
+
const booleanOptions = new Set();
|
|
131
|
+
const commandEntries = {};
|
|
132
|
+
for (const [name, command] of Object.entries(commands_1.commands)) {
|
|
133
|
+
const flags = {};
|
|
134
|
+
if (command.options) {
|
|
135
|
+
const optionsShape = command.options.shape;
|
|
136
|
+
for (const [flagName, schema] of Object.entries(optionsShape)) {
|
|
137
|
+
const isBoolean = isBooleanSchema(schema);
|
|
138
|
+
flags[flagName] = isBoolean ? 'boolean' : 'string';
|
|
139
|
+
if (isBoolean)
|
|
140
|
+
booleanOptions.add(flagName);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
const args = command.args ? Object.keys(command.args.shape) : [];
|
|
144
|
+
commandEntries[name] = { help: generateCommandHelp(command), flags, args };
|
|
145
|
+
}
|
|
146
|
+
return {
|
|
147
|
+
global: generateHelp(),
|
|
148
|
+
commands: commandEntries,
|
|
149
|
+
booleanOptions: [...booleanOptions],
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
function formatWithGap(prefix, text, threshold = 30) {
|
|
153
|
+
const indent = Math.max(1, threshold - prefix.length);
|
|
154
|
+
return prefix + ' '.repeat(indent) + text;
|
|
155
|
+
}
|
|
156
|
+
//# sourceMappingURL=helpGenerator.js.map
|