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 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 * as t from "@babel/types";
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 = excarnate(root, 0);
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-ts",
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/ensure-lazy-imports.ts
724
- function ensureLazyImport(sourceFile) {
725
- const reactImport = sourceFile.getImportDeclaration((d) => d.getModuleSpecifierValue() === "react");
726
- if (!reactImport) {
727
- sourceFile.addImportDeclaration({
728
- moduleSpecifier: "react",
729
- namedImports: ["lazy"]
730
- });
731
- return;
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
- if (!reactImport.getNamedImports().some((i) => i.getName() === "lazy")) reactImport.addNamedImport("lazy");
734
- }
281
+ };
735
282
  //#endregion
736
- //#region src/init/registry.ts
737
- async function generateInitialRegistry(outDir, projectType) {
738
- const isTs = projectType.endsWith("ts");
739
- const ext = isTs ? "tsx" : "jsx";
740
- const skullTypes = isTs ? `
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
- const skullUtils = `
755
- const buildSkullAttributes = ({ hideSubTree, isTransparent }${isTs ? ": SkullTweaks" : ""})${isTs ? ": Omit<WithDataSkull, \"data-skullmaster\">" : ""} => {
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${isTs ? ": SkullTweaks" : ""} = {})${isTs ? ": WithDataSkull" : ""} => {
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${isTs ? ": SkullTweaks" : ""} = {})${isTs ? ": Omit<WithDataSkull, \"data-skullmaster\">" : ""} => {
371
+ export const tweakForSkull = (tweaks: SkullTweaks = {}): Omit<WithDataSkull, "data-skullmaster"> => {
770
372
  return buildSkullAttributes(tweaks);
771
373
  };
772
374
  `;
773
- const skeletonPropsType = isTs ? `
774
- type SkeletonProps = {
775
- name: keyof typeof registry | (string & {});
776
- defaultBoneProps?: ComponentProps<typeof DefaultBone>;
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
- * Auto-generated by Skullmaster.
787
- *
788
- * Do not edit this file manually.
789
- * Use Skullmaster commands to add, update, or remove skeletons.
790
- *
791
- */
383
+ export const markAsSkull = (name: string, tweaks = {}) => {
384
+ return {
385
+ "data-skullmaster": name,
386
+ ...buildSkullAttributes(tweaks),
387
+ };
388
+ };
792
389
 
793
- import "@skullmaster/react/style.css";
794
- import DefaultBone from "./skeletons/DefaultBone";
795
- ${isTs ? "import { type ComponentProps, type HTMLAttributes, lazy } from \"react\";" : ""}
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
- const registry = {default: lazy(() => import("./skeletons/DefaultBone"))}${isTs ? " as const" : ""};
410
+ if (!Component) {
411
+ return <DefaultBone {...defaultBoneProps} />;
412
+ }
798
413
 
799
- ${skullTypes}${skeletonPropsType}${skullUtils}
800
- export default function Skeleton({
414
+ return <Component />;
415
+ }
416
+ `;
417
+ const JSX_SKELETON_JS = `export default function Skeleton({
801
418
  name,
802
419
  defaultBoneProps = {},
803
- }${isTs ? ": SkeletonProps" : ""}) {
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
- `, "utf8");
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
- async function generateRegistry(operation, isTs, registryPath) {
815
- const project = isTs ? new Project({ tsConfigFilePath: "tsconfig.json" }) : new Project();
816
- const sourceFile = project.addSourceFileAtPath(registryPath);
817
- ensureLazyImport(sourceFile);
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
- project.saveSync();
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
- async function defaultBone(target) {
864
- await writeFile(target, `
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
- `, "utf8");
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.endsWith("ts"), this.getRegistryPath());
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.endsWith("ts") ? "tsx" : "jsx";
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.0",
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/oxlint-config": "0.0.0",
53
- "@skullmaster/typescript-config": "0.0.0"
52
+ "@skullmaster/typescript-config": "0.0.0",
53
+ "@skullmaster/oxlint-config": "0.0.0"
54
54
  },
55
55
  "scripts": {
56
56
  "build": "tsdown",