skullmaster 0.3.0-beta.0 → 0.3.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.mjs +260 -551
- package/dist/cli.mjs.map +1 -1
- package/package.json +3 -3
package/dist/cli.mjs
CHANGED
|
@@ -9,8 +9,7 @@ import { access, readFile, writeFile } from "node:fs/promises";
|
|
|
9
9
|
import z from "zod";
|
|
10
10
|
import { JSDOM } from "jsdom";
|
|
11
11
|
import pkg from "@babel/generator";
|
|
12
|
-
import
|
|
13
|
-
import { jsxText } from "@babel/types";
|
|
12
|
+
import htmlNodeToJsx from "@skullmaster/excarnate";
|
|
14
13
|
import { readFile as readFile$1, writeFile as writeFile$1 } from "fs/promises";
|
|
15
14
|
import { mkdirSync, readdirSync, rmSync, writeFileSync } from "node:fs";
|
|
16
15
|
//#region src/shared/constants.ts
|
|
@@ -105,494 +104,12 @@ function generateTarget({ project, filePath, componentName, body }) {
|
|
|
105
104
|
`);
|
|
106
105
|
}
|
|
107
106
|
//#endregion
|
|
108
|
-
//#region ../excarnate/dist/index.mjs
|
|
109
|
-
function buildExecutor(rules) {
|
|
110
|
-
return (ctx) => {
|
|
111
|
-
let current = ctx;
|
|
112
|
-
for (const rule of rules) {
|
|
113
|
-
if (!rule.match(current)) continue;
|
|
114
|
-
current = rule.transform(current);
|
|
115
|
-
if (rule.skipAllRest) break;
|
|
116
|
-
}
|
|
117
|
-
return current;
|
|
118
|
-
};
|
|
119
|
-
}
|
|
120
|
-
function sanitizeAttrValue(value) {
|
|
121
|
-
return value.replace(/"/g, "'").replace(/\\/g, "/");
|
|
122
|
-
}
|
|
123
|
-
function createJsxStringAttribute(name, value) {
|
|
124
|
-
return t.jsxAttribute(t.jsxIdentifier(name), t.stringLiteral(sanitizeAttrValue(value)));
|
|
125
|
-
}
|
|
126
|
-
function createJsxExpressionAttribute(name, expression) {
|
|
127
|
-
return t.jsxAttribute(t.jsxIdentifier(name), t.jsxExpressionContainer(expression));
|
|
128
|
-
}
|
|
129
|
-
function findJsxAttribute(attributes, name) {
|
|
130
|
-
return attributes.find((attr) => t.isJSXAttribute(attr) && t.isJSXIdentifier(attr.name) && attr.name.name === name);
|
|
131
|
-
}
|
|
132
|
-
function findStringJsxAttribute(attributes, name) {
|
|
133
|
-
const attr = findJsxAttribute(attributes, name);
|
|
134
|
-
if (!attr?.value || !t.isStringLiteral(attr.value)) return;
|
|
135
|
-
return attr;
|
|
136
|
-
}
|
|
137
|
-
function createJsxElement(tagName, children, attributes = []) {
|
|
138
|
-
return t.jsxElement(t.jsxOpeningElement(t.jsxIdentifier(tagName), attributes, false), t.jsxClosingElement(t.jsxIdentifier(tagName)), children, false);
|
|
139
|
-
}
|
|
140
|
-
const DEPTH_ATTRIBUTE = "data-depth";
|
|
141
|
-
const TEXT_CLASSNAME = "empty-set__text";
|
|
142
|
-
const SKELETON_CLASSNAME = "empty-set__skeleton";
|
|
143
|
-
var TargetElementMismatchError = class extends Error {
|
|
144
|
-
constructor(expected, actual) {
|
|
145
|
-
super(`Expected target element to be ${expected}, but got ${actual}`);
|
|
146
|
-
this.name = "TargetElementMismatchError";
|
|
147
|
-
}
|
|
148
|
-
};
|
|
149
|
-
const ATTRIBUTE_MAP = {
|
|
150
|
-
class: "className",
|
|
151
|
-
for: "htmlFor",
|
|
152
|
-
tabindex: "tabIndex",
|
|
153
|
-
readonly: "readOnly",
|
|
154
|
-
maxlength: "maxLength",
|
|
155
|
-
minlength: "minLength",
|
|
156
|
-
colspan: "colSpan",
|
|
157
|
-
rowspan: "rowSpan",
|
|
158
|
-
contenteditable: "contentEditable",
|
|
159
|
-
autocapitalize: "autoCapitalize",
|
|
160
|
-
autocomplete: "autoComplete",
|
|
161
|
-
autofocus: "autoFocus",
|
|
162
|
-
spellcheck: "spellCheck",
|
|
163
|
-
crossorigin: "crossOrigin",
|
|
164
|
-
referrerpolicy: "referrerPolicy",
|
|
165
|
-
strokewidth: "strokeWidth",
|
|
166
|
-
"stroke-width": "strokeWidth",
|
|
167
|
-
strokelinecap: "strokeLinecap",
|
|
168
|
-
"stroke-linecap": "strokeLinecap",
|
|
169
|
-
strokelinejoin: "strokeLinejoin",
|
|
170
|
-
"stroke-linejoin": "strokeLinejoin",
|
|
171
|
-
strokemiterlimit: "strokeMiterlimit",
|
|
172
|
-
"stroke-miterlimit": "strokeMiterlimit",
|
|
173
|
-
strokedasharray: "strokeDasharray",
|
|
174
|
-
"stroke-dasharray": "strokeDasharray",
|
|
175
|
-
strokedashoffset: "strokeDashoffset",
|
|
176
|
-
"stroke-dashoffset": "strokeDashoffset",
|
|
177
|
-
strokeopacity: "strokeOpacity",
|
|
178
|
-
"stroke-opacity": "strokeOpacity",
|
|
179
|
-
fillopacity: "fillOpacity",
|
|
180
|
-
"fill-opacity": "fillOpacity",
|
|
181
|
-
fillrule: "fillRule",
|
|
182
|
-
"fill-rule": "fillRule",
|
|
183
|
-
cliprule: "clipRule",
|
|
184
|
-
"clip-rule": "clipRule",
|
|
185
|
-
clippath: "clipPath",
|
|
186
|
-
"clip-path": "clipPath",
|
|
187
|
-
stopcolor: "stopColor",
|
|
188
|
-
"stop-color": "stopColor",
|
|
189
|
-
stopopacity: "stopOpacity",
|
|
190
|
-
"stop-opacity": "stopOpacity",
|
|
191
|
-
viewbox: "viewBox",
|
|
192
|
-
xlinkhref: "xlinkHref",
|
|
193
|
-
"xlink:href": "xlinkHref",
|
|
194
|
-
xmlspace: "xmlSpace",
|
|
195
|
-
"xml:space": "xmlSpace"
|
|
196
|
-
};
|
|
197
|
-
function normalizeAttributeName(name) {
|
|
198
|
-
const lower = name.toLowerCase();
|
|
199
|
-
if (ATTRIBUTE_MAP[lower]) return ATTRIBUTE_MAP[lower];
|
|
200
|
-
if (lower.startsWith("data-") || lower.startsWith("aria-")) return lower;
|
|
201
|
-
return name.replace(/-([a-z])/g, (_, char) => char.toUpperCase());
|
|
202
|
-
}
|
|
203
|
-
const STYLE_ATTRIBUTES = /* @__PURE__ */ new Set([
|
|
204
|
-
"class",
|
|
205
|
-
"style",
|
|
206
|
-
"type",
|
|
207
|
-
"fill",
|
|
208
|
-
"fill-opacity",
|
|
209
|
-
"fill-rule",
|
|
210
|
-
"src",
|
|
211
|
-
"stroke",
|
|
212
|
-
"stroke-width",
|
|
213
|
-
"stroke-opacity",
|
|
214
|
-
"stroke-linecap",
|
|
215
|
-
"stroke-linejoin",
|
|
216
|
-
"stroke-dasharray",
|
|
217
|
-
"stroke-dashoffset",
|
|
218
|
-
"opacity",
|
|
219
|
-
"role",
|
|
220
|
-
"width",
|
|
221
|
-
"height",
|
|
222
|
-
"x",
|
|
223
|
-
"y",
|
|
224
|
-
"cx",
|
|
225
|
-
"cy",
|
|
226
|
-
"r",
|
|
227
|
-
"rx",
|
|
228
|
-
"ry",
|
|
229
|
-
"viewbox",
|
|
230
|
-
"transform",
|
|
231
|
-
"d",
|
|
232
|
-
"points"
|
|
233
|
-
]);
|
|
234
|
-
function shouldKeepAttribute(name) {
|
|
235
|
-
const lowerName = name.toLowerCase();
|
|
236
|
-
return lowerName.startsWith("data-") || lowerName.startsWith("aria-") || STYLE_ATTRIBUTES.has(lowerName);
|
|
237
|
-
}
|
|
238
|
-
function parseStyle(style) {
|
|
239
|
-
const properties = [];
|
|
240
|
-
for (const rule of style.split(";")) {
|
|
241
|
-
const trimmedRule = rule.trim();
|
|
242
|
-
if (!trimmedRule) continue;
|
|
243
|
-
const colonIndex = trimmedRule.indexOf(":");
|
|
244
|
-
if (colonIndex === -1) continue;
|
|
245
|
-
const rawKey = trimmedRule.slice(0, colonIndex).trim();
|
|
246
|
-
const rawValue = trimmedRule.slice(colonIndex + 1).trim();
|
|
247
|
-
const key = rawKey.replace(/-([a-z])/g, (_, char) => char.toUpperCase());
|
|
248
|
-
const keyNode = key.startsWith("--") || key.includes("-") ? t.stringLiteral(key) : t.identifier(key);
|
|
249
|
-
properties.push(t.objectProperty(keyNode, t.stringLiteral(rawValue)));
|
|
250
|
-
}
|
|
251
|
-
return t.objectExpression(properties);
|
|
252
|
-
}
|
|
253
|
-
const populateAttrs = {
|
|
254
|
-
id: "populate-attrs",
|
|
255
|
-
match: (ctx) => ctx.element.nodeType === 1,
|
|
256
|
-
transform: (ctx) => {
|
|
257
|
-
const element = ctx.element;
|
|
258
|
-
const attributes = [];
|
|
259
|
-
const tagName = element.tagName.toLowerCase();
|
|
260
|
-
if (ctx.target?.element && ctx.target?.element !== tagName) throw new TargetElementMismatchError(tagName, ctx.target.element);
|
|
261
|
-
if (!element.hasAttribute("data-depth")) attributes.push(createJsxStringAttribute(DEPTH_ATTRIBUTE, String(ctx.depth % 4)));
|
|
262
|
-
for (const attr of element.attributes) {
|
|
263
|
-
if (!shouldKeepAttribute(attr.name)) continue;
|
|
264
|
-
const name = normalizeAttributeName(attr.name);
|
|
265
|
-
const value = attr.value;
|
|
266
|
-
if (name === "style") {
|
|
267
|
-
attributes.push(createJsxExpressionAttribute("style", parseStyle(value)));
|
|
268
|
-
continue;
|
|
269
|
-
}
|
|
270
|
-
attributes.push(createJsxStringAttribute(name, value));
|
|
271
|
-
}
|
|
272
|
-
return {
|
|
273
|
-
...ctx,
|
|
274
|
-
target: {
|
|
275
|
-
element: tagName,
|
|
276
|
-
attributes
|
|
277
|
-
}
|
|
278
|
-
};
|
|
279
|
-
}
|
|
280
|
-
};
|
|
281
|
-
const atDepth = (depth) => (ctx) => ctx.depth === depth;
|
|
282
|
-
const isTagNamesIn = (elements) => (ctx) => ctx.element.nodeType === 1 && elements.includes(ctx.element.tagName.toLowerCase());
|
|
283
|
-
const processSvg = {
|
|
284
|
-
id: "process-svg",
|
|
285
|
-
skipAllRest: true,
|
|
286
|
-
match: isTagNamesIn(["svg"]),
|
|
287
|
-
transform: (ctx) => {
|
|
288
|
-
return {
|
|
289
|
-
...ctx,
|
|
290
|
-
target: {
|
|
291
|
-
...ctx.target,
|
|
292
|
-
element: "svg",
|
|
293
|
-
children: []
|
|
294
|
-
}
|
|
295
|
-
};
|
|
296
|
-
}
|
|
297
|
-
};
|
|
298
|
-
const removeReduntantNode = {
|
|
299
|
-
id: "remove-node",
|
|
300
|
-
skipAllRest: true,
|
|
301
|
-
match: isTagNamesIn([
|
|
302
|
-
"html",
|
|
303
|
-
"script",
|
|
304
|
-
"style",
|
|
305
|
-
"head",
|
|
306
|
-
"meta",
|
|
307
|
-
"link",
|
|
308
|
-
"noscript",
|
|
309
|
-
"template",
|
|
310
|
-
"audio",
|
|
311
|
-
"video",
|
|
312
|
-
"source",
|
|
313
|
-
"track",
|
|
314
|
-
"iframe",
|
|
315
|
-
"embed",
|
|
316
|
-
"object",
|
|
317
|
-
"title",
|
|
318
|
-
"base",
|
|
319
|
-
"defs",
|
|
320
|
-
"symbol",
|
|
321
|
-
"html",
|
|
322
|
-
"canvas",
|
|
323
|
-
"map",
|
|
324
|
-
"area",
|
|
325
|
-
"picture",
|
|
326
|
-
"portal"
|
|
327
|
-
]),
|
|
328
|
-
transform: (ctx) => {
|
|
329
|
-
return {
|
|
330
|
-
...ctx,
|
|
331
|
-
target: null
|
|
332
|
-
};
|
|
333
|
-
}
|
|
334
|
-
};
|
|
335
|
-
const addRootSkeletonsAttrs = {
|
|
336
|
-
id: "add-root-skeleton-attrs",
|
|
337
|
-
match: (ctx) => ctx.element.nodeType === 1 && atDepth(0)(ctx),
|
|
338
|
-
transform: (ctx) => {
|
|
339
|
-
const tagName = ctx.element.tagName.toLowerCase();
|
|
340
|
-
if (ctx.target?.element && ctx.target.element !== tagName) throw new TargetElementMismatchError(tagName, ctx.target.element);
|
|
341
|
-
const existingTarget = ctx.target ?? {
|
|
342
|
-
element: tagName,
|
|
343
|
-
attributes: []
|
|
344
|
-
};
|
|
345
|
-
const existingAttrs = existingTarget.attributes ?? [];
|
|
346
|
-
const classNameAttr = findStringJsxAttribute(existingAttrs, "className");
|
|
347
|
-
const attributes = [...classNameAttr ? existingAttrs.map((attr) => attr === classNameAttr ? {
|
|
348
|
-
...attr,
|
|
349
|
-
value: {
|
|
350
|
-
...classNameAttr.value,
|
|
351
|
-
value: `${classNameAttr.value.value} ${SKELETON_CLASSNAME}`
|
|
352
|
-
}
|
|
353
|
-
} : attr) : [...existingAttrs, createJsxStringAttribute("className", SKELETON_CLASSNAME)]];
|
|
354
|
-
if (!findJsxAttribute(attributes, "role")) attributes.push(createJsxStringAttribute("role", "status"));
|
|
355
|
-
if (!findJsxAttribute(attributes, "aria-live")) attributes.push(createJsxStringAttribute("aria-live", "polite"));
|
|
356
|
-
if (!findJsxAttribute(attributes, "aria-busy")) attributes.push(createJsxStringAttribute("aria-busy", "true"));
|
|
357
|
-
return {
|
|
358
|
-
...ctx,
|
|
359
|
-
target: {
|
|
360
|
-
...existingTarget,
|
|
361
|
-
element: tagName,
|
|
362
|
-
attributes
|
|
363
|
-
}
|
|
364
|
-
};
|
|
365
|
-
}
|
|
366
|
-
};
|
|
367
|
-
const skipNode = {
|
|
368
|
-
id: "skip-node",
|
|
369
|
-
skipAllRest: true,
|
|
370
|
-
match: (ctx) => ctx.element.nodeType === 1 && ctx.element.hasAttribute("data-skip-skull"),
|
|
371
|
-
transform: (ctx) => ({
|
|
372
|
-
...ctx,
|
|
373
|
-
target: null
|
|
374
|
-
})
|
|
375
|
-
};
|
|
376
|
-
const DATA_NAT_H = "data-natural-h";
|
|
377
|
-
const DATA_NAT_W = "data-natural-w";
|
|
378
|
-
const DATA_IMAGE_SKELETON = "data-image-skeleton";
|
|
379
|
-
function createSkeletonSrc(width, height, color = "#808080") {
|
|
380
|
-
const w = Number(width) || 400;
|
|
381
|
-
const h = Number(height) || 300;
|
|
382
|
-
return `data:image/svg+xml,${encodeURIComponent(`<svg xmlns="http://www.w3.org/2000/svg" width="${w}" height="${h}" viewBox="0 0 ${w} ${h}" preserveAspectRatio="none"><rect width="100%" height="100%" fill="${color}"/></svg>`)}`;
|
|
383
|
-
}
|
|
384
|
-
const transformImg = {
|
|
385
|
-
id: "transform-img",
|
|
386
|
-
match: (ctx) => ctx.element.nodeType === 1 && ctx.element.tagName.toLowerCase() === "img",
|
|
387
|
-
transform: (ctx) => {
|
|
388
|
-
if (!ctx.target) throw new Error("Target must be defined before transforming an image element.");
|
|
389
|
-
const attrs = ctx.target.attributes ?? [];
|
|
390
|
-
const naturalWidthAttr = findStringJsxAttribute(attrs, DATA_NAT_W);
|
|
391
|
-
const naturalHeightAttr = findStringJsxAttribute(attrs, DATA_NAT_H);
|
|
392
|
-
const naturalWidth = naturalWidthAttr?.value?.value;
|
|
393
|
-
const naturalHeight = naturalHeightAttr?.value?.value;
|
|
394
|
-
const placeholderSrc = createSkeletonSrc(naturalWidth, naturalHeight);
|
|
395
|
-
const attributes = [
|
|
396
|
-
...attrs.filter((attr) => {
|
|
397
|
-
if (!t.isJSXAttribute(attr)) return false;
|
|
398
|
-
const name = t.isJSXIdentifier(attr.name) ? attr.name.name : void 0;
|
|
399
|
-
return ![
|
|
400
|
-
"src",
|
|
401
|
-
"srcSet",
|
|
402
|
-
"sizes",
|
|
403
|
-
"loading",
|
|
404
|
-
"decoding",
|
|
405
|
-
"fetchPriority",
|
|
406
|
-
DATA_NAT_W,
|
|
407
|
-
DATA_NAT_H,
|
|
408
|
-
DATA_IMAGE_SKELETON
|
|
409
|
-
].includes(name ?? "");
|
|
410
|
-
}),
|
|
411
|
-
createJsxStringAttribute("alt", ""),
|
|
412
|
-
createJsxStringAttribute("src", placeholderSrc),
|
|
413
|
-
createJsxStringAttribute(DATA_IMAGE_SKELETON, "true")
|
|
414
|
-
];
|
|
415
|
-
return {
|
|
416
|
-
...ctx,
|
|
417
|
-
target: {
|
|
418
|
-
...ctx.target,
|
|
419
|
-
attributes
|
|
420
|
-
}
|
|
421
|
-
};
|
|
422
|
-
}
|
|
423
|
-
};
|
|
424
|
-
const INTERACTIVE_TAGS = /* @__PURE__ */ new Set([
|
|
425
|
-
"input",
|
|
426
|
-
"textarea",
|
|
427
|
-
"select",
|
|
428
|
-
"option",
|
|
429
|
-
"optgroup",
|
|
430
|
-
"button",
|
|
431
|
-
"label",
|
|
432
|
-
"fieldset",
|
|
433
|
-
"legend",
|
|
434
|
-
"output",
|
|
435
|
-
"datalist",
|
|
436
|
-
"a",
|
|
437
|
-
"details",
|
|
438
|
-
"summary",
|
|
439
|
-
"audio",
|
|
440
|
-
"video",
|
|
441
|
-
"iframe",
|
|
442
|
-
"embed",
|
|
443
|
-
"object",
|
|
444
|
-
"dialog"
|
|
445
|
-
]);
|
|
446
|
-
const INTERACTIVE_ROLES = /* @__PURE__ */ new Set([
|
|
447
|
-
"button",
|
|
448
|
-
"link",
|
|
449
|
-
"tab",
|
|
450
|
-
"menuitem",
|
|
451
|
-
"checkbox",
|
|
452
|
-
"radio",
|
|
453
|
-
"switch",
|
|
454
|
-
"option",
|
|
455
|
-
"combobox",
|
|
456
|
-
"textbox",
|
|
457
|
-
"searchbox",
|
|
458
|
-
"slider",
|
|
459
|
-
"spinbutton",
|
|
460
|
-
"listbox",
|
|
461
|
-
"treeitem",
|
|
462
|
-
"gridcell",
|
|
463
|
-
"rowheader",
|
|
464
|
-
"columnheader"
|
|
465
|
-
]);
|
|
466
|
-
const PASSWORD_MANAGER_TAGS = /* @__PURE__ */ new Set([
|
|
467
|
-
"input",
|
|
468
|
-
"select",
|
|
469
|
-
"textarea"
|
|
470
|
-
]);
|
|
471
|
-
const ARIA_ATTRIBUTES_TO_REMOVE = /* @__PURE__ */ new Set([
|
|
472
|
-
"role",
|
|
473
|
-
"aria-label",
|
|
474
|
-
"aria-labelledby",
|
|
475
|
-
"aria-describedby",
|
|
476
|
-
"aria-controls",
|
|
477
|
-
"aria-expanded",
|
|
478
|
-
"aria-haspopup",
|
|
479
|
-
"aria-pressed",
|
|
480
|
-
"aria-selected",
|
|
481
|
-
"aria-checked",
|
|
482
|
-
"aria-current",
|
|
483
|
-
"contenteditable",
|
|
484
|
-
"tabindex",
|
|
485
|
-
"aria-hidden",
|
|
486
|
-
"data-skeleton-interactive"
|
|
487
|
-
]);
|
|
488
|
-
const transformInteractiveElements = {
|
|
489
|
-
id: "transform-interactive-elements",
|
|
490
|
-
match: (ctx) => {
|
|
491
|
-
if (ctx.element.nodeType !== 1) return false;
|
|
492
|
-
const element = ctx.element;
|
|
493
|
-
const tag = element.tagName.toLowerCase();
|
|
494
|
-
if (INTERACTIVE_TAGS.has(tag)) return true;
|
|
495
|
-
const role = element.getAttribute("role")?.toLowerCase();
|
|
496
|
-
if (role && INTERACTIVE_ROLES.has(role)) return true;
|
|
497
|
-
if (element.hasAttribute("contenteditable")) return true;
|
|
498
|
-
if (element.hasAttribute("tabindex")) return true;
|
|
499
|
-
return false;
|
|
500
|
-
},
|
|
501
|
-
transform: (ctx) => {
|
|
502
|
-
if (!ctx.target) return ctx;
|
|
503
|
-
const attributes = (ctx.target.attributes ?? []).filter((attribute) => {
|
|
504
|
-
const name = attribute.type === "JSXAttribute" && attribute.name?.name ? String(attribute.name.name).toLowerCase() : "";
|
|
505
|
-
return !ARIA_ATTRIBUTES_TO_REMOVE.has(name);
|
|
506
|
-
});
|
|
507
|
-
attributes.push(createJsxStringAttribute("data-skeleton-interactive", "true"), createJsxStringAttribute("aria-hidden", "true"), createJsxExpressionAttribute("tabIndex", t.numericLiteral(-1)));
|
|
508
|
-
if (ctx.target.element && PASSWORD_MANAGER_TAGS.has(ctx.target.element)) {
|
|
509
|
-
const passwordManagerAttributes = [
|
|
510
|
-
createJsxStringAttribute("autoComplete", "off"),
|
|
511
|
-
createJsxStringAttribute("data-1p-ignore", "true"),
|
|
512
|
-
createJsxStringAttribute("data-lpignore", "true"),
|
|
513
|
-
createJsxStringAttribute("data-bwignore", "true"),
|
|
514
|
-
createJsxStringAttribute("data-protonpass-ignore", "true"),
|
|
515
|
-
createJsxStringAttribute("form", "none")
|
|
516
|
-
];
|
|
517
|
-
for (const attribute of passwordManagerAttributes) {
|
|
518
|
-
const name = attribute.name?.name ? String(attribute.name.name).toLowerCase() : "";
|
|
519
|
-
const existingIndex = attributes.findIndex((existing) => existing.type === "JSXAttribute" && existing.name?.name && String(existing.name.name).toLowerCase() === name);
|
|
520
|
-
if (existingIndex >= 0) attributes[existingIndex] = attribute;
|
|
521
|
-
else attributes.push(attribute);
|
|
522
|
-
}
|
|
523
|
-
}
|
|
524
|
-
return {
|
|
525
|
-
...ctx,
|
|
526
|
-
target: {
|
|
527
|
-
...ctx.target,
|
|
528
|
-
attributes
|
|
529
|
-
}
|
|
530
|
-
};
|
|
531
|
-
}
|
|
532
|
-
};
|
|
533
|
-
function spacePreservedObfuscator(input) {
|
|
534
|
-
if (!input) return null;
|
|
535
|
-
return [...input].map((char) => char === " " ? " " : "█").join("");
|
|
536
|
-
}
|
|
537
|
-
const executor = buildExecutor([
|
|
538
|
-
skipNode,
|
|
539
|
-
{
|
|
540
|
-
id: "transform-text",
|
|
541
|
-
skipAllRest: true,
|
|
542
|
-
match: (ctx) => ctx.element.nodeType === 3,
|
|
543
|
-
transform: (ctx) => {
|
|
544
|
-
const text = spacePreservedObfuscator(ctx.element.textContent?.trim());
|
|
545
|
-
if (!text) return ctx;
|
|
546
|
-
const isHeading = ctx.parentNode?.nodeName.toLowerCase().startsWith("h");
|
|
547
|
-
if (!["p", "label"].includes(ctx.parentNode?.nodeName.toLowerCase() ?? "") && !isHeading) return {
|
|
548
|
-
...ctx,
|
|
549
|
-
target: {
|
|
550
|
-
element: "TEXT",
|
|
551
|
-
children: [jsxText(text)]
|
|
552
|
-
}
|
|
553
|
-
};
|
|
554
|
-
return {
|
|
555
|
-
...ctx,
|
|
556
|
-
target: {
|
|
557
|
-
element: "span",
|
|
558
|
-
attributes: [
|
|
559
|
-
createJsxStringAttribute("className", TEXT_CLASSNAME),
|
|
560
|
-
createJsxStringAttribute("data-text-node", "true"),
|
|
561
|
-
createJsxStringAttribute(DEPTH_ATTRIBUTE, ctx.parentDepth ?? String(ctx.depth))
|
|
562
|
-
],
|
|
563
|
-
children: [jsxText(text)]
|
|
564
|
-
}
|
|
565
|
-
};
|
|
566
|
-
}
|
|
567
|
-
},
|
|
568
|
-
removeReduntantNode,
|
|
569
|
-
populateAttrs,
|
|
570
|
-
processSvg,
|
|
571
|
-
transformImg,
|
|
572
|
-
transformInteractiveElements,
|
|
573
|
-
addRootSkeletonsAttrs
|
|
574
|
-
]);
|
|
575
|
-
function excarnate(element, depth, parentNode = null, parentDepth) {
|
|
576
|
-
const target = executor({
|
|
577
|
-
element,
|
|
578
|
-
depth,
|
|
579
|
-
parentNode,
|
|
580
|
-
parentDepth
|
|
581
|
-
}).target;
|
|
582
|
-
if (!target) return null;
|
|
583
|
-
const { children, element: tagName, attributes } = target;
|
|
584
|
-
if (tagName === "TEXT") return children?.[0] ?? null;
|
|
585
|
-
if (children) return createJsxElement(tagName, children, attributes);
|
|
586
|
-
const { childNodes } = element ?? { childNodes: [] };
|
|
587
|
-
return createJsxElement(tagName, Array.from(childNodes).map((child) => excarnate(child, depth + 1, element, depth.toString())).filter(Boolean), attributes);
|
|
588
|
-
}
|
|
589
|
-
//#endregion
|
|
590
107
|
//#region src/transform/index.ts
|
|
591
108
|
const generate = pkg.default;
|
|
592
109
|
function transformInput(html) {
|
|
593
110
|
const root = new JSDOM(html).window.document.body.firstElementChild;
|
|
594
111
|
if (!root) throw new Error("No root element found");
|
|
595
|
-
const jsxAst =
|
|
112
|
+
const jsxAst = htmlNodeToJsx(root, 0);
|
|
596
113
|
if (!jsxAst) throw new Error("Failed to generate JSX AST");
|
|
597
114
|
return generate(jsxAst, { jsescOption: { minimal: true } }).code;
|
|
598
115
|
}
|
|
@@ -683,6 +200,20 @@ async function fileExists(path) {
|
|
|
683
200
|
const CONFIG_PATH = "skullmaster.config.json";
|
|
684
201
|
//#endregion
|
|
685
202
|
//#region src/init/collect-preferences.ts
|
|
203
|
+
const projectTypes = [{
|
|
204
|
+
value: "react",
|
|
205
|
+
label: "React"
|
|
206
|
+
}, {
|
|
207
|
+
value: "preact",
|
|
208
|
+
label: "Preact"
|
|
209
|
+
}];
|
|
210
|
+
const projectVariantType = [{
|
|
211
|
+
value: "ts",
|
|
212
|
+
label: "TypeScript"
|
|
213
|
+
}, {
|
|
214
|
+
value: "js",
|
|
215
|
+
label: "JavaScript"
|
|
216
|
+
}];
|
|
686
217
|
async function collectPreferences() {
|
|
687
218
|
if (await fileExists("skullmaster.config.json")) return JSON.parse(await readFile$1(`./${CONFIG_PATH}`, "utf-8"));
|
|
688
219
|
const outDir = await text({
|
|
@@ -699,45 +230,86 @@ async function collectPreferences() {
|
|
|
699
230
|
}
|
|
700
231
|
const projectType = await select({
|
|
701
232
|
message: "Pick a project type.",
|
|
702
|
-
initialValue: "react
|
|
703
|
-
options:
|
|
704
|
-
value: "react-ts",
|
|
705
|
-
label: "React with TypeScript"
|
|
706
|
-
}, {
|
|
707
|
-
value: "react-js",
|
|
708
|
-
label: "React"
|
|
709
|
-
}]
|
|
233
|
+
initialValue: "react",
|
|
234
|
+
options: projectTypes
|
|
710
235
|
});
|
|
711
236
|
if (isCancel(projectType)) {
|
|
712
237
|
cancel("Operation cancelled.");
|
|
713
238
|
process.exit(0);
|
|
714
239
|
}
|
|
240
|
+
const variant = await select({
|
|
241
|
+
message: "Pick a project variant.",
|
|
242
|
+
initialValue: "ts",
|
|
243
|
+
options: projectVariantType
|
|
244
|
+
});
|
|
245
|
+
if (isCancel(variant)) {
|
|
246
|
+
cancel("Operation cancelled.");
|
|
247
|
+
process.exit(0);
|
|
248
|
+
}
|
|
715
249
|
const preferences = {
|
|
716
250
|
outDir,
|
|
717
|
-
project: projectType.toString()
|
|
251
|
+
project: `${projectType}-${variant.toString()}`
|
|
718
252
|
};
|
|
719
253
|
await writeFile$1(`./${CONFIG_PATH}`, JSON.stringify(preferences, null, 2), "utf-8");
|
|
720
254
|
return preferences;
|
|
721
255
|
}
|
|
722
256
|
//#endregion
|
|
723
|
-
//#region src/init/
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
257
|
+
//#region src/init/registry/header.ts
|
|
258
|
+
const REGISTRY_HEADER = `
|
|
259
|
+
/* eslint-disable */
|
|
260
|
+
/* oxlint-disable */
|
|
261
|
+
/* biome-ignore-all lint */
|
|
262
|
+
/* @ts-nocheck */
|
|
263
|
+
|
|
264
|
+
/**
|
|
265
|
+
* Auto-generated by Skullmaster.
|
|
266
|
+
*
|
|
267
|
+
* Do not edit this file manually.
|
|
268
|
+
* Use Skullmaster commands to add, update, or remove skeletons.
|
|
269
|
+
*
|
|
270
|
+
*/
|
|
271
|
+
`;
|
|
272
|
+
//#endregion
|
|
273
|
+
//#region src/init/registry/extension.ts
|
|
274
|
+
const getExtension = (project) => {
|
|
275
|
+
switch (project) {
|
|
276
|
+
case "react-ts":
|
|
277
|
+
case "preact-ts": return "tsx";
|
|
278
|
+
case "react-js":
|
|
279
|
+
case "preact-js": return "jsx";
|
|
732
280
|
}
|
|
733
|
-
|
|
734
|
-
}
|
|
281
|
+
};
|
|
735
282
|
//#endregion
|
|
736
|
-
//#region src/init/registry.ts
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
283
|
+
//#region src/init/registry/imports.ts
|
|
284
|
+
const REGISTRY_IMPORTS = (project) => {
|
|
285
|
+
switch (project) {
|
|
286
|
+
case "react-ts": return `import "@skullmaster/react/style.css";
|
|
287
|
+
import DefaultBone from "./skeletons/DefaultBone";
|
|
288
|
+
import { type ComponentProps, type HTMLAttributes, lazy } from "react";`;
|
|
289
|
+
case "react-js": return `import "@skullmaster/react/style.css";
|
|
290
|
+
import DefaultBone from "./skeletons/DefaultBone";
|
|
291
|
+
import { lazy } from "react";`;
|
|
292
|
+
case "preact-ts": return `import "@skullmaster/preact/style.css";
|
|
293
|
+
import DefaultBone from "./skeletons/DefaultBone";
|
|
294
|
+
import { type ComponentProps, type HTMLAttributes, lazy } from "preact/compat";`;
|
|
295
|
+
case "preact-js": return `import "@skullmaster/preact/style.css";
|
|
296
|
+
import DefaultBone from "./skeletons/DefaultBone";
|
|
297
|
+
import { lazy } from "preact/compat";`;
|
|
298
|
+
}
|
|
299
|
+
};
|
|
300
|
+
//#endregion
|
|
301
|
+
//#region src/init/registry/registry-object.ts
|
|
302
|
+
const REGISTRY_OBJECT = (project) => {
|
|
303
|
+
switch (project) {
|
|
304
|
+
case "react-ts": return `const registry = {default: lazy(() => import("./skeletons/DefaultBone"))} as const;`;
|
|
305
|
+
case "preact-ts": return `const registry = {default: lazy(() => import("./skeletons/DefaultBone"))} as const;`;
|
|
306
|
+
case "react-js":
|
|
307
|
+
case "preact-js": return `const registry = {default: lazy(() => import("./skeletons/DefaultBone"))};`;
|
|
308
|
+
}
|
|
309
|
+
};
|
|
310
|
+
//#endregion
|
|
311
|
+
//#region src/init/registry/skull-types.ts
|
|
312
|
+
const JSX_SKULL_TYPES = `
|
|
741
313
|
export type SkullTweaks = {
|
|
742
314
|
/** Exclude this element and its entire subtree from skeleton generation. */
|
|
743
315
|
hideSubTree?: boolean;
|
|
@@ -750,57 +322,102 @@ export type WithDataSkull = HTMLAttributes<HTMLElement> & {
|
|
|
750
322
|
"data-skip-skull"?: boolean;
|
|
751
323
|
"data-depth"?: "-1";
|
|
752
324
|
};
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
325
|
+
`;
|
|
326
|
+
const REGISTRY_SKULL_TYPES = (project) => {
|
|
327
|
+
switch (project) {
|
|
328
|
+
case "react-ts": return JSX_SKULL_TYPES;
|
|
329
|
+
case "preact-ts": return JSX_SKULL_TYPES;
|
|
330
|
+
case "react-js":
|
|
331
|
+
case "preact-js": return "";
|
|
332
|
+
}
|
|
333
|
+
};
|
|
334
|
+
//#endregion
|
|
335
|
+
//#region src/init/registry/skeleton-props.ts
|
|
336
|
+
const REGISTRY_SKELETON_PROPS_TYPE = (project) => {
|
|
337
|
+
switch (project) {
|
|
338
|
+
case "react-ts": return `
|
|
339
|
+
type SkeletonProps = {
|
|
340
|
+
name: keyof typeof registry | (string & {});
|
|
341
|
+
defaultBoneProps?: ComponentProps<typeof DefaultBone>;
|
|
342
|
+
};
|
|
343
|
+
`;
|
|
344
|
+
case "preact-ts": return `
|
|
345
|
+
type SkeletonProps = {
|
|
346
|
+
name: keyof typeof registry | (string & {});
|
|
347
|
+
defaultBoneProps?: ComponentProps<typeof DefaultBone>;
|
|
348
|
+
};
|
|
349
|
+
`;
|
|
350
|
+
case "react-js":
|
|
351
|
+
case "preact-js": return "";
|
|
352
|
+
}
|
|
353
|
+
};
|
|
354
|
+
//#endregion
|
|
355
|
+
//#region src/init/registry/skull-utils.ts
|
|
356
|
+
const JSX_SKULL_UTILS_TS = `
|
|
357
|
+
const buildSkullAttributes = ({ hideSubTree, isTransparent }: SkullTweaks): Omit<WithDataSkull, "data-skullmaster"> => {
|
|
756
358
|
return {
|
|
757
359
|
"data-skip-skull": hideSubTree,
|
|
758
360
|
"data-depth": isTransparent ? "-1" : undefined,
|
|
759
361
|
};
|
|
760
362
|
};
|
|
761
363
|
|
|
762
|
-
export const markAsSkull = (name: string, tweaks
|
|
364
|
+
export const markAsSkull = (name: string, tweaks: SkullTweaks = {}): WithDataSkull => {
|
|
763
365
|
return {
|
|
764
366
|
"data-skullmaster": name,
|
|
765
367
|
...buildSkullAttributes(tweaks),
|
|
766
368
|
};
|
|
767
369
|
};
|
|
768
370
|
|
|
769
|
-
export const tweakForSkull = (tweaks
|
|
371
|
+
export const tweakForSkull = (tweaks: SkullTweaks = {}): Omit<WithDataSkull, "data-skullmaster"> => {
|
|
770
372
|
return buildSkullAttributes(tweaks);
|
|
771
373
|
};
|
|
772
374
|
`;
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
375
|
+
const JSX_SKULL_UTILS_JS = `
|
|
376
|
+
const buildSkullAttributes = ({ hideSubTree, isTransparent }) => {
|
|
377
|
+
return {
|
|
378
|
+
"data-skip-skull": hideSubTree,
|
|
379
|
+
"data-depth": isTransparent ? "-1" : undefined,
|
|
380
|
+
};
|
|
777
381
|
};
|
|
778
|
-
` : "";
|
|
779
|
-
await writeFile(`${outDir}/registry.${ext}`, `
|
|
780
|
-
/* eslint-disable */
|
|
781
|
-
/* oxlint-disable */
|
|
782
|
-
/* biome-ignore-all lint */
|
|
783
|
-
/* @ts-nocheck */
|
|
784
382
|
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
*/
|
|
383
|
+
export const markAsSkull = (name: string, tweaks = {}) => {
|
|
384
|
+
return {
|
|
385
|
+
"data-skullmaster": name,
|
|
386
|
+
...buildSkullAttributes(tweaks),
|
|
387
|
+
};
|
|
388
|
+
};
|
|
792
389
|
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
390
|
+
export const tweakForSkull = (tweaks = {}) => {
|
|
391
|
+
return buildSkullAttributes(tweaks);
|
|
392
|
+
};
|
|
393
|
+
`;
|
|
394
|
+
const REGISTRY_SKULL_UTILS = (project) => {
|
|
395
|
+
switch (project) {
|
|
396
|
+
case "react-ts": return JSX_SKULL_UTILS_TS;
|
|
397
|
+
case "react-js": return JSX_SKULL_UTILS_JS;
|
|
398
|
+
case "preact-ts": return JSX_SKULL_UTILS_TS;
|
|
399
|
+
case "preact-js": return JSX_SKULL_UTILS_JS;
|
|
400
|
+
}
|
|
401
|
+
};
|
|
402
|
+
//#endregion
|
|
403
|
+
//#region src/init/registry/skeleton.ts
|
|
404
|
+
const JSX_SKELETON_TS = `export default function Skeleton({
|
|
405
|
+
name,
|
|
406
|
+
defaultBoneProps = {},
|
|
407
|
+
}: SkeletonProps) {
|
|
408
|
+
const Component = registry[name];
|
|
796
409
|
|
|
797
|
-
|
|
410
|
+
if (!Component) {
|
|
411
|
+
return <DefaultBone {...defaultBoneProps} />;
|
|
412
|
+
}
|
|
798
413
|
|
|
799
|
-
|
|
800
|
-
|
|
414
|
+
return <Component />;
|
|
415
|
+
}
|
|
416
|
+
`;
|
|
417
|
+
const JSX_SKELETON_JS = `export default function Skeleton({
|
|
801
418
|
name,
|
|
802
419
|
defaultBoneProps = {},
|
|
803
|
-
}
|
|
420
|
+
}) {
|
|
804
421
|
const Component = registry[name];
|
|
805
422
|
|
|
806
423
|
if (!Component) {
|
|
@@ -809,12 +426,66 @@ export default function Skeleton({
|
|
|
809
426
|
|
|
810
427
|
return <Component />;
|
|
811
428
|
}
|
|
812
|
-
|
|
429
|
+
`;
|
|
430
|
+
const REGISTRY_SKELETON = (project) => {
|
|
431
|
+
switch (project) {
|
|
432
|
+
case "react-ts": return JSX_SKELETON_TS;
|
|
433
|
+
case "react-js": return JSX_SKELETON_JS;
|
|
434
|
+
case "preact-ts": return JSX_SKELETON_TS;
|
|
435
|
+
case "preact-js": return JSX_SKELETON_JS;
|
|
436
|
+
}
|
|
437
|
+
};
|
|
438
|
+
//#endregion
|
|
439
|
+
//#region src/init/registry/index.ts
|
|
440
|
+
async function generateInitialRegistry(outDir, projectType) {
|
|
441
|
+
const ext = getExtension(projectType);
|
|
442
|
+
const skeleton = REGISTRY_SKELETON(projectType);
|
|
443
|
+
const content = `
|
|
444
|
+
${REGISTRY_HEADER}
|
|
445
|
+
|
|
446
|
+
|
|
447
|
+
${REGISTRY_IMPORTS(projectType)}
|
|
448
|
+
|
|
449
|
+
${REGISTRY_OBJECT(projectType)}
|
|
450
|
+
|
|
451
|
+
${REGISTRY_SKULL_TYPES(projectType)}
|
|
452
|
+
${REGISTRY_SKELETON_PROPS_TYPE(projectType)}
|
|
453
|
+
${REGISTRY_SKULL_UTILS(projectType)}
|
|
454
|
+
${skeleton}
|
|
455
|
+
`;
|
|
456
|
+
await writeFile(`${outDir}/registry.${ext}`, content, "utf8");
|
|
457
|
+
}
|
|
458
|
+
//#endregion
|
|
459
|
+
//#region src/init/ensure-lazy-imports.ts
|
|
460
|
+
function ensureLazyImport(sourceFile, project) {
|
|
461
|
+
let moduleSpecifier;
|
|
462
|
+
switch (project) {
|
|
463
|
+
case "preact-ts":
|
|
464
|
+
case "preact-js":
|
|
465
|
+
moduleSpecifier = "preact/compat";
|
|
466
|
+
break;
|
|
467
|
+
case "react-ts":
|
|
468
|
+
case "react-js":
|
|
469
|
+
moduleSpecifier = "react";
|
|
470
|
+
break;
|
|
471
|
+
}
|
|
472
|
+
const runtimeImport = sourceFile.getImportDeclaration((d) => d.getModuleSpecifierValue() === moduleSpecifier);
|
|
473
|
+
if (!runtimeImport) {
|
|
474
|
+
sourceFile.addImportDeclaration({
|
|
475
|
+
moduleSpecifier,
|
|
476
|
+
namedImports: ["lazy"]
|
|
477
|
+
});
|
|
478
|
+
return;
|
|
479
|
+
}
|
|
480
|
+
if (!runtimeImport.getNamedImports().some((i) => i.getName() === "lazy")) runtimeImport.addNamedImport("lazy");
|
|
813
481
|
}
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
482
|
+
//#endregion
|
|
483
|
+
//#region src/init/registry/operations.ts
|
|
484
|
+
async function generateRegistry(operation, project, registryPath) {
|
|
485
|
+
const isTs = getExtension(project) === "tsx";
|
|
486
|
+
const tsMorphProject = isTs ? new Project({ tsConfigFilePath: "tsconfig.json" }) : new Project();
|
|
487
|
+
const sourceFile = tsMorphProject.addSourceFileAtPath(registryPath);
|
|
488
|
+
ensureLazyImport(sourceFile, project);
|
|
818
489
|
const registry = sourceFile.getVariableDeclaration("registry")?.getInitializerIfKind(SyntaxKind.AsExpression)?.getExpressionIfKind(SyntaxKind.ObjectLiteralExpression) ?? sourceFile.getVariableDeclaration("registry")?.getInitializerIfKind(SyntaxKind.ObjectLiteralExpression);
|
|
819
490
|
if (!registry) throw new Error("Unable to locate registry object, have you ran skullmaster init??");
|
|
820
491
|
const existingComponents = new Set(registry.getProperties().filter((property) => property.getKind() === SyntaxKind.PropertyAssignment).map((property) => property.asKindOrThrow(SyntaxKind.PropertyAssignment)).map((property) => property.getName().replace(/['"]/g, "")));
|
|
@@ -833,7 +504,7 @@ async function generateRegistry(operation, isTs, registryPath) {
|
|
|
833
504
|
}
|
|
834
505
|
sourceFile.formatText();
|
|
835
506
|
await sourceFile.save();
|
|
836
|
-
|
|
507
|
+
tsMorphProject.saveSync();
|
|
837
508
|
}
|
|
838
509
|
//#endregion
|
|
839
510
|
//#region src/init/cache-registry.ts
|
|
@@ -860,8 +531,9 @@ async function updateCacheRegistry(operation, outDir) {
|
|
|
860
531
|
}
|
|
861
532
|
//#endregion
|
|
862
533
|
//#region src/init/default-bone.ts
|
|
863
|
-
|
|
864
|
-
|
|
534
|
+
const DEFAULT_BONE_CONTENT = (project) => {
|
|
535
|
+
switch (project) {
|
|
536
|
+
case "react-ts": return `
|
|
865
537
|
/* eslint-disable */
|
|
866
538
|
/* oxlint-disable */
|
|
867
539
|
/* biome-ignore-all lint */
|
|
@@ -883,7 +555,44 @@ type DefaultBoneProps = HTMLProps<HTMLDivElement>;
|
|
|
883
555
|
export default function DefaultBone(props: DefaultBoneProps) {
|
|
884
556
|
return <div {...props}>loading...</div>;
|
|
885
557
|
}
|
|
886
|
-
|
|
558
|
+
`;
|
|
559
|
+
case "preact-ts": return `
|
|
560
|
+
/* eslint-disable */
|
|
561
|
+
/* oxlint-disable */
|
|
562
|
+
/* biome-ignore-all lint */
|
|
563
|
+
/* @ts-nocheck */
|
|
564
|
+
|
|
565
|
+
import type { HTMLAttributes } from "preact";
|
|
566
|
+
|
|
567
|
+
/**
|
|
568
|
+
* Auto-generated by Skullmaster.
|
|
569
|
+
*
|
|
570
|
+
* This is the default fallback skeleton component displayed when a
|
|
571
|
+
* matching skeleton implementation cannot be found in the registry.
|
|
572
|
+
*
|
|
573
|
+
* You may freely customize or replace this component to match the
|
|
574
|
+
* loading experience of your application.
|
|
575
|
+
*/
|
|
576
|
+
type DefaultBoneProps = HTMLAttributes<HTMLDivElement>;
|
|
577
|
+
|
|
578
|
+
export default function DefaultBone(props: DefaultBoneProps) {
|
|
579
|
+
return <div {...props}>loading...</div>;
|
|
580
|
+
}
|
|
581
|
+
`;
|
|
582
|
+
case "react-js":
|
|
583
|
+
case "preact-js": return `
|
|
584
|
+
/* eslint-disable */
|
|
585
|
+
/* oxlint-disable */
|
|
586
|
+
/* biome-ignore-all lint */
|
|
587
|
+
|
|
588
|
+
export default function DefaultBone(props) {
|
|
589
|
+
return <div {...props}>loading...</div>;
|
|
590
|
+
}
|
|
591
|
+
`;
|
|
592
|
+
}
|
|
593
|
+
};
|
|
594
|
+
async function defaultBone(target, project) {
|
|
595
|
+
await writeFile(target, DEFAULT_BONE_CONTENT(project), "utf8");
|
|
887
596
|
}
|
|
888
597
|
//#endregion
|
|
889
598
|
//#region src/init/preferences.ts
|
|
@@ -920,7 +629,7 @@ var Config = class {
|
|
|
920
629
|
} else log.gray(`Cache exists: ${cachePath}`);
|
|
921
630
|
const defaultBonePath = this.getDefSkeletonPath();
|
|
922
631
|
if (forceReset || !await fileExists(defaultBonePath)) {
|
|
923
|
-
await defaultBone(defaultBonePath);
|
|
632
|
+
await defaultBone(defaultBonePath, this.projectType);
|
|
924
633
|
log.success(`Created default bone: ${defaultBonePath}`);
|
|
925
634
|
} else log.gray(`Default bone exists: ${defaultBonePath}`);
|
|
926
635
|
log.success("Initialization complete");
|
|
@@ -929,7 +638,7 @@ var Config = class {
|
|
|
929
638
|
return await updateCacheRegistry(op, this.getCachePath());
|
|
930
639
|
}
|
|
931
640
|
async registry(op) {
|
|
932
|
-
return generateRegistry(op, this.projectType
|
|
641
|
+
return generateRegistry(op, this.projectType, this.getRegistryPath());
|
|
933
642
|
}
|
|
934
643
|
getCachePath() {
|
|
935
644
|
return `${this.outDir}/cache.json`;
|
|
@@ -941,7 +650,7 @@ var Config = class {
|
|
|
941
650
|
return `${this.getSkeletonPath()}/DefaultBone.${this.getExt()}`;
|
|
942
651
|
}
|
|
943
652
|
getExt() {
|
|
944
|
-
return this.projectType
|
|
653
|
+
return getExtension(this.projectType);
|
|
945
654
|
}
|
|
946
655
|
getRegistryPath() {
|
|
947
656
|
return `${this.outDir}/registry.${this.getExt()}`;
|
package/dist/cli.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.mjs","names":["htmlNodeToJsx","readFile","writeFile"],"sources":["../src/shared/constants.ts","../src/shared/schema.ts","../src/shared/log.ts","../src/cache/index.ts","../src/generate-target/index.ts","../../excarnate/dist/index.mjs","../src/transform/index.ts","../src/utils/to-pascal-case.ts","../src/utils/fnv1a.ts","../src/commands/serve.ts","../src/init/is-file-exists.ts","../src/constants.ts","../src/init/collect-preferences.ts","../src/init/ensure-lazy-imports.ts","../src/init/registry.ts","../src/init/cache-registry.ts","../src/init/default-bone.ts","../src/init/preferences.ts","../src/cli.ts"],"sourcesContent":["export const DEFAULT_PORT = 8008;\nexport const EMPTY_SET_DEFAULT_DIR = \"skullmaster\";\nexport const DATA_NAT_H = \"data-natural-h\";\nexport const DATA_NAT_W = \"data-natural-w\";\n","import z from \"zod\";\n\nexport const SkeletonPayloadInputSchema = z.record(\n z.string(),\n z.object({\n component: z.string(),\n html: z.string(),\n }),\n);\n\nexport const SkeletonCacheEntrySchema = z.record(\n z.string(),\n z.object({\n component: z.string(),\n html: z.string(),\n hash: z.string(),\n }),\n);\n\nexport type SkeletonPayloadInput = z.infer<typeof SkeletonPayloadInputSchema>;\n\nexport type SkeletonCacheEntry = z.infer<typeof SkeletonCacheEntrySchema>;\n","export const log = {\n success: (message: string) => console.log(`\\x1b[32m[💀] ${message}\\x1b[0m`),\n info: (message: string) => console.log(`\\x1b[36m[💀] ${message}\\x1b[0m`),\n warn: (message: string) => console.log(`\\x1b[33m[💀] ${message}\\x1b[0m`),\n error: (message: string) => console.log(`\\x1b[31m[💀] ${message}\\x1b[0m`),\n gray: (message: string) => console.log(`\\x1b[90m[💀] ${message}\\x1b[0m`),\n};\n","import { readFile } from \"node:fs/promises\";\nimport type { Config } from \"../init/preferences\";\nimport { type SkeletonCacheEntry, SkeletonCacheEntrySchema } from \"../shared\";\n\nexport class SkeletonCacheDB {\n private data: SkeletonCacheEntry = {};\n config: Config;\n private constructor(config: Config) {\n this.config = config;\n }\n\n static async create(config: Config) {\n const db = new SkeletonCacheDB(config);\n\n await db.load();\n\n return db;\n }\n\n private async load() {\n try {\n const file = await readFile(this.config.getCachePath(), \"utf8\");\n\n const parsed = JSON.parse(file);\n\n this.data = SkeletonCacheEntrySchema.parse(parsed);\n } catch {\n this.data = {};\n\n await this.config.cache({ type: \"replace\", cacheEntry: {} });\n }\n }\n\n get(key: string) {\n return this.data[key];\n }\n getComponentNames(): string[] {\n return Object.values(this.data).map((entry) => entry.component);\n }\n\n async set(key: string, value: SkeletonCacheEntry[string]) {\n this.data[key] = value;\n this.config.cache({ type: \"update\", componentName: key, payload: value });\n }\n}\n","import { Project, QuoteKind, ScriptKind } from \"ts-morph\";\n\ntype GenerateTargetOptions = {\n project: Project;\n filePath: string;\n componentName: string;\n body: string;\n};\n\nexport default function generateTarget({\n project,\n filePath,\n componentName,\n body,\n}: GenerateTargetOptions) {\n project.manipulationSettings.set({\n quoteKind: QuoteKind.Double,\n });\n\n const file = project.createSourceFile(filePath, \"\", {\n overwrite: true,\n scriptKind: ScriptKind.TSX,\n });\n\n file.insertText(\n 0,\n `/* eslint-disable */\n/* prettier-ignore-start */\n\n/**\n * Auto-generated by Skullmaster.\n *\n * DO NOT EDIT THIS FILE MANUALLY.\n * Changes may be overwritten on the next generation.\n */\n\n`,\n );\n\n file.addFunction({\n name: componentName,\n isDefaultExport: true,\n statements: [`return (${body});`],\n });\n\n file.addStatements(`\n/* prettier-ignore-end */\n`);\n}\n","import * as t from \"@babel/types\";\nimport { jsxText } from \"@babel/types\";\n//#region src/executor.ts\nfunction buildExecutor(rules) {\n\treturn (ctx) => {\n\t\tlet current = ctx;\n\t\tfor (const rule of rules) {\n\t\t\tif (!rule.match(current)) continue;\n\t\t\tcurrent = rule.transform(current);\n\t\t\tif (rule.skipAllRest) break;\n\t\t}\n\t\treturn current;\n\t};\n}\n//#endregion\n//#region src/helpers/sanitize-attr-value.ts\nfunction sanitizeAttrValue(value) {\n\treturn value.replace(/\"/g, \"'\").replace(/\\\\/g, \"/\");\n}\n//#endregion\n//#region src/helpers/jsx.ts\nfunction createJsxStringAttribute(name, value) {\n\treturn t.jsxAttribute(t.jsxIdentifier(name), t.stringLiteral(sanitizeAttrValue(value)));\n}\nfunction createJsxExpressionAttribute(name, expression) {\n\treturn t.jsxAttribute(t.jsxIdentifier(name), t.jsxExpressionContainer(expression));\n}\nfunction findJsxAttribute(attributes, name) {\n\treturn attributes.find((attr) => t.isJSXAttribute(attr) && t.isJSXIdentifier(attr.name) && attr.name.name === name);\n}\nfunction findStringJsxAttribute(attributes, name) {\n\tconst attr = findJsxAttribute(attributes, name);\n\tif (!attr?.value || !t.isStringLiteral(attr.value)) return;\n\treturn attr;\n}\nfunction createJsxElement(tagName, children, attributes = []) {\n\treturn t.jsxElement(t.jsxOpeningElement(t.jsxIdentifier(tagName), attributes, false), t.jsxClosingElement(t.jsxIdentifier(tagName)), children, false);\n}\n//#endregion\n//#region src/constants.ts\nconst DEPTH_ATTRIBUTE = \"data-depth\";\nconst TEXT_CLASSNAME = \"empty-set__text\";\nconst SKELETON_CLASSNAME = \"empty-set__skeleton\";\n//#endregion\n//#region src/exceptions/target-mismatch.ts\nvar TargetElementMismatchError = class extends Error {\n\tconstructor(expected, actual) {\n\t\tsuper(`Expected target element to be ${expected}, but got ${actual}`);\n\t\tthis.name = \"TargetElementMismatchError\";\n\t}\n};\n//#endregion\n//#region src/helpers/attribute-replace-map.ts\nconst ATTRIBUTE_MAP = {\n\tclass: \"className\",\n\tfor: \"htmlFor\",\n\ttabindex: \"tabIndex\",\n\treadonly: \"readOnly\",\n\tmaxlength: \"maxLength\",\n\tminlength: \"minLength\",\n\tcolspan: \"colSpan\",\n\trowspan: \"rowSpan\",\n\tcontenteditable: \"contentEditable\",\n\tautocapitalize: \"autoCapitalize\",\n\tautocomplete: \"autoComplete\",\n\tautofocus: \"autoFocus\",\n\tspellcheck: \"spellCheck\",\n\tcrossorigin: \"crossOrigin\",\n\treferrerpolicy: \"referrerPolicy\",\n\tstrokewidth: \"strokeWidth\",\n\t\"stroke-width\": \"strokeWidth\",\n\tstrokelinecap: \"strokeLinecap\",\n\t\"stroke-linecap\": \"strokeLinecap\",\n\tstrokelinejoin: \"strokeLinejoin\",\n\t\"stroke-linejoin\": \"strokeLinejoin\",\n\tstrokemiterlimit: \"strokeMiterlimit\",\n\t\"stroke-miterlimit\": \"strokeMiterlimit\",\n\tstrokedasharray: \"strokeDasharray\",\n\t\"stroke-dasharray\": \"strokeDasharray\",\n\tstrokedashoffset: \"strokeDashoffset\",\n\t\"stroke-dashoffset\": \"strokeDashoffset\",\n\tstrokeopacity: \"strokeOpacity\",\n\t\"stroke-opacity\": \"strokeOpacity\",\n\tfillopacity: \"fillOpacity\",\n\t\"fill-opacity\": \"fillOpacity\",\n\tfillrule: \"fillRule\",\n\t\"fill-rule\": \"fillRule\",\n\tcliprule: \"clipRule\",\n\t\"clip-rule\": \"clipRule\",\n\tclippath: \"clipPath\",\n\t\"clip-path\": \"clipPath\",\n\tstopcolor: \"stopColor\",\n\t\"stop-color\": \"stopColor\",\n\tstopopacity: \"stopOpacity\",\n\t\"stop-opacity\": \"stopOpacity\",\n\tviewbox: \"viewBox\",\n\txlinkhref: \"xlinkHref\",\n\t\"xlink:href\": \"xlinkHref\",\n\txmlspace: \"xmlSpace\",\n\t\"xml:space\": \"xmlSpace\"\n};\n//#endregion\n//#region src/helpers/attr-normalize.ts\nfunction normalizeAttributeName(name) {\n\tconst lower = name.toLowerCase();\n\tif (ATTRIBUTE_MAP[lower]) return ATTRIBUTE_MAP[lower];\n\tif (lower.startsWith(\"data-\") || lower.startsWith(\"aria-\")) return lower;\n\treturn name.replace(/-([a-z])/g, (_, char) => char.toUpperCase());\n}\n//#endregion\n//#region src/helpers/is-style.ts\nconst STYLE_ATTRIBUTES = /* @__PURE__ */ new Set([\n\t\"class\",\n\t\"style\",\n\t\"type\",\n\t\"fill\",\n\t\"fill-opacity\",\n\t\"fill-rule\",\n\t\"src\",\n\t\"stroke\",\n\t\"stroke-width\",\n\t\"stroke-opacity\",\n\t\"stroke-linecap\",\n\t\"stroke-linejoin\",\n\t\"stroke-dasharray\",\n\t\"stroke-dashoffset\",\n\t\"opacity\",\n\t\"role\",\n\t\"width\",\n\t\"height\",\n\t\"x\",\n\t\"y\",\n\t\"cx\",\n\t\"cy\",\n\t\"r\",\n\t\"rx\",\n\t\"ry\",\n\t\"viewbox\",\n\t\"transform\",\n\t\"d\",\n\t\"points\"\n]);\nfunction shouldKeepAttribute(name) {\n\tconst lowerName = name.toLowerCase();\n\treturn lowerName.startsWith(\"data-\") || lowerName.startsWith(\"aria-\") || STYLE_ATTRIBUTES.has(lowerName);\n}\n//#endregion\n//#region src/helpers/parse-style.ts\nfunction parseStyle(style) {\n\tconst properties = [];\n\tfor (const rule of style.split(\";\")) {\n\t\tconst trimmedRule = rule.trim();\n\t\tif (!trimmedRule) continue;\n\t\tconst colonIndex = trimmedRule.indexOf(\":\");\n\t\tif (colonIndex === -1) continue;\n\t\tconst rawKey = trimmedRule.slice(0, colonIndex).trim();\n\t\tconst rawValue = trimmedRule.slice(colonIndex + 1).trim();\n\t\tconst key = rawKey.replace(/-([a-z])/g, (_, char) => char.toUpperCase());\n\t\tconst keyNode = key.startsWith(\"--\") || key.includes(\"-\") ? t.stringLiteral(key) : t.identifier(key);\n\t\tproperties.push(t.objectProperty(keyNode, t.stringLiteral(rawValue)));\n\t}\n\treturn t.objectExpression(properties);\n}\n//#endregion\n//#region src/rules/populate-attrs.ts\nconst populateAttrs = {\n\tid: \"populate-attrs\",\n\tmatch: (ctx) => ctx.element.nodeType === 1,\n\ttransform: (ctx) => {\n\t\tconst element = ctx.element;\n\t\tconst attributes = [];\n\t\tconst tagName = element.tagName.toLowerCase();\n\t\tif (ctx.target?.element && ctx.target?.element !== tagName) throw new TargetElementMismatchError(tagName, ctx.target.element);\n\t\tif (!element.hasAttribute(\"data-depth\")) attributes.push(createJsxStringAttribute(DEPTH_ATTRIBUTE, String(ctx.depth % 4)));\n\t\tfor (const attr of element.attributes) {\n\t\t\tif (!shouldKeepAttribute(attr.name)) continue;\n\t\t\tconst name = normalizeAttributeName(attr.name);\n\t\t\tconst value = attr.value;\n\t\t\tif (name === \"style\") {\n\t\t\t\tattributes.push(createJsxExpressionAttribute(\"style\", parseStyle(value)));\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tattributes.push(createJsxStringAttribute(name, value));\n\t\t}\n\t\treturn {\n\t\t\t...ctx,\n\t\t\ttarget: {\n\t\t\t\telement: tagName,\n\t\t\t\tattributes\n\t\t\t}\n\t\t};\n\t}\n};\n//#endregion\n//#region src/matchers.ts\nconst atDepth = (depth) => (ctx) => ctx.depth === depth;\nconst isTagNamesIn = (elements) => (ctx) => ctx.element.nodeType === 1 && elements.includes(ctx.element.tagName.toLowerCase());\n//#endregion\n//#region src/rules/process-svg.ts\nconst processSvg = {\n\tid: \"process-svg\",\n\tskipAllRest: true,\n\tmatch: isTagNamesIn([\"svg\"]),\n\ttransform: (ctx) => {\n\t\treturn {\n\t\t\t...ctx,\n\t\t\ttarget: {\n\t\t\t\t...ctx.target,\n\t\t\t\telement: \"svg\",\n\t\t\t\tchildren: []\n\t\t\t}\n\t\t};\n\t}\n};\n//#endregion\n//#region src/rules/remove-node.ts\nconst removeReduntantNode = {\n\tid: \"remove-node\",\n\tskipAllRest: true,\n\tmatch: isTagNamesIn([\n\t\t\"html\",\n\t\t\"script\",\n\t\t\"style\",\n\t\t\"head\",\n\t\t\"meta\",\n\t\t\"link\",\n\t\t\"noscript\",\n\t\t\"template\",\n\t\t\"audio\",\n\t\t\"video\",\n\t\t\"source\",\n\t\t\"track\",\n\t\t\"iframe\",\n\t\t\"embed\",\n\t\t\"object\",\n\t\t\"title\",\n\t\t\"base\",\n\t\t\"defs\",\n\t\t\"symbol\",\n\t\t\"html\",\n\t\t\"canvas\",\n\t\t\"map\",\n\t\t\"area\",\n\t\t\"picture\",\n\t\t\"portal\"\n\t]),\n\ttransform: (ctx) => {\n\t\treturn {\n\t\t\t...ctx,\n\t\t\ttarget: null\n\t\t};\n\t}\n};\n//#endregion\n//#region src/rules/root-skeleton-attrs.ts\nconst addRootSkeletonsAttrs = {\n\tid: \"add-root-skeleton-attrs\",\n\tmatch: (ctx) => ctx.element.nodeType === 1 && atDepth(0)(ctx),\n\ttransform: (ctx) => {\n\t\tconst tagName = ctx.element.tagName.toLowerCase();\n\t\tif (ctx.target?.element && ctx.target.element !== tagName) throw new TargetElementMismatchError(tagName, ctx.target.element);\n\t\tconst existingTarget = ctx.target ?? {\n\t\t\telement: tagName,\n\t\t\tattributes: []\n\t\t};\n\t\tconst existingAttrs = existingTarget.attributes ?? [];\n\t\tconst classNameAttr = findStringJsxAttribute(existingAttrs, \"className\");\n\t\tconst attributes = [...classNameAttr ? existingAttrs.map((attr) => attr === classNameAttr ? {\n\t\t\t...attr,\n\t\t\tvalue: {\n\t\t\t\t...classNameAttr.value,\n\t\t\t\tvalue: `${classNameAttr.value.value} ${SKELETON_CLASSNAME}`\n\t\t\t}\n\t\t} : attr) : [...existingAttrs, createJsxStringAttribute(\"className\", SKELETON_CLASSNAME)]];\n\t\tif (!findJsxAttribute(attributes, \"role\")) attributes.push(createJsxStringAttribute(\"role\", \"status\"));\n\t\tif (!findJsxAttribute(attributes, \"aria-live\")) attributes.push(createJsxStringAttribute(\"aria-live\", \"polite\"));\n\t\tif (!findJsxAttribute(attributes, \"aria-busy\")) attributes.push(createJsxStringAttribute(\"aria-busy\", \"true\"));\n\t\treturn {\n\t\t\t...ctx,\n\t\t\ttarget: {\n\t\t\t\t...existingTarget,\n\t\t\t\telement: tagName,\n\t\t\t\tattributes\n\t\t\t}\n\t\t};\n\t}\n};\n//#endregion\n//#region src/rules/skip-node.ts\nconst skipNode = {\n\tid: \"skip-node\",\n\tskipAllRest: true,\n\tmatch: (ctx) => ctx.element.nodeType === 1 && ctx.element.hasAttribute(\"data-skip-skull\"),\n\ttransform: (ctx) => ({\n\t\t...ctx,\n\t\ttarget: null\n\t})\n};\n//#endregion\n//#region src/rules/transform-img.ts\nconst DATA_NAT_H = \"data-natural-h\";\nconst DATA_NAT_W = \"data-natural-w\";\nconst DATA_IMAGE_SKELETON = \"data-image-skeleton\";\nfunction createSkeletonSrc(width, height, color = \"#808080\") {\n\tconst w = Number(width) || 400;\n\tconst h = Number(height) || 300;\n\treturn `data:image/svg+xml,${encodeURIComponent(`<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"${w}\" height=\"${h}\" viewBox=\"0 0 ${w} ${h}\" preserveAspectRatio=\"none\"><rect width=\"100%\" height=\"100%\" fill=\"${color}\"/></svg>`)}`;\n}\nconst transformImg = {\n\tid: \"transform-img\",\n\tmatch: (ctx) => ctx.element.nodeType === 1 && ctx.element.tagName.toLowerCase() === \"img\",\n\ttransform: (ctx) => {\n\t\tif (!ctx.target) throw new Error(\"Target must be defined before transforming an image element.\");\n\t\tconst attrs = ctx.target.attributes ?? [];\n\t\tconst naturalWidthAttr = findStringJsxAttribute(attrs, DATA_NAT_W);\n\t\tconst naturalHeightAttr = findStringJsxAttribute(attrs, DATA_NAT_H);\n\t\tconst naturalWidth = naturalWidthAttr?.value?.value;\n\t\tconst naturalHeight = naturalHeightAttr?.value?.value;\n\t\tconst placeholderSrc = createSkeletonSrc(naturalWidth, naturalHeight);\n\t\tconst attributes = [\n\t\t\t...attrs.filter((attr) => {\n\t\t\t\tif (!t.isJSXAttribute(attr)) return false;\n\t\t\t\tconst name = t.isJSXIdentifier(attr.name) ? attr.name.name : void 0;\n\t\t\t\treturn ![\n\t\t\t\t\t\"src\",\n\t\t\t\t\t\"srcSet\",\n\t\t\t\t\t\"sizes\",\n\t\t\t\t\t\"loading\",\n\t\t\t\t\t\"decoding\",\n\t\t\t\t\t\"fetchPriority\",\n\t\t\t\t\tDATA_NAT_W,\n\t\t\t\t\tDATA_NAT_H,\n\t\t\t\t\tDATA_IMAGE_SKELETON\n\t\t\t\t].includes(name ?? \"\");\n\t\t\t}),\n\t\t\tcreateJsxStringAttribute(\"alt\", \"\"),\n\t\t\tcreateJsxStringAttribute(\"src\", placeholderSrc),\n\t\t\tcreateJsxStringAttribute(DATA_IMAGE_SKELETON, \"true\")\n\t\t];\n\t\treturn {\n\t\t\t...ctx,\n\t\t\ttarget: {\n\t\t\t\t...ctx.target,\n\t\t\t\tattributes\n\t\t\t}\n\t\t};\n\t}\n};\n//#endregion\n//#region src/rules/transform-interactive.ts\nconst INTERACTIVE_TAGS = /* @__PURE__ */ new Set([\n\t\"input\",\n\t\"textarea\",\n\t\"select\",\n\t\"option\",\n\t\"optgroup\",\n\t\"button\",\n\t\"label\",\n\t\"fieldset\",\n\t\"legend\",\n\t\"output\",\n\t\"datalist\",\n\t\"a\",\n\t\"details\",\n\t\"summary\",\n\t\"audio\",\n\t\"video\",\n\t\"iframe\",\n\t\"embed\",\n\t\"object\",\n\t\"dialog\"\n]);\nconst INTERACTIVE_ROLES = /* @__PURE__ */ new Set([\n\t\"button\",\n\t\"link\",\n\t\"tab\",\n\t\"menuitem\",\n\t\"checkbox\",\n\t\"radio\",\n\t\"switch\",\n\t\"option\",\n\t\"combobox\",\n\t\"textbox\",\n\t\"searchbox\",\n\t\"slider\",\n\t\"spinbutton\",\n\t\"listbox\",\n\t\"treeitem\",\n\t\"gridcell\",\n\t\"rowheader\",\n\t\"columnheader\"\n]);\nconst PASSWORD_MANAGER_TAGS = /* @__PURE__ */ new Set([\n\t\"input\",\n\t\"select\",\n\t\"textarea\"\n]);\nconst ARIA_ATTRIBUTES_TO_REMOVE = /* @__PURE__ */ new Set([\n\t\"role\",\n\t\"aria-label\",\n\t\"aria-labelledby\",\n\t\"aria-describedby\",\n\t\"aria-controls\",\n\t\"aria-expanded\",\n\t\"aria-haspopup\",\n\t\"aria-pressed\",\n\t\"aria-selected\",\n\t\"aria-checked\",\n\t\"aria-current\",\n\t\"contenteditable\",\n\t\"tabindex\",\n\t\"aria-hidden\",\n\t\"data-skeleton-interactive\"\n]);\nconst transformInteractiveElements = {\n\tid: \"transform-interactive-elements\",\n\tmatch: (ctx) => {\n\t\tif (ctx.element.nodeType !== 1) return false;\n\t\tconst element = ctx.element;\n\t\tconst tag = element.tagName.toLowerCase();\n\t\tif (INTERACTIVE_TAGS.has(tag)) return true;\n\t\tconst role = element.getAttribute(\"role\")?.toLowerCase();\n\t\tif (role && INTERACTIVE_ROLES.has(role)) return true;\n\t\tif (element.hasAttribute(\"contenteditable\")) return true;\n\t\tif (element.hasAttribute(\"tabindex\")) return true;\n\t\treturn false;\n\t},\n\ttransform: (ctx) => {\n\t\tif (!ctx.target) return ctx;\n\t\tconst attributes = (ctx.target.attributes ?? []).filter((attribute) => {\n\t\t\tconst name = attribute.type === \"JSXAttribute\" && attribute.name?.name ? String(attribute.name.name).toLowerCase() : \"\";\n\t\t\treturn !ARIA_ATTRIBUTES_TO_REMOVE.has(name);\n\t\t});\n\t\tattributes.push(createJsxStringAttribute(\"data-skeleton-interactive\", \"true\"), createJsxStringAttribute(\"aria-hidden\", \"true\"), createJsxExpressionAttribute(\"tabIndex\", t.numericLiteral(-1)));\n\t\tif (ctx.target.element && PASSWORD_MANAGER_TAGS.has(ctx.target.element)) {\n\t\t\tconst passwordManagerAttributes = [\n\t\t\t\tcreateJsxStringAttribute(\"autoComplete\", \"off\"),\n\t\t\t\tcreateJsxStringAttribute(\"data-1p-ignore\", \"true\"),\n\t\t\t\tcreateJsxStringAttribute(\"data-lpignore\", \"true\"),\n\t\t\t\tcreateJsxStringAttribute(\"data-bwignore\", \"true\"),\n\t\t\t\tcreateJsxStringAttribute(\"data-protonpass-ignore\", \"true\"),\n\t\t\t\tcreateJsxStringAttribute(\"form\", \"none\")\n\t\t\t];\n\t\t\tfor (const attribute of passwordManagerAttributes) {\n\t\t\t\tconst name = attribute.name?.name ? String(attribute.name.name).toLowerCase() : \"\";\n\t\t\t\tconst existingIndex = attributes.findIndex((existing) => existing.type === \"JSXAttribute\" && existing.name?.name && String(existing.name.name).toLowerCase() === name);\n\t\t\t\tif (existingIndex >= 0) attributes[existingIndex] = attribute;\n\t\t\t\telse attributes.push(attribute);\n\t\t\t}\n\t\t}\n\t\treturn {\n\t\t\t...ctx,\n\t\t\ttarget: {\n\t\t\t\t...ctx.target,\n\t\t\t\tattributes\n\t\t\t}\n\t\t};\n\t}\n};\n//#endregion\n//#region src/helpers/hash.ts\nfunction spacePreservedObfuscator(input) {\n\tif (!input) return null;\n\treturn [...input].map((char) => char === \" \" ? \" \" : \"█\").join(\"\");\n}\n//#endregion\n//#region src/index.ts\nconst executor = buildExecutor([\n\tskipNode,\n\t{\n\t\tid: \"transform-text\",\n\t\tskipAllRest: true,\n\t\tmatch: (ctx) => ctx.element.nodeType === 3,\n\t\ttransform: (ctx) => {\n\t\t\tconst text = spacePreservedObfuscator(ctx.element.textContent?.trim());\n\t\t\tif (!text) return ctx;\n\t\t\tconst isHeading = ctx.parentNode?.nodeName.toLowerCase().startsWith(\"h\");\n\t\t\tif (![\"p\", \"label\"].includes(ctx.parentNode?.nodeName.toLowerCase() ?? \"\") && !isHeading) return {\n\t\t\t\t...ctx,\n\t\t\t\ttarget: {\n\t\t\t\t\telement: \"TEXT\",\n\t\t\t\t\tchildren: [jsxText(text)]\n\t\t\t\t}\n\t\t\t};\n\t\t\treturn {\n\t\t\t\t...ctx,\n\t\t\t\ttarget: {\n\t\t\t\t\telement: \"span\",\n\t\t\t\t\tattributes: [\n\t\t\t\t\t\tcreateJsxStringAttribute(\"className\", TEXT_CLASSNAME),\n\t\t\t\t\t\tcreateJsxStringAttribute(\"data-text-node\", \"true\"),\n\t\t\t\t\t\tcreateJsxStringAttribute(DEPTH_ATTRIBUTE, ctx.parentDepth ?? String(ctx.depth))\n\t\t\t\t\t],\n\t\t\t\t\tchildren: [jsxText(text)]\n\t\t\t\t}\n\t\t\t};\n\t\t}\n\t},\n\tremoveReduntantNode,\n\tpopulateAttrs,\n\tprocessSvg,\n\ttransformImg,\n\ttransformInteractiveElements,\n\taddRootSkeletonsAttrs\n]);\nfunction excarnate(element, depth, parentNode = null, parentDepth) {\n\tconst target = executor({\n\t\telement,\n\t\tdepth,\n\t\tparentNode,\n\t\tparentDepth\n\t}).target;\n\tif (!target) return null;\n\tconst { children, element: tagName, attributes } = target;\n\tif (tagName === \"TEXT\") return children?.[0] ?? null;\n\tif (children) return createJsxElement(tagName, children, attributes);\n\tconst { childNodes } = element ?? { childNodes: [] };\n\treturn createJsxElement(tagName, Array.from(childNodes).map((child) => excarnate(child, depth + 1, element, depth.toString())).filter(Boolean), attributes);\n}\n//#endregion\nexport { excarnate as default };\n\n//# sourceMappingURL=index.mjs.map","import { JSDOM } from \"jsdom\";\nimport pkg from \"@babel/generator\";\n\n// @ts-ignore\nconst generate = pkg.default;\n\nimport htmlNodeToJsx from \"@skullmaster/excarnate\";\n\nexport function transformInput(html: string) {\n const dom = new JSDOM(html);\n\n const root = dom.window.document.body.firstElementChild;\n\n if (!root) {\n throw new Error(\"No root element found\");\n }\n\n const jsxAst = htmlNodeToJsx(root, 0);\n\n if (!jsxAst) {\n throw new Error(\"Failed to generate JSX AST\");\n }\n\n const result = generate(jsxAst, {\n jsescOption: {\n minimal: true,\n },\n });\n\n return result.code;\n}\n","export function toPascalCase(input: string): string {\n return input\n .trim()\n .replace(/['\"]/g, \"\")\n .split(/[^a-zA-Z0-9]+/)\n .filter(Boolean)\n .map((word) => word.charAt(0).toUpperCase() + word.slice(1))\n .join(\"\");\n}\n","export function fnv1a(str: string): number {\n let hash = 0x811c9dc5;\n\n for (let i = 0; i < str.length; i++) {\n hash ^= str.charCodeAt(i);\n hash = Math.imul(hash, 0x01000193);\n }\n\n return hash >>> 0;\n}\n","import { serve } from \"@hono/node-server\";\nimport { Hono } from \"hono\";\nimport { cors } from \"hono/cors\";\nimport { Project } from \"ts-morph\";\nimport { SkeletonCacheDB } from \"../cache\";\nimport generateTarget from \"../generate-target\";\nimport { transformInput } from \"../transform\";\nimport { toPascalCase } from \"../utils/to-pascal-case\";\nimport { fnv1a } from \"../utils/fnv1a\";\nimport type { Config } from \"../init/preferences\";\nimport { log, SkeletonPayloadInputSchema } from \"../shared\";\n\nexport async function serveCommand(config: Config, port: number) {\n const app = new Hono();\n\n app.use(\n \"*\",\n cors({\n origin: \"*\",\n allowMethods: [\"GET\", \"POST\", \"OPTIONS\"],\n allowHeaders: [\"Content-Type\", \"Authorization\"],\n }),\n );\n\n const db = await SkeletonCacheDB.create(config);\n\n app.get(\"/health\", (c) => {\n return c.json({\n ok: true,\n config: config.configJson(),\n });\n });\n\n app.post(\"/skeletons\", async (c) => {\n const body = await c.req.json();\n\n const result = SkeletonPayloadInputSchema.parse(body);\n\n const project = new Project();\n const entries = Object.entries(result).map(async ([key, value]) => {\n const componentName = toPascalCase(value.component);\n const transformedHtml = transformInput(value.html);\n const hash = fnv1a(transformedHtml).toString();\n const cached = db.get(key);\n const shouldSkip = cached && cached.hash === hash;\n\n if (shouldSkip) {\n return;\n }\n\n generateTarget({\n project,\n filePath: `${config.getSkeletonPath()}/${componentName}.${config.getExt()}`,\n componentName,\n body: transformedHtml,\n });\n\n await db.set(key, {\n component: value.component,\n html: transformedHtml,\n hash,\n });\n });\n await Promise.all(entries);\n config.registry({ type: \"add\", components: db.getComponentNames() });\n await project.save();\n\n return c.json({\n sucess: true,\n });\n });\n\n serve(\n {\n fetch: app.fetch,\n port,\n },\n (info) => {\n log.info(`Server running at http://localhost:${info.port}`);\n },\n );\n}\n","import { access } from \"node:fs/promises\";\n\nexport default async function fileExists(path: string): Promise<boolean> {\n try {\n await access(path);\n return true;\n } catch {\n return false;\n }\n}\n","export const CONFIG_PATH = \"skullmaster.config.json\";\n","import { cancel, isCancel, select, text } from \"@clack/prompts\";\nimport fileExists from \"./is-file-exists\";\nimport { readFile, writeFile } from \"fs/promises\";\nimport { CONFIG_PATH } from \"../constants\";\n\nexport type Preferences = {\n outDir: string;\n project: string;\n};\n\nexport default async function collectPreferences(): Promise<Preferences> {\n const isAlreadyInitialized = await fileExists(CONFIG_PATH);\n if (isAlreadyInitialized) {\n return JSON.parse(await readFile(`./${CONFIG_PATH}`, \"utf-8\"));\n }\n\n const outDir = await text({\n message: \"Where do you want to output the generated files?\",\n placeholder: \"src/skeletons\",\n initialValue: \"src/skeletons\",\n validate(value) {\n if (value?.length === 0) return `Value is required!`;\n },\n });\n if (isCancel(outDir)) {\n cancel(\"Operation cancelled.\");\n process.exit(0);\n }\n\n const projectType = await select({\n message: \"Pick a project type.\",\n initialValue: \"react-ts\",\n options: [\n { value: \"react-ts\", label: \"React with TypeScript\" },\n { value: \"react-js\", label: \"React\" },\n ],\n });\n\n if (isCancel(projectType)) {\n cancel(\"Operation cancelled.\");\n process.exit(0);\n }\n\n const preferences = {\n outDir,\n project: projectType.toString(),\n };\n await writeFile(`./${CONFIG_PATH}`, JSON.stringify(preferences, null, 2), \"utf-8\");\n\n return preferences;\n}\n","import { SourceFile } from \"ts-morph\";\n\nexport function ensureLazyImport(sourceFile: SourceFile) {\n const reactImport = sourceFile.getImportDeclaration(\n (d) => d.getModuleSpecifierValue() === \"react\",\n );\n\n if (!reactImport) {\n sourceFile.addImportDeclaration({\n moduleSpecifier: \"react\",\n namedImports: [\"lazy\"],\n });\n\n return;\n }\n\n const hasLazy = reactImport.getNamedImports().some((i) => i.getName() === \"lazy\");\n\n if (!hasLazy) {\n reactImport.addNamedImport(\"lazy\");\n }\n}\n","import { Project, SyntaxKind } from \"ts-morph\";\nimport { writeFile } from \"node:fs/promises\";\nimport { ensureLazyImport } from \"./ensure-lazy-imports\";\nimport { toPascalCase } from \"../utils/to-pascal-case\";\n\nexport async function generateInitialRegistry(outDir: string, projectType: string) {\n const isTs = projectType.endsWith(\"ts\");\n\n const ext = isTs ? \"tsx\" : \"jsx\";\n\n const skullTypes = isTs\n ? `\nexport type SkullTweaks = {\n /** Exclude this element and its entire subtree from skeleton generation. */\n hideSubTree?: boolean;\n /** Render this element as transparent (layout preserved) in the skeleton. */\n isTransparent?: boolean;\n};\n\nexport type WithDataSkull = HTMLAttributes<HTMLElement> & {\n \"data-skullmaster\": string;\n \"data-skip-skull\"?: boolean;\n \"data-depth\"?: \"-1\";\n};\n`\n : \"\";\n\n const skullUtils = `\nconst buildSkullAttributes = ({ hideSubTree, isTransparent }${\n isTs ? \": SkullTweaks\" : \"\"\n })${isTs ? ': Omit<WithDataSkull, \"data-skullmaster\">' : \"\"} => {\n return {\n \"data-skip-skull\": hideSubTree,\n \"data-depth\": isTransparent ? \"-1\" : undefined,\n };\n};\n\nexport const markAsSkull = (name: string, tweaks${\n isTs ? \": SkullTweaks\" : \"\"\n } = {})${isTs ? \": WithDataSkull\" : \"\"} => {\n return {\n \"data-skullmaster\": name,\n ...buildSkullAttributes(tweaks),\n };\n};\n\nexport const tweakForSkull = (tweaks${\n isTs ? \": SkullTweaks\" : \"\"\n } = {})${isTs ? ': Omit<WithDataSkull, \"data-skullmaster\">' : \"\"} => {\n return buildSkullAttributes(tweaks);\n};\n`;\n\n const skeletonPropsType = isTs\n ? `\ntype SkeletonProps = {\n name: keyof typeof registry | (string & {});\n defaultBoneProps?: ComponentProps<typeof DefaultBone>;\n};\n`\n : \"\";\n\n await writeFile(\n `${outDir}/registry.${ext}`,\n `\n/* eslint-disable */\n/* oxlint-disable */\n/* biome-ignore-all lint */\n/* @ts-nocheck */\n\n/**\n * Auto-generated by Skullmaster.\n *\n * Do not edit this file manually.\n * Use Skullmaster commands to add, update, or remove skeletons.\n *\n */\n\nimport \"@skullmaster/react/style.css\";\nimport DefaultBone from \"./skeletons/DefaultBone\";\n${isTs ? 'import { type ComponentProps, type HTMLAttributes, lazy } from \"react\";' : \"\"}\n\nconst registry = {default: lazy(() => import(\"./skeletons/DefaultBone\"))}${isTs ? \" as const\" : \"\"};\n\n${skullTypes}${skeletonPropsType}${skullUtils}\nexport default function Skeleton({\n name,\n defaultBoneProps = {},\n}${isTs ? \": SkeletonProps\" : \"\"}) {\n const Component = registry[name];\n\n if (!Component) {\n return <DefaultBone {...defaultBoneProps} />;\n }\n\n return <Component />;\n}\n`,\n \"utf8\",\n );\n}\nexport type RegistryOperation =\n | { type: \"init\"; components: string[] }\n | { type: \"add\"; components: string[] };\n\nexport async function generateRegistry(\n operation: RegistryOperation,\n isTs: boolean,\n registryPath: string,\n) {\n const project = isTs\n ? new Project({\n tsConfigFilePath: \"tsconfig.json\",\n })\n : new Project();\n\n const sourceFile = project.addSourceFileAtPath(registryPath);\n\n ensureLazyImport(sourceFile);\n\n const registry =\n sourceFile\n .getVariableDeclaration(\"registry\")\n ?.getInitializerIfKind(SyntaxKind.AsExpression)\n ?.getExpressionIfKind(SyntaxKind.ObjectLiteralExpression) ??\n sourceFile\n .getVariableDeclaration(\"registry\")\n ?.getInitializerIfKind(SyntaxKind.ObjectLiteralExpression);\n\n if (!registry) {\n throw new Error(\"Unable to locate registry object, have you ran skullmaster init??\");\n }\n\n const existingComponents = new Set(\n registry\n .getProperties()\n .filter((property) => property.getKind() === SyntaxKind.PropertyAssignment)\n .map((property) => property.asKindOrThrow(SyntaxKind.PropertyAssignment))\n .map((property) => property.getName().replace(/['\"]/g, \"\")),\n );\n\n for (let component of operation.components) {\n component = toPascalCase(component);\n\n if (existingComponents.has(component)) {\n continue;\n }\n\n registry.addPropertyAssignment({\n name: `\"${component}\"`,\n initializer: `lazy(() => import(\"./skeletons/${component}\"))`,\n });\n }\n\n if (isTs) {\n const declaration = sourceFile.getVariableDeclarationOrThrow(\"registry\");\n\n const initializer = declaration.getInitializer();\n\n if (initializer && !initializer.isKind(SyntaxKind.AsExpression)) {\n declaration.setInitializer(`${initializer.getText()} as const`);\n }\n }\n\n sourceFile.formatText();\n\n await sourceFile.save();\n\n project.saveSync();\n}\n","import { readFile, writeFile } from \"node:fs/promises\";\nimport z from \"zod\";\nimport fileExists from \"./is-file-exists\";\nimport { fnv1a } from \"../utils/fnv1a\";\nimport { SkeletonCacheEntrySchema } from \"../shared\";\n\nexport type CacheOperation =\n | { type: \"replace\"; cacheEntry: z.infer<typeof SkeletonCacheEntrySchema> }\n | { type: \"delete\"; componentName: string }\n | {\n type: \"update\";\n componentName: string;\n payload: z.infer<typeof SkeletonCacheEntrySchema>[string];\n };\n\nexport async function updateCacheRegistry(operation: CacheOperation, outDir: string) {\n const cacheFilePath = outDir;\n let cacheEntries: z.infer<typeof SkeletonCacheEntrySchema> = {};\n if (!(await fileExists(cacheFilePath))) {\n await writeFile(cacheFilePath, JSON.stringify({}), \"utf8\");\n } else {\n cacheEntries = SkeletonCacheEntrySchema.parse(\n JSON.parse(await readFile(cacheFilePath, \"utf8\")),\n );\n }\n switch (operation.type) {\n case \"replace\":\n await writeFile(cacheFilePath, JSON.stringify(operation.cacheEntry), \"utf8\");\n break;\n case \"delete\":\n delete cacheEntries[operation.componentName];\n await writeFile(cacheFilePath, JSON.stringify(cacheEntries), \"utf8\");\n break;\n case \"update\":\n cacheEntries[operation.componentName] = {\n ...operation.payload,\n hash: fnv1a(operation.payload.html).toString(),\n };\n await writeFile(cacheFilePath, JSON.stringify(cacheEntries), \"utf8\");\n }\n}\n","import { writeFile } from \"node:fs/promises\";\n\nexport default async function defaultBone(target: string) {\n await writeFile(\n target,\n `\n/* eslint-disable */\n/* oxlint-disable */\n/* biome-ignore-all lint */\n/* @ts-nocheck */\n\nimport type { HTMLProps } from \"react\";\n\n/**\n * Auto-generated by Skullmaster.\n *\n * This is the default fallback skeleton component displayed when a\n * matching skeleton implementation cannot be found in the registry.\n *\n * You may freely customize or replace this component to match the\n * loading experience of your application.\n */\ntype DefaultBoneProps = HTMLProps<HTMLDivElement>;\n\nexport default function DefaultBone(props: DefaultBoneProps) {\n return <div {...props}>loading...</div>;\n}\n`,\n \"utf8\",\n );\n}\n","import { mkdirSync, readdirSync, rmSync, writeFileSync } from \"node:fs\";\nimport fileExists from \"./is-file-exists\";\nimport { generateInitialRegistry, generateRegistry, type RegistryOperation } from \"./registry\";\nimport { updateCacheRegistry, type CacheOperation } from \"./cache-registry\";\nimport defaultBone from \"./default-bone\";\nimport { log } from \"../shared\";\n\nexport class Config {\n outDir: string;\n projectType: string;\n\n constructor(outDir: string, projectType: string) {\n this.outDir = outDir;\n this.projectType = projectType;\n }\n async initialize(forceReset?: boolean) {\n log.info(\"Initializing project structure...\");\n if (!(await fileExists(this.outDir))) {\n mkdirSync(this.outDir, { recursive: true });\n log.success(`Created output directory: ${this.outDir}`);\n } else {\n log.gray(`Output directory exists: ${this.outDir}`);\n }\n const skeletonsDirectoryPath = this.getSkeletonPath();\n if (!(await fileExists(skeletonsDirectoryPath))) {\n mkdirSync(skeletonsDirectoryPath, { recursive: true });\n log.success(`Created skeletons directory: ${skeletonsDirectoryPath}`);\n } else if (forceReset) {\n for (const file of readdirSync(skeletonsDirectoryPath)) {\n rmSync(`${skeletonsDirectoryPath}/${file}`, { recursive: true });\n }\n log.success(`Cleared skeletons directory: ${skeletonsDirectoryPath}`);\n } else {\n log.gray(`Skeletons directory exists: ${skeletonsDirectoryPath}`);\n }\n const registryFilePath = this.getRegistryPath();\n if (forceReset || !(await fileExists(registryFilePath))) {\n await generateInitialRegistry(this.outDir, this.projectType);\n log.success(`Created registry: ${registryFilePath}`);\n } else {\n log.gray(`Registry exists: ${registryFilePath}`);\n }\n const cachePath = this.getCachePath();\n if (forceReset || !(await fileExists(cachePath))) {\n writeFileSync(cachePath, JSON.stringify({}), \"utf8\");\n log.success(`Created cache: ${cachePath}`);\n } else {\n log.gray(`Cache exists: ${cachePath}`);\n }\n const defaultBonePath = this.getDefSkeletonPath();\n if (forceReset || !(await fileExists(defaultBonePath))) {\n await defaultBone(defaultBonePath);\n log.success(`Created default bone: ${defaultBonePath}`);\n } else {\n log.gray(`Default bone exists: ${defaultBonePath}`);\n }\n log.success(\"Initialization complete\");\n }\n async cache(op: CacheOperation) {\n return await updateCacheRegistry(op, this.getCachePath());\n }\n async registry(op: RegistryOperation) {\n return generateRegistry(op, this.projectType.endsWith(\"ts\"), this.getRegistryPath());\n }\n getCachePath() {\n return `${this.outDir}/cache.json`;\n }\n getSkeletonPath() {\n return `${this.outDir}/skeletons`;\n }\n getDefSkeletonPath() {\n return `${this.getSkeletonPath()}/DefaultBone.${this.getExt()}`;\n }\n getExt() {\n return this.projectType.endsWith(\"ts\") ? \"tsx\" : \"jsx\";\n }\n getRegistryPath() {\n return `${this.outDir}/registry.${this.getExt()}`;\n }\n configJson() {\n return { projectType: this.projectType, outDir: this.outDir };\n }\n}\n","#!/usr/bin/env node\n\nimport { cac } from \"cac\";\nimport { cancel, isCancel, confirm } from \"@clack/prompts\";\nimport { serveCommand } from \"./commands/serve\";\nimport collectPreferences from \"./init/collect-preferences\";\nimport { Config } from \"./init/preferences\";\nimport { DEFAULT_PORT, log } from \"./shared\";\n\nconst cli = cac(\"💀\");\n\ncli\n .command(\"serve\", \"Start 💀 dev server\")\n .option(\"--port <port>\", \"Port\", {\n default: DEFAULT_PORT,\n })\n .action(async (options) => {\n const preferences = await collectPreferences();\n const config = new Config(preferences.outDir, preferences.project);\n await config.initialize();\n await serveCommand(config, Number(options.port));\n });\n\ncli.command(\"reset\", \"Reset Skullmaster to its initial state\").action(async () => {\n const proceed = await confirm({\n message:\n \"This will wipe out all present generated skeletons and reset the registry. Are you sure?\",\n });\n\n if (isCancel(proceed) || !proceed) {\n cancel(\"Reset cancelled.\");\n process.exit(0);\n }\n\n const preferences = await collectPreferences();\n const config = new Config(preferences.outDir, preferences.project);\n await config.initialize(true);\n log.success(\"Reset complete\");\n});\n\ncli.help();\ncli.parse();\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"cli.mjs","names":["readFile","writeFile"],"sources":["../src/shared/constants.ts","../src/shared/schema.ts","../src/shared/log.ts","../src/cache/index.ts","../src/generate-target/index.ts","../src/transform/index.ts","../src/utils/to-pascal-case.ts","../src/utils/fnv1a.ts","../src/commands/serve.ts","../src/init/is-file-exists.ts","../src/constants.ts","../src/init/collect-preferences.ts","../src/init/registry/header.ts","../src/init/registry/extension.ts","../src/init/registry/imports.ts","../src/init/registry/registry-object.ts","../src/init/registry/skull-types.ts","../src/init/registry/skeleton-props.ts","../src/init/registry/skull-utils.ts","../src/init/registry/skeleton.ts","../src/init/registry/index.ts","../src/init/ensure-lazy-imports.ts","../src/init/registry/operations.ts","../src/init/cache-registry.ts","../src/init/default-bone.ts","../src/init/preferences.ts","../src/cli.ts"],"sourcesContent":["export const DEFAULT_PORT = 8008;\nexport const EMPTY_SET_DEFAULT_DIR = \"skullmaster\";\nexport const DATA_NAT_H = \"data-natural-h\";\nexport const DATA_NAT_W = \"data-natural-w\";\n","import z from \"zod\";\n\nexport const SkeletonPayloadInputSchema = z.record(\n z.string(),\n z.object({\n component: z.string(),\n html: z.string(),\n }),\n);\n\nexport const SkeletonCacheEntrySchema = z.record(\n z.string(),\n z.object({\n component: z.string(),\n html: z.string(),\n hash: z.string(),\n }),\n);\n\nexport type SkeletonPayloadInput = z.infer<typeof SkeletonPayloadInputSchema>;\n\nexport type SkeletonCacheEntry = z.infer<typeof SkeletonCacheEntrySchema>;\n","export const log = {\n success: (message: string) => console.log(`\\x1b[32m[💀] ${message}\\x1b[0m`),\n info: (message: string) => console.log(`\\x1b[36m[💀] ${message}\\x1b[0m`),\n warn: (message: string) => console.log(`\\x1b[33m[💀] ${message}\\x1b[0m`),\n error: (message: string) => console.log(`\\x1b[31m[💀] ${message}\\x1b[0m`),\n gray: (message: string) => console.log(`\\x1b[90m[💀] ${message}\\x1b[0m`),\n};\n","import { readFile } from \"node:fs/promises\";\nimport type { Config } from \"../init/preferences\";\nimport { type SkeletonCacheEntry, SkeletonCacheEntrySchema } from \"../shared\";\n\nexport class SkeletonCacheDB {\n private data: SkeletonCacheEntry = {};\n config: Config;\n private constructor(config: Config) {\n this.config = config;\n }\n\n static async create(config: Config) {\n const db = new SkeletonCacheDB(config);\n\n await db.load();\n\n return db;\n }\n\n private async load() {\n try {\n const file = await readFile(this.config.getCachePath(), \"utf8\");\n\n const parsed = JSON.parse(file);\n\n this.data = SkeletonCacheEntrySchema.parse(parsed);\n } catch {\n this.data = {};\n\n await this.config.cache({ type: \"replace\", cacheEntry: {} });\n }\n }\n\n get(key: string) {\n return this.data[key];\n }\n getComponentNames(): string[] {\n return Object.values(this.data).map((entry) => entry.component);\n }\n\n async set(key: string, value: SkeletonCacheEntry[string]) {\n this.data[key] = value;\n this.config.cache({ type: \"update\", componentName: key, payload: value });\n }\n}\n","import { Project, QuoteKind, ScriptKind } from \"ts-morph\";\n\ntype GenerateTargetOptions = {\n project: Project;\n filePath: string;\n componentName: string;\n body: string;\n};\n\nexport default function generateTarget({\n project,\n filePath,\n componentName,\n body,\n}: GenerateTargetOptions) {\n project.manipulationSettings.set({\n quoteKind: QuoteKind.Double,\n });\n\n const file = project.createSourceFile(filePath, \"\", {\n overwrite: true,\n scriptKind: ScriptKind.TSX,\n });\n\n file.insertText(\n 0,\n `/* eslint-disable */\n/* prettier-ignore-start */\n\n/**\n * Auto-generated by Skullmaster.\n *\n * DO NOT EDIT THIS FILE MANUALLY.\n * Changes may be overwritten on the next generation.\n */\n\n`,\n );\n\n file.addFunction({\n name: componentName,\n isDefaultExport: true,\n statements: [`return (${body});`],\n });\n\n file.addStatements(`\n/* prettier-ignore-end */\n`);\n}\n","import { JSDOM } from \"jsdom\";\nimport pkg from \"@babel/generator\";\n\n// @ts-ignore\nconst generate = pkg.default;\n\nimport htmlNodeToJsx from \"@skullmaster/excarnate\";\n\nexport function transformInput(html: string) {\n const dom = new JSDOM(html);\n\n const root = dom.window.document.body.firstElementChild;\n\n if (!root) {\n throw new Error(\"No root element found\");\n }\n\n const jsxAst = htmlNodeToJsx(root, 0);\n\n if (!jsxAst) {\n throw new Error(\"Failed to generate JSX AST\");\n }\n\n const result = generate(jsxAst, {\n jsescOption: {\n minimal: true,\n },\n });\n\n return result.code;\n}\n","export function toPascalCase(input: string): string {\n return input\n .trim()\n .replace(/['\"]/g, \"\")\n .split(/[^a-zA-Z0-9]+/)\n .filter(Boolean)\n .map((word) => word.charAt(0).toUpperCase() + word.slice(1))\n .join(\"\");\n}\n","export function fnv1a(str: string): number {\n let hash = 0x811c9dc5;\n\n for (let i = 0; i < str.length; i++) {\n hash ^= str.charCodeAt(i);\n hash = Math.imul(hash, 0x01000193);\n }\n\n return hash >>> 0;\n}\n","import { serve } from \"@hono/node-server\";\nimport { Hono } from \"hono\";\nimport { cors } from \"hono/cors\";\nimport { Project } from \"ts-morph\";\nimport { SkeletonCacheDB } from \"../cache\";\nimport generateTarget from \"../generate-target\";\nimport { transformInput } from \"../transform\";\nimport { toPascalCase } from \"../utils/to-pascal-case\";\nimport { fnv1a } from \"../utils/fnv1a\";\nimport type { Config } from \"../init/preferences\";\nimport { log, SkeletonPayloadInputSchema } from \"../shared\";\n\nexport async function serveCommand(config: Config, port: number) {\n const app = new Hono();\n\n app.use(\n \"*\",\n cors({\n origin: \"*\",\n allowMethods: [\"GET\", \"POST\", \"OPTIONS\"],\n allowHeaders: [\"Content-Type\", \"Authorization\"],\n }),\n );\n\n const db = await SkeletonCacheDB.create(config);\n\n app.get(\"/health\", (c) => {\n return c.json({\n ok: true,\n config: config.configJson(),\n });\n });\n\n app.post(\"/skeletons\", async (c) => {\n const body = await c.req.json();\n\n const result = SkeletonPayloadInputSchema.parse(body);\n\n const project = new Project();\n const entries = Object.entries(result).map(async ([key, value]) => {\n const componentName = toPascalCase(value.component);\n const transformedHtml = transformInput(value.html);\n const hash = fnv1a(transformedHtml).toString();\n const cached = db.get(key);\n const shouldSkip = cached && cached.hash === hash;\n\n if (shouldSkip) {\n return;\n }\n\n generateTarget({\n project,\n filePath: `${config.getSkeletonPath()}/${componentName}.${config.getExt()}`,\n componentName,\n body: transformedHtml,\n });\n\n await db.set(key, {\n component: value.component,\n html: transformedHtml,\n hash,\n });\n });\n await Promise.all(entries);\n config.registry({ type: \"add\", components: db.getComponentNames() });\n await project.save();\n\n return c.json({\n sucess: true,\n });\n });\n\n serve(\n {\n fetch: app.fetch,\n port,\n },\n (info) => {\n log.info(`Server running at http://localhost:${info.port}`);\n },\n );\n}\n","import { access } from \"node:fs/promises\";\n\nexport default async function fileExists(path: string): Promise<boolean> {\n try {\n await access(path);\n return true;\n } catch {\n return false;\n }\n}\n","export const CONFIG_PATH = \"skullmaster.config.json\";\n","import { cancel, isCancel, select, text } from \"@clack/prompts\";\nimport fileExists from \"./is-file-exists\";\nimport { readFile, writeFile } from \"fs/promises\";\nimport { CONFIG_PATH } from \"../constants\";\nexport const projectTypes = [\n { value: \"react\", label: \"React\" } as const,\n { value: \"preact\", label: \"Preact\" } as const,\n];\nconst projectVariantType = [\n { value: \"ts\", label: \"TypeScript\" } as const,\n { value: \"js\", label: \"JavaScript\" } as const,\n];\nexport type Preferences = {\n outDir: string;\n project: `${(typeof projectTypes)[number][\"value\"]}-${(typeof projectVariantType)[number][\"value\"]}`;\n};\n\nexport default async function collectPreferences(): Promise<Preferences> {\n const isAlreadyInitialized = await fileExists(CONFIG_PATH);\n if (isAlreadyInitialized) {\n return JSON.parse(await readFile(`./${CONFIG_PATH}`, \"utf-8\"));\n }\n\n const outDir = await text({\n message: \"Where do you want to output the generated files?\",\n placeholder: \"src/skeletons\",\n initialValue: \"src/skeletons\",\n validate(value) {\n if (value?.length === 0) return `Value is required!`;\n },\n });\n if (isCancel(outDir)) {\n cancel(\"Operation cancelled.\");\n process.exit(0);\n }\n\n const projectType = await select({\n message: \"Pick a project type.\",\n initialValue: \"react\",\n options: projectTypes,\n });\n\n if (isCancel(projectType)) {\n cancel(\"Operation cancelled.\");\n process.exit(0);\n }\n\n const variant = await select({\n message: \"Pick a project variant.\",\n initialValue: \"ts\",\n options: projectVariantType,\n });\n\n if (isCancel(variant)) {\n cancel(\"Operation cancelled.\");\n process.exit(0);\n }\n\n const preferences: Preferences = {\n outDir,\n project: `${projectType}-${variant.toString()}` as Preferences[\"project\"],\n };\n await writeFile(`./${CONFIG_PATH}`, JSON.stringify(preferences, null, 2), \"utf-8\");\n\n return preferences;\n}\n","export const REGISTRY_HEADER = `\n/* eslint-disable */\n/* oxlint-disable */\n/* biome-ignore-all lint */\n/* @ts-nocheck */\n\n/**\n * Auto-generated by Skullmaster.\n *\n * Do not edit this file manually.\n * Use Skullmaster commands to add, update, or remove skeletons.\n *\n */\n`;\n","import type { Preferences } from \"../collect-preferences\";\n\nexport const getExtension = (project: Preferences[\"project\"]): \"tsx\" | \"jsx\" => {\n switch (project) {\n case \"react-ts\":\n case \"preact-ts\":\n return \"tsx\";\n case \"react-js\":\n case \"preact-js\":\n return \"jsx\";\n }\n};\n","import type { Preferences } from \"../collect-preferences\";\n\nexport const REGISTRY_IMPORTS = (project: Preferences[\"project\"]): string => {\n switch (project) {\n case \"react-ts\":\n return `import \"@skullmaster/react/style.css\";\nimport DefaultBone from \"./skeletons/DefaultBone\";\nimport { type ComponentProps, type HTMLAttributes, lazy } from \"react\";`;\n case \"react-js\":\n return `import \"@skullmaster/react/style.css\";\nimport DefaultBone from \"./skeletons/DefaultBone\";\nimport { lazy } from \"react\";`;\n case \"preact-ts\":\n return `import \"@skullmaster/preact/style.css\";\nimport DefaultBone from \"./skeletons/DefaultBone\";\nimport { type ComponentProps, type HTMLAttributes, lazy } from \"preact/compat\";`;\n case \"preact-js\":\n return `import \"@skullmaster/preact/style.css\";\nimport DefaultBone from \"./skeletons/DefaultBone\";\nimport { lazy } from \"preact/compat\";`;\n }\n};\n","import type { Preferences } from \"../collect-preferences\";\n\nexport const REGISTRY_OBJECT = (project: Preferences[\"project\"]): string => {\n switch (project) {\n case \"react-ts\":\n return `const registry = {default: lazy(() => import(\"./skeletons/DefaultBone\"))} as const;`;\n case \"preact-ts\":\n return `const registry = {default: lazy(() => import(\"./skeletons/DefaultBone\"))} as const;`;\n case \"react-js\":\n case \"preact-js\":\n return `const registry = {default: lazy(() => import(\"./skeletons/DefaultBone\"))};`;\n }\n};\n","import type { Preferences } from \"../collect-preferences\";\n\nconst JSX_SKULL_TYPES = `\nexport type SkullTweaks = {\n /** Exclude this element and its entire subtree from skeleton generation. */\n hideSubTree?: boolean;\n /** Render this element as transparent (layout preserved) in the skeleton. */\n isTransparent?: boolean;\n};\n\nexport type WithDataSkull = HTMLAttributes<HTMLElement> & {\n \"data-skullmaster\": string;\n \"data-skip-skull\"?: boolean;\n \"data-depth\"?: \"-1\";\n};\n`;\n\nexport const REGISTRY_SKULL_TYPES = (project: Preferences[\"project\"]): string => {\n switch (project) {\n case \"react-ts\":\n return JSX_SKULL_TYPES;\n case \"preact-ts\":\n return JSX_SKULL_TYPES;\n case \"react-js\":\n case \"preact-js\":\n return \"\";\n }\n};\n","import type { Preferences } from \"../collect-preferences\";\n\nexport const REGISTRY_SKELETON_PROPS_TYPE = (project: Preferences[\"project\"]): string => {\n switch (project) {\n case \"react-ts\":\n return `\ntype SkeletonProps = {\n name: keyof typeof registry | (string & {});\n defaultBoneProps?: ComponentProps<typeof DefaultBone>;\n};\n`;\n case \"preact-ts\":\n return `\ntype SkeletonProps = {\n name: keyof typeof registry | (string & {});\n defaultBoneProps?: ComponentProps<typeof DefaultBone>;\n};\n`;\n case \"react-js\":\n case \"preact-js\":\n return \"\";\n }\n};\n","import type { Preferences } from \"../collect-preferences\";\n\nconst JSX_SKULL_UTILS_TS = `\nconst buildSkullAttributes = ({ hideSubTree, isTransparent }: SkullTweaks): Omit<WithDataSkull, \"data-skullmaster\"> => {\n return {\n \"data-skip-skull\": hideSubTree,\n \"data-depth\": isTransparent ? \"-1\" : undefined,\n };\n};\n\nexport const markAsSkull = (name: string, tweaks: SkullTweaks = {}): WithDataSkull => {\n return {\n \"data-skullmaster\": name,\n ...buildSkullAttributes(tweaks),\n };\n};\n\nexport const tweakForSkull = (tweaks: SkullTweaks = {}): Omit<WithDataSkull, \"data-skullmaster\"> => {\n return buildSkullAttributes(tweaks);\n};\n`;\n\nconst JSX_SKULL_UTILS_JS = `\nconst buildSkullAttributes = ({ hideSubTree, isTransparent }) => {\n return {\n \"data-skip-skull\": hideSubTree,\n \"data-depth\": isTransparent ? \"-1\" : undefined,\n };\n};\n\nexport const markAsSkull = (name: string, tweaks = {}) => {\n return {\n \"data-skullmaster\": name,\n ...buildSkullAttributes(tweaks),\n };\n};\n\nexport const tweakForSkull = (tweaks = {}) => {\n return buildSkullAttributes(tweaks);\n};\n`;\n\nexport const REGISTRY_SKULL_UTILS = (project: Preferences[\"project\"]): string => {\n switch (project) {\n case \"react-ts\":\n return JSX_SKULL_UTILS_TS;\n case \"react-js\":\n return JSX_SKULL_UTILS_JS;\n case \"preact-ts\":\n return JSX_SKULL_UTILS_TS;\n case \"preact-js\":\n return JSX_SKULL_UTILS_JS;\n }\n};\n","import type { Preferences } from \"../collect-preferences\";\n\nconst JSX_SKELETON_TS = `export default function Skeleton({\n name,\n defaultBoneProps = {},\n}: SkeletonProps) {\n const Component = registry[name];\n\n if (!Component) {\n return <DefaultBone {...defaultBoneProps} />;\n }\n\n return <Component />;\n}\n`;\n\nconst JSX_SKELETON_JS = `export default function Skeleton({\n name,\n defaultBoneProps = {},\n}) {\n const Component = registry[name];\n\n if (!Component) {\n return <DefaultBone {...defaultBoneProps} />;\n }\n\n return <Component />;\n}\n`;\n\nexport const REGISTRY_SKELETON = (project: Preferences[\"project\"]): string => {\n switch (project) {\n case \"react-ts\":\n return JSX_SKELETON_TS;\n case \"react-js\":\n return JSX_SKELETON_JS;\n case \"preact-ts\":\n return JSX_SKELETON_TS;\n case \"preact-js\":\n return JSX_SKELETON_JS;\n }\n};\n","import { writeFile } from \"node:fs/promises\";\nimport { REGISTRY_HEADER } from \"./header\";\nimport { getExtension } from \"./extension\";\nimport { REGISTRY_IMPORTS } from \"./imports\";\nimport { REGISTRY_OBJECT } from \"./registry-object\";\nimport { REGISTRY_SKULL_TYPES } from \"./skull-types\";\nimport { REGISTRY_SKELETON_PROPS_TYPE } from \"./skeleton-props\";\nimport { REGISTRY_SKULL_UTILS } from \"./skull-utils\";\nimport { REGISTRY_SKELETON } from \"./skeleton\";\nimport type { Preferences } from \"../collect-preferences\";\n\nexport async function generateInitialRegistry(outDir: string, projectType: Preferences[\"project\"]) {\n const ext = getExtension(projectType);\n\n const skeleton = REGISTRY_SKELETON(projectType);\n\n const content = `\n${REGISTRY_HEADER}\n\n\n${REGISTRY_IMPORTS(projectType)}\n\n${REGISTRY_OBJECT(projectType)}\n\n${REGISTRY_SKULL_TYPES(projectType)}\n${REGISTRY_SKELETON_PROPS_TYPE(projectType)}\n${REGISTRY_SKULL_UTILS(projectType)}\n${skeleton}\n`;\n\n await writeFile(`${outDir}/registry.${ext}`, content, \"utf8\");\n}\n","import { SourceFile } from \"ts-morph\";\nimport type { Preferences } from \"./collect-preferences\";\n\nexport function ensureLazyImport(sourceFile: SourceFile, project: Preferences[\"project\"]) {\n let moduleSpecifier: string;\n switch (project) {\n case \"preact-ts\":\n case \"preact-js\":\n moduleSpecifier = \"preact/compat\";\n break;\n case \"react-ts\":\n case \"react-js\":\n moduleSpecifier = \"react\";\n break;\n }\n\n const runtimeImport = sourceFile.getImportDeclaration(\n (d) => d.getModuleSpecifierValue() === moduleSpecifier,\n );\n\n if (!runtimeImport) {\n sourceFile.addImportDeclaration({\n moduleSpecifier,\n namedImports: [\"lazy\"],\n });\n\n return;\n }\n\n const hasLazy = runtimeImport.getNamedImports().some((i) => i.getName() === \"lazy\");\n\n if (!hasLazy) {\n runtimeImport.addNamedImport(\"lazy\");\n }\n}\n","import { Project, SyntaxKind } from \"ts-morph\";\nimport { ensureLazyImport } from \"../ensure-lazy-imports\";\nimport { toPascalCase } from \"../../utils/to-pascal-case\";\nimport { getExtension } from \"./extension\";\nimport type { Preferences } from \"../collect-preferences\";\n\nexport type RegistryOperation =\n | { type: \"init\"; components: string[] }\n | { type: \"add\"; components: string[] };\n\nexport async function generateRegistry(\n operation: RegistryOperation,\n project: Preferences[\"project\"],\n registryPath: string,\n) {\n const isTs = getExtension(project) === \"tsx\";\n\n const tsMorphProject = isTs\n ? new Project({\n tsConfigFilePath: \"tsconfig.json\",\n })\n : new Project();\n\n const sourceFile = tsMorphProject.addSourceFileAtPath(registryPath);\n\n ensureLazyImport(sourceFile, project);\n\n const registry =\n sourceFile\n .getVariableDeclaration(\"registry\")\n ?.getInitializerIfKind(SyntaxKind.AsExpression)\n ?.getExpressionIfKind(SyntaxKind.ObjectLiteralExpression) ??\n sourceFile\n .getVariableDeclaration(\"registry\")\n ?.getInitializerIfKind(SyntaxKind.ObjectLiteralExpression);\n\n if (!registry) {\n throw new Error(\"Unable to locate registry object, have you ran skullmaster init??\");\n }\n\n const existingComponents = new Set(\n registry\n .getProperties()\n .filter((property) => property.getKind() === SyntaxKind.PropertyAssignment)\n .map((property) => property.asKindOrThrow(SyntaxKind.PropertyAssignment))\n .map((property) => property.getName().replace(/['\"]/g, \"\")),\n );\n\n for (let component of operation.components) {\n component = toPascalCase(component);\n\n if (existingComponents.has(component)) {\n continue;\n }\n\n registry.addPropertyAssignment({\n name: `\"${component}\"`,\n initializer: `lazy(() => import(\"./skeletons/${component}\"))`,\n });\n }\n\n if (isTs) {\n const declaration = sourceFile.getVariableDeclarationOrThrow(\"registry\");\n\n const initializer = declaration.getInitializer();\n\n if (initializer && !initializer.isKind(SyntaxKind.AsExpression)) {\n declaration.setInitializer(`${initializer.getText()} as const`);\n }\n }\n\n sourceFile.formatText();\n\n await sourceFile.save();\n\n tsMorphProject.saveSync();\n}\n","import { readFile, writeFile } from \"node:fs/promises\";\nimport z from \"zod\";\nimport fileExists from \"./is-file-exists\";\nimport { fnv1a } from \"../utils/fnv1a\";\nimport { SkeletonCacheEntrySchema } from \"../shared\";\n\nexport type CacheOperation =\n | { type: \"replace\"; cacheEntry: z.infer<typeof SkeletonCacheEntrySchema> }\n | { type: \"delete\"; componentName: string }\n | {\n type: \"update\";\n componentName: string;\n payload: z.infer<typeof SkeletonCacheEntrySchema>[string];\n };\n\nexport async function updateCacheRegistry(operation: CacheOperation, outDir: string) {\n const cacheFilePath = outDir;\n let cacheEntries: z.infer<typeof SkeletonCacheEntrySchema> = {};\n if (!(await fileExists(cacheFilePath))) {\n await writeFile(cacheFilePath, JSON.stringify({}), \"utf8\");\n } else {\n cacheEntries = SkeletonCacheEntrySchema.parse(\n JSON.parse(await readFile(cacheFilePath, \"utf8\")),\n );\n }\n switch (operation.type) {\n case \"replace\":\n await writeFile(cacheFilePath, JSON.stringify(operation.cacheEntry), \"utf8\");\n break;\n case \"delete\":\n delete cacheEntries[operation.componentName];\n await writeFile(cacheFilePath, JSON.stringify(cacheEntries), \"utf8\");\n break;\n case \"update\":\n cacheEntries[operation.componentName] = {\n ...operation.payload,\n hash: fnv1a(operation.payload.html).toString(),\n };\n await writeFile(cacheFilePath, JSON.stringify(cacheEntries), \"utf8\");\n }\n}\n","import { writeFile } from \"node:fs/promises\";\nimport type { Preferences } from \"./collect-preferences\";\n\nexport const DEFAULT_BONE_CONTENT = (project: Preferences[\"project\"]): string => {\n switch (project) {\n case \"react-ts\":\n return `\n/* eslint-disable */\n/* oxlint-disable */\n/* biome-ignore-all lint */\n/* @ts-nocheck */\n\nimport type { HTMLProps } from \"react\";\n\n/**\n * Auto-generated by Skullmaster.\n *\n * This is the default fallback skeleton component displayed when a\n * matching skeleton implementation cannot be found in the registry.\n *\n * You may freely customize or replace this component to match the\n * loading experience of your application.\n */\ntype DefaultBoneProps = HTMLProps<HTMLDivElement>;\n\nexport default function DefaultBone(props: DefaultBoneProps) {\n return <div {...props}>loading...</div>;\n}\n`;\n case \"preact-ts\":\n return `\n/* eslint-disable */\n/* oxlint-disable */\n/* biome-ignore-all lint */\n/* @ts-nocheck */\n\nimport type { HTMLAttributes } from \"preact\";\n\n/**\n * Auto-generated by Skullmaster.\n *\n * This is the default fallback skeleton component displayed when a\n * matching skeleton implementation cannot be found in the registry.\n *\n * You may freely customize or replace this component to match the\n * loading experience of your application.\n */\ntype DefaultBoneProps = HTMLAttributes<HTMLDivElement>;\n\nexport default function DefaultBone(props: DefaultBoneProps) {\n return <div {...props}>loading...</div>;\n}\n`;\n case \"react-js\":\n case \"preact-js\":\n return `\n/* eslint-disable */\n/* oxlint-disable */\n/* biome-ignore-all lint */\n\nexport default function DefaultBone(props) {\n return <div {...props}>loading...</div>;\n}\n`;\n }\n};\n\nexport default async function defaultBone(target: string, project: Preferences[\"project\"]) {\n await writeFile(target, DEFAULT_BONE_CONTENT(project), \"utf8\");\n}\n","import { mkdirSync, readdirSync, rmSync, writeFileSync } from \"node:fs\";\nimport fileExists from \"./is-file-exists\";\nimport { generateInitialRegistry } from \"./registry\";\nimport { getExtension } from \"./registry/extension\";\nimport { generateRegistry, type RegistryOperation } from \"./registry/operations\";\nimport { updateCacheRegistry, type CacheOperation } from \"./cache-registry\";\nimport defaultBone from \"./default-bone\";\nimport { log } from \"../shared\";\nimport type { Preferences } from \"./collect-preferences\";\n\nexport class Config {\n outDir: string;\n projectType: Preferences[\"project\"];\n\n constructor(outDir: string, projectType: Preferences[\"project\"]) {\n this.outDir = outDir;\n this.projectType = projectType;\n }\n async initialize(forceReset?: boolean) {\n log.info(\"Initializing project structure...\");\n if (!(await fileExists(this.outDir))) {\n mkdirSync(this.outDir, { recursive: true });\n log.success(`Created output directory: ${this.outDir}`);\n } else {\n log.gray(`Output directory exists: ${this.outDir}`);\n }\n const skeletonsDirectoryPath = this.getSkeletonPath();\n if (!(await fileExists(skeletonsDirectoryPath))) {\n mkdirSync(skeletonsDirectoryPath, { recursive: true });\n log.success(`Created skeletons directory: ${skeletonsDirectoryPath}`);\n } else if (forceReset) {\n for (const file of readdirSync(skeletonsDirectoryPath)) {\n rmSync(`${skeletonsDirectoryPath}/${file}`, { recursive: true });\n }\n log.success(`Cleared skeletons directory: ${skeletonsDirectoryPath}`);\n } else {\n log.gray(`Skeletons directory exists: ${skeletonsDirectoryPath}`);\n }\n const registryFilePath = this.getRegistryPath();\n if (forceReset || !(await fileExists(registryFilePath))) {\n await generateInitialRegistry(this.outDir, this.projectType);\n log.success(`Created registry: ${registryFilePath}`);\n } else {\n log.gray(`Registry exists: ${registryFilePath}`);\n }\n const cachePath = this.getCachePath();\n if (forceReset || !(await fileExists(cachePath))) {\n writeFileSync(cachePath, JSON.stringify({}), \"utf8\");\n log.success(`Created cache: ${cachePath}`);\n } else {\n log.gray(`Cache exists: ${cachePath}`);\n }\n const defaultBonePath = this.getDefSkeletonPath();\n if (forceReset || !(await fileExists(defaultBonePath))) {\n await defaultBone(defaultBonePath, this.projectType);\n log.success(`Created default bone: ${defaultBonePath}`);\n } else {\n log.gray(`Default bone exists: ${defaultBonePath}`);\n }\n log.success(\"Initialization complete\");\n }\n async cache(op: CacheOperation) {\n return await updateCacheRegistry(op, this.getCachePath());\n }\n async registry(op: RegistryOperation) {\n return generateRegistry(op, this.projectType, this.getRegistryPath());\n }\n getCachePath() {\n return `${this.outDir}/cache.json`;\n }\n getSkeletonPath() {\n return `${this.outDir}/skeletons`;\n }\n getDefSkeletonPath() {\n return `${this.getSkeletonPath()}/DefaultBone.${this.getExt()}`;\n }\n getExt() {\n return getExtension(this.projectType);\n }\n getRegistryPath() {\n return `${this.outDir}/registry.${this.getExt()}`;\n }\n configJson() {\n return { projectType: this.projectType, outDir: this.outDir };\n }\n}\n","#!/usr/bin/env node\n\nimport { cac } from \"cac\";\nimport { cancel, isCancel, confirm } from \"@clack/prompts\";\nimport { serveCommand } from \"./commands/serve\";\nimport collectPreferences from \"./init/collect-preferences\";\nimport { Config } from \"./init/preferences\";\nimport { DEFAULT_PORT, log } from \"./shared\";\n\nconst cli = cac(\"💀\");\n\ncli\n .command(\"serve\", \"Start 💀 dev server\")\n .option(\"--port <port>\", \"Port\", {\n default: DEFAULT_PORT,\n })\n .action(async (options) => {\n const preferences = await collectPreferences();\n const config = new Config(preferences.outDir, preferences.project);\n await config.initialize();\n await serveCommand(config, Number(options.port));\n });\n\ncli.command(\"reset\", \"Reset Skullmaster to its initial state\").action(async () => {\n const proceed = await confirm({\n message:\n \"This will wipe out all present generated skeletons and reset the registry. Are you sure?\",\n });\n\n if (isCancel(proceed) || !proceed) {\n cancel(\"Reset cancelled.\");\n process.exit(0);\n }\n\n const preferences = await collectPreferences();\n const config = new Config(preferences.outDir, preferences.project);\n await config.initialize(true);\n log.success(\"Reset complete\");\n});\n\ncli.help();\ncli.parse();\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "skullmaster",
|
|
3
|
-
"version": "0.3.0-beta.
|
|
3
|
+
"version": "0.3.0-beta.1",
|
|
4
4
|
"private": false,
|
|
5
5
|
"homepage": "https://www.ajth.in/skullmaster/",
|
|
6
6
|
"bugs": {
|
|
@@ -49,8 +49,8 @@
|
|
|
49
49
|
"tsdown": "^0.22.0",
|
|
50
50
|
"typescript": "^6.0.3",
|
|
51
51
|
"@skullmaster/excarnate": "0.3.0-beta.0",
|
|
52
|
-
"@skullmaster/
|
|
53
|
-
"@skullmaster/
|
|
52
|
+
"@skullmaster/typescript-config": "0.0.0",
|
|
53
|
+
"@skullmaster/oxlint-config": "0.0.0"
|
|
54
54
|
},
|
|
55
55
|
"scripts": {
|
|
56
56
|
"build": "tsdown",
|