skullmaster 0.1.1 → 0.1.3
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.d.mts +1 -0
- package/dist/cli.mjs +433 -0
- package/dist/cli.mjs.map +1 -0
- package/dist/index.d.mts +5 -0
- package/dist/index.d.mts.map +1 -0
- package/dist/index.mjs +8 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +2 -3
package/dist/cli.d.mts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { };
|
package/dist/cli.mjs
ADDED
|
@@ -0,0 +1,433 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { cac } from "cac";
|
|
3
|
+
import { serve } from "@hono/node-server";
|
|
4
|
+
import { Hono } from "hono";
|
|
5
|
+
import { cors } from "hono/cors";
|
|
6
|
+
import { Project, QuoteKind, ScriptKind, SyntaxKind } from "ts-morph";
|
|
7
|
+
import { access, readFile, writeFile } from "node:fs/promises";
|
|
8
|
+
import z from "zod";
|
|
9
|
+
import { JSDOM } from "jsdom";
|
|
10
|
+
import pkg from "@babel/generator";
|
|
11
|
+
import htmlNodeToJsx from "@skullmaster/excarnate";
|
|
12
|
+
import { cancel, isCancel, select, text } from "@clack/prompts";
|
|
13
|
+
import { readFile as readFile$1, writeFile as writeFile$1 } from "fs/promises";
|
|
14
|
+
import { mkdirSync, writeFileSync } from "node:fs";
|
|
15
|
+
//#region src/shared/constants.ts
|
|
16
|
+
const DEFAULT_PORT = 8008;
|
|
17
|
+
//#endregion
|
|
18
|
+
//#region src/shared/schema.ts
|
|
19
|
+
const SkeletonPayloadInputSchema = z.record(z.string(), z.object({
|
|
20
|
+
component: z.string(),
|
|
21
|
+
html: z.string()
|
|
22
|
+
}));
|
|
23
|
+
const SkeletonCacheEntrySchema = z.record(z.string(), z.object({
|
|
24
|
+
component: z.string(),
|
|
25
|
+
html: z.string(),
|
|
26
|
+
hash: z.string()
|
|
27
|
+
}));
|
|
28
|
+
//#endregion
|
|
29
|
+
//#region src/shared/log.ts
|
|
30
|
+
const log = {
|
|
31
|
+
success: (message) => console.log(`\x1b[32m[💀] ${message}\x1b[0m`),
|
|
32
|
+
info: (message) => console.log(`\x1b[36m[💀] ${message}\x1b[0m`),
|
|
33
|
+
warn: (message) => console.log(`\x1b[33m[💀] ${message}\x1b[0m`),
|
|
34
|
+
error: (message) => console.log(`\x1b[31m[💀] ${message}\x1b[0m`),
|
|
35
|
+
gray: (message) => console.log(`\x1b[90m[💀] ${message}\x1b[0m`)
|
|
36
|
+
};
|
|
37
|
+
//#endregion
|
|
38
|
+
//#region src/cache/index.ts
|
|
39
|
+
var SkeletonCacheDB = class SkeletonCacheDB {
|
|
40
|
+
data = {};
|
|
41
|
+
config;
|
|
42
|
+
constructor(config) {
|
|
43
|
+
this.config = config;
|
|
44
|
+
}
|
|
45
|
+
static async create(config) {
|
|
46
|
+
const db = new SkeletonCacheDB(config);
|
|
47
|
+
await db.load();
|
|
48
|
+
return db;
|
|
49
|
+
}
|
|
50
|
+
async load() {
|
|
51
|
+
try {
|
|
52
|
+
const file = await readFile(this.config.getCachePath(), "utf8");
|
|
53
|
+
const parsed = JSON.parse(file);
|
|
54
|
+
this.data = SkeletonCacheEntrySchema.parse(parsed);
|
|
55
|
+
} catch {
|
|
56
|
+
this.data = {};
|
|
57
|
+
await this.config.cache({
|
|
58
|
+
type: "replace",
|
|
59
|
+
cacheEntry: {}
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
get(key) {
|
|
64
|
+
return this.data[key];
|
|
65
|
+
}
|
|
66
|
+
getComponentNames() {
|
|
67
|
+
return Object.values(this.data).map((entry) => entry.component);
|
|
68
|
+
}
|
|
69
|
+
async set(key, value) {
|
|
70
|
+
this.data[key] = value;
|
|
71
|
+
this.config.cache({
|
|
72
|
+
type: "update",
|
|
73
|
+
componentName: key,
|
|
74
|
+
payload: value
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
//#endregion
|
|
79
|
+
//#region src/generate-target/index.ts
|
|
80
|
+
function generateTarget({ project, filePath, componentName, body }) {
|
|
81
|
+
project.manipulationSettings.set({ quoteKind: QuoteKind.Double });
|
|
82
|
+
const file = project.createSourceFile(filePath, "", {
|
|
83
|
+
overwrite: true,
|
|
84
|
+
scriptKind: ScriptKind.TSX
|
|
85
|
+
});
|
|
86
|
+
file.insertText(0, `/* eslint-disable */
|
|
87
|
+
/* prettier-ignore-start */
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Auto-generated by Skullmaster.
|
|
91
|
+
*
|
|
92
|
+
* DO NOT EDIT THIS FILE MANUALLY.
|
|
93
|
+
* Changes may be overwritten on the next generation.
|
|
94
|
+
*/
|
|
95
|
+
|
|
96
|
+
`);
|
|
97
|
+
file.addFunction({
|
|
98
|
+
name: componentName,
|
|
99
|
+
isDefaultExport: true,
|
|
100
|
+
statements: [`return (${body});`]
|
|
101
|
+
});
|
|
102
|
+
file.addStatements(`
|
|
103
|
+
/* prettier-ignore-end */
|
|
104
|
+
`);
|
|
105
|
+
}
|
|
106
|
+
//#endregion
|
|
107
|
+
//#region src/transform/index.ts
|
|
108
|
+
const generate = pkg.default;
|
|
109
|
+
function transformInput(html) {
|
|
110
|
+
const root = new JSDOM(html).window.document.body.firstElementChild;
|
|
111
|
+
if (!root) throw new Error("No root element found");
|
|
112
|
+
const jsxAst = htmlNodeToJsx(root, 0);
|
|
113
|
+
if (!jsxAst) throw new Error("Failed to generate JSX AST");
|
|
114
|
+
return generate(jsxAst, { jsescOption: { minimal: true } }).code;
|
|
115
|
+
}
|
|
116
|
+
//#endregion
|
|
117
|
+
//#region src/utils/to-pascal-case.ts
|
|
118
|
+
function toPascalCase(input) {
|
|
119
|
+
return input.trim().replace(/['"]/g, "").split(/[^a-zA-Z0-9]+/).filter(Boolean).map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join("");
|
|
120
|
+
}
|
|
121
|
+
//#endregion
|
|
122
|
+
//#region src/utils/fnv1a.ts
|
|
123
|
+
function fnv1a(str) {
|
|
124
|
+
let hash = 2166136261;
|
|
125
|
+
for (let i = 0; i < str.length; i++) {
|
|
126
|
+
hash ^= str.charCodeAt(i);
|
|
127
|
+
hash = Math.imul(hash, 16777619);
|
|
128
|
+
}
|
|
129
|
+
return hash >>> 0;
|
|
130
|
+
}
|
|
131
|
+
//#endregion
|
|
132
|
+
//#region src/commands/serve.ts
|
|
133
|
+
async function serveCommand(config, port) {
|
|
134
|
+
const app = new Hono();
|
|
135
|
+
app.use("*", cors({
|
|
136
|
+
origin: "*",
|
|
137
|
+
allowMethods: [
|
|
138
|
+
"GET",
|
|
139
|
+
"POST",
|
|
140
|
+
"OPTIONS"
|
|
141
|
+
],
|
|
142
|
+
allowHeaders: ["Content-Type", "Authorization"]
|
|
143
|
+
}));
|
|
144
|
+
const db = await SkeletonCacheDB.create(config);
|
|
145
|
+
app.get("/health", (c) => {
|
|
146
|
+
return c.json({ ok: true });
|
|
147
|
+
});
|
|
148
|
+
app.post("/skeletons", async (c) => {
|
|
149
|
+
const body = await c.req.json();
|
|
150
|
+
const result = SkeletonPayloadInputSchema.parse(body);
|
|
151
|
+
const project = new Project();
|
|
152
|
+
const entries = Object.entries(result).map(async ([key, value]) => {
|
|
153
|
+
const componentName = toPascalCase(value.component);
|
|
154
|
+
const transformedHtml = transformInput(value.html);
|
|
155
|
+
const hash = fnv1a(transformedHtml).toString();
|
|
156
|
+
const cached = db.get(key);
|
|
157
|
+
if (cached && cached.hash === hash) return;
|
|
158
|
+
generateTarget({
|
|
159
|
+
project,
|
|
160
|
+
filePath: `${config.getSkeletonPath()}/${componentName}.${config.getExt()}`,
|
|
161
|
+
componentName,
|
|
162
|
+
body: transformedHtml
|
|
163
|
+
});
|
|
164
|
+
await db.set(key, {
|
|
165
|
+
component: value.component,
|
|
166
|
+
html: transformedHtml,
|
|
167
|
+
hash
|
|
168
|
+
});
|
|
169
|
+
});
|
|
170
|
+
await Promise.all(entries);
|
|
171
|
+
config.registry({
|
|
172
|
+
type: "add",
|
|
173
|
+
components: db.getComponentNames()
|
|
174
|
+
});
|
|
175
|
+
await project.save();
|
|
176
|
+
return c.json({ sucess: true });
|
|
177
|
+
});
|
|
178
|
+
serve({
|
|
179
|
+
fetch: app.fetch,
|
|
180
|
+
port
|
|
181
|
+
}, (info) => {
|
|
182
|
+
log.info(`Server running at http://localhost:${info.port}`);
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
//#endregion
|
|
186
|
+
//#region src/init/is-file-exists.ts
|
|
187
|
+
async function fileExists(path) {
|
|
188
|
+
try {
|
|
189
|
+
await access(path);
|
|
190
|
+
return true;
|
|
191
|
+
} catch {
|
|
192
|
+
return false;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
//#endregion
|
|
196
|
+
//#region src/constants.ts
|
|
197
|
+
const CONFIG_PATH = "skullmaster.config.json";
|
|
198
|
+
//#endregion
|
|
199
|
+
//#region src/init/collect-preferences.ts
|
|
200
|
+
async function collectPreferences() {
|
|
201
|
+
if (await fileExists("skullmaster.config.json")) return JSON.parse(await readFile$1(`./${CONFIG_PATH}`, "utf-8"));
|
|
202
|
+
const outDir = await text({
|
|
203
|
+
message: "Where do you want to output the generated files?",
|
|
204
|
+
placeholder: "src/skeletons",
|
|
205
|
+
initialValue: "src/skeletons",
|
|
206
|
+
validate(value) {
|
|
207
|
+
if (value?.length === 0) return `Value is required!`;
|
|
208
|
+
}
|
|
209
|
+
});
|
|
210
|
+
if (isCancel(outDir)) {
|
|
211
|
+
cancel("Operation cancelled.");
|
|
212
|
+
process.exit(0);
|
|
213
|
+
}
|
|
214
|
+
const projectType = await select({
|
|
215
|
+
message: "Pick a project type.",
|
|
216
|
+
initialValue: "react-ts",
|
|
217
|
+
options: [{
|
|
218
|
+
value: "react-ts",
|
|
219
|
+
label: "React with TypeScript"
|
|
220
|
+
}, {
|
|
221
|
+
value: "react-js",
|
|
222
|
+
label: "React"
|
|
223
|
+
}]
|
|
224
|
+
});
|
|
225
|
+
if (isCancel(projectType)) {
|
|
226
|
+
cancel("Operation cancelled.");
|
|
227
|
+
process.exit(0);
|
|
228
|
+
}
|
|
229
|
+
const preferences = {
|
|
230
|
+
outDir,
|
|
231
|
+
project: projectType.toString()
|
|
232
|
+
};
|
|
233
|
+
await writeFile$1(`./${CONFIG_PATH}`, JSON.stringify(preferences, null, 2), "utf-8");
|
|
234
|
+
return preferences;
|
|
235
|
+
}
|
|
236
|
+
//#endregion
|
|
237
|
+
//#region src/init/ensure-lazy-imports.ts
|
|
238
|
+
function ensureLazyImport(sourceFile) {
|
|
239
|
+
const reactImport = sourceFile.getImportDeclaration((d) => d.getModuleSpecifierValue() === "react");
|
|
240
|
+
if (!reactImport) {
|
|
241
|
+
sourceFile.addImportDeclaration({
|
|
242
|
+
moduleSpecifier: "react",
|
|
243
|
+
namedImports: ["lazy"]
|
|
244
|
+
});
|
|
245
|
+
return;
|
|
246
|
+
}
|
|
247
|
+
if (!reactImport.getNamedImports().some((i) => i.getName() === "lazy")) reactImport.addNamedImport("lazy");
|
|
248
|
+
}
|
|
249
|
+
//#endregion
|
|
250
|
+
//#region src/init/registry.ts
|
|
251
|
+
async function generateInitialRegistry(outDir, projectType) {
|
|
252
|
+
const isTs = projectType.endsWith("ts");
|
|
253
|
+
const ext = isTs ? "tsx" : "jsx";
|
|
254
|
+
const skeletonPropsType = isTs ? `
|
|
255
|
+
type SkeletonProps = {
|
|
256
|
+
name: string;
|
|
257
|
+
};
|
|
258
|
+
` : "";
|
|
259
|
+
await writeFile(`${outDir}/registry.${ext}`, `
|
|
260
|
+
/* eslint-disable */
|
|
261
|
+
/* oxlint-disable */
|
|
262
|
+
/* biome-ignore-all lint */
|
|
263
|
+
/* @ts-nocheck */
|
|
264
|
+
|
|
265
|
+
/**
|
|
266
|
+
* Auto-generated by Skullmaster.
|
|
267
|
+
*
|
|
268
|
+
* Do not edit this file manually.
|
|
269
|
+
* Use Skullmaster commands to add, update, or remove skeletons.
|
|
270
|
+
*
|
|
271
|
+
* To remove unused skeletons:
|
|
272
|
+
* pnpm skeleton prune
|
|
273
|
+
*/
|
|
274
|
+
|
|
275
|
+
|
|
276
|
+
import DefaultBone from "./skeletons/DefaultBone";
|
|
277
|
+
|
|
278
|
+
const registry${isTs ? ": Record<string, any>" : ""} = {};
|
|
279
|
+
|
|
280
|
+
${skeletonPropsType}
|
|
281
|
+
|
|
282
|
+
export default function Skeleton({
|
|
283
|
+
name,
|
|
284
|
+
}${isTs ? ": SkeletonProps" : ""}) {
|
|
285
|
+
const Component = registry[name];
|
|
286
|
+
|
|
287
|
+
if (!Component) {
|
|
288
|
+
return <DefaultBone />;
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
return <Component />;
|
|
292
|
+
}
|
|
293
|
+
`, "utf8");
|
|
294
|
+
}
|
|
295
|
+
async function generateRegistry(operation, isTs, registryPath) {
|
|
296
|
+
let project;
|
|
297
|
+
if (isTs) project = new Project({ tsConfigFilePath: "tsconfig.json" });
|
|
298
|
+
else project = new Project();
|
|
299
|
+
const sourceFile = project.addSourceFileAtPath(registryPath);
|
|
300
|
+
ensureLazyImport(sourceFile);
|
|
301
|
+
const registry = sourceFile.getVariableDeclaration("registry")?.getInitializerIfKind(SyntaxKind.ObjectLiteralExpression);
|
|
302
|
+
if (!registry) throw new Error("Unable to locate registry object, have you ran skullmaster init??");
|
|
303
|
+
const existingComponents = new Set(registry.getProperties().filter((property) => property.getKind() === SyntaxKind.PropertyAssignment).map((property) => property.asKindOrThrow(SyntaxKind.PropertyAssignment)).map((property) => property.getName().replace(/['"]/g, "")));
|
|
304
|
+
for (const component of operation.components) {
|
|
305
|
+
if (existingComponents.has(component)) continue;
|
|
306
|
+
registry.addPropertyAssignment({
|
|
307
|
+
name: `"${component}"`,
|
|
308
|
+
initializer: `lazy(() => import("./skeletons/${component}"))`
|
|
309
|
+
});
|
|
310
|
+
}
|
|
311
|
+
sourceFile.formatText();
|
|
312
|
+
await sourceFile.save();
|
|
313
|
+
project.saveSync();
|
|
314
|
+
}
|
|
315
|
+
//#endregion
|
|
316
|
+
//#region src/init/cache-registry.ts
|
|
317
|
+
async function updateCacheRegistry(operation, outDir) {
|
|
318
|
+
const cacheFilePath = outDir;
|
|
319
|
+
let cacheEntries = {};
|
|
320
|
+
if (!await fileExists(cacheFilePath)) await writeFile(cacheFilePath, JSON.stringify({}), "utf8");
|
|
321
|
+
else cacheEntries = SkeletonCacheEntrySchema.parse(JSON.parse(await readFile(cacheFilePath, "utf8")));
|
|
322
|
+
switch (operation.type) {
|
|
323
|
+
case "replace":
|
|
324
|
+
await writeFile(cacheFilePath, JSON.stringify(operation.cacheEntry), "utf8");
|
|
325
|
+
break;
|
|
326
|
+
case "delete":
|
|
327
|
+
delete cacheEntries[operation.componentName];
|
|
328
|
+
await writeFile(cacheFilePath, JSON.stringify(cacheEntries), "utf8");
|
|
329
|
+
break;
|
|
330
|
+
case "update":
|
|
331
|
+
cacheEntries[operation.componentName] = {
|
|
332
|
+
...operation.payload,
|
|
333
|
+
hash: fnv1a(operation.payload.html).toString()
|
|
334
|
+
};
|
|
335
|
+
await writeFile(cacheFilePath, JSON.stringify(cacheEntries), "utf8");
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
//#endregion
|
|
339
|
+
//#region src/init/default-bone.ts
|
|
340
|
+
async function defaultBone(target) {
|
|
341
|
+
await writeFile(target, `/* eslint-disable */
|
|
342
|
+
/* oxlint-disable */
|
|
343
|
+
/* biome-ignore-all lint */
|
|
344
|
+
/* @ts-nocheck */
|
|
345
|
+
|
|
346
|
+
/**
|
|
347
|
+
* Auto-generated by Skullmaster.
|
|
348
|
+
*
|
|
349
|
+
* This is the default fallback skeleton component displayed when a
|
|
350
|
+
* matching skeleton implementation cannot be found in the registry.
|
|
351
|
+
*
|
|
352
|
+
* You may freely customize or replace this component to match the
|
|
353
|
+
* loading experience of your application.
|
|
354
|
+
*/
|
|
355
|
+
export default function DefaultBone() {
|
|
356
|
+
return <div>loading...</div>;
|
|
357
|
+
}
|
|
358
|
+
`, "utf8");
|
|
359
|
+
}
|
|
360
|
+
//#endregion
|
|
361
|
+
//#region src/init/preferences.ts
|
|
362
|
+
var Config = class {
|
|
363
|
+
outDir;
|
|
364
|
+
projectType;
|
|
365
|
+
constructor(outDir, projectType) {
|
|
366
|
+
this.outDir = outDir;
|
|
367
|
+
this.projectType = projectType;
|
|
368
|
+
}
|
|
369
|
+
async initialize() {
|
|
370
|
+
log.info("Initializing project structure...");
|
|
371
|
+
if (!await fileExists(this.outDir)) {
|
|
372
|
+
mkdirSync(this.outDir, { recursive: true });
|
|
373
|
+
log.success(`Created output directory: ${this.outDir}`);
|
|
374
|
+
} else log.gray(`Output directory exists: ${this.outDir}`);
|
|
375
|
+
const skeletonsDirectoryPath = this.getSkeletonPath();
|
|
376
|
+
if (!await fileExists(skeletonsDirectoryPath)) {
|
|
377
|
+
mkdirSync(skeletonsDirectoryPath, { recursive: true });
|
|
378
|
+
log.success(`Created skeletons directory: ${skeletonsDirectoryPath}`);
|
|
379
|
+
} else log.gray(`Skeletons directory exists: ${skeletonsDirectoryPath}`);
|
|
380
|
+
const registryFilePath = this.getRegistryPath();
|
|
381
|
+
if (!await fileExists(registryFilePath)) {
|
|
382
|
+
await generateInitialRegistry(this.outDir, this.projectType);
|
|
383
|
+
log.success(`Created registry: ${registryFilePath}`);
|
|
384
|
+
} else log.gray(`Registry exists: ${registryFilePath}`);
|
|
385
|
+
const cachePath = this.getCachePath();
|
|
386
|
+
if (!await fileExists(cachePath)) {
|
|
387
|
+
writeFileSync(cachePath, JSON.stringify({}), "utf8");
|
|
388
|
+
log.success(`Created cache: ${cachePath}`);
|
|
389
|
+
} else log.gray(`Cache exists: ${cachePath}`);
|
|
390
|
+
const defaultBonePath = this.getDefSkeletonPath();
|
|
391
|
+
if (!await fileExists(defaultBonePath)) {
|
|
392
|
+
await defaultBone(defaultBonePath);
|
|
393
|
+
log.success(`Created default bone: ${defaultBonePath}`);
|
|
394
|
+
} else log.gray(`Default bone exists: ${defaultBonePath}`);
|
|
395
|
+
log.success("Initialization complete");
|
|
396
|
+
}
|
|
397
|
+
async cache(op) {
|
|
398
|
+
return await updateCacheRegistry(op, this.getCachePath());
|
|
399
|
+
}
|
|
400
|
+
async registry(op) {
|
|
401
|
+
return generateRegistry(op, this.projectType.endsWith("ts"), this.getRegistryPath());
|
|
402
|
+
}
|
|
403
|
+
getCachePath() {
|
|
404
|
+
return `${this.outDir}/cache.json`;
|
|
405
|
+
}
|
|
406
|
+
getSkeletonPath() {
|
|
407
|
+
return `${this.outDir}/skeletons`;
|
|
408
|
+
}
|
|
409
|
+
getDefSkeletonPath() {
|
|
410
|
+
return `${this.getSkeletonPath()}/DefaultBone.${this.getExt()}`;
|
|
411
|
+
}
|
|
412
|
+
getExt() {
|
|
413
|
+
return this.projectType.endsWith("ts") ? "tsx" : "jsx";
|
|
414
|
+
}
|
|
415
|
+
getRegistryPath() {
|
|
416
|
+
return `${this.outDir}/registry.${this.getExt()}`;
|
|
417
|
+
}
|
|
418
|
+
};
|
|
419
|
+
//#endregion
|
|
420
|
+
//#region src/cli.ts
|
|
421
|
+
const cli = cac("💀");
|
|
422
|
+
cli.command("serve", "Start 💀 dev server").option("--port <port>", "Port", { default: DEFAULT_PORT }).action(async (options) => {
|
|
423
|
+
const preferences = await collectPreferences();
|
|
424
|
+
const config = new Config(preferences.outDir, preferences.project);
|
|
425
|
+
await config.initialize();
|
|
426
|
+
await serveCommand(config, Number(options.port));
|
|
427
|
+
});
|
|
428
|
+
cli.help();
|
|
429
|
+
cli.parse();
|
|
430
|
+
//#endregion
|
|
431
|
+
export {};
|
|
432
|
+
|
|
433
|
+
//# sourceMappingURL=cli.mjs.map
|
package/dist/cli.mjs.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
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/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 { 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 });\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\";\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 skeletonPropsType = isTs\n ? `\ntype SkeletonProps = {\n name: string;\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 * To remove unused skeletons:\n * pnpm skeleton prune\n */\n\n\nimport DefaultBone from \"./skeletons/DefaultBone\";\n\nconst registry${isTs ? \": Record<string, any>\" : \"\"} = {};\n\n${skeletonPropsType}\n\nexport default function Skeleton({\n name,\n}${isTs ? \": SkeletonProps\" : \"\"}) {\n const Component = registry[name];\n\n if (!Component) {\n return <DefaultBone />;\n }\n\n return <Component />;\n}\n`,\n \"utf8\",\n );\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 let project: Project;\n if (isTs) {\n project = new Project({\n tsConfigFilePath: \"tsconfig.json\",\n });\n } else {\n project = new Project();\n }\n\n const sourceFile = project.addSourceFileAtPath(registryPath);\n\n ensureLazyImport(sourceFile);\n\n const registry = 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 (const component of operation.components) {\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 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 `/* eslint-disable */\n/* oxlint-disable */\n/* biome-ignore-all lint */\n/* @ts-nocheck */\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 */\nexport default function DefaultBone() {\n return <div>loading...</div>;\n}\n`,\n \"utf8\",\n );\n}\n","import { mkdirSync, 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() {\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 {\n log.gray(`Skeletons directory exists: ${skeletonsDirectoryPath}`);\n }\n const registryFilePath = this.getRegistryPath();\n if (!(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 (!(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 (!(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}\n","#!/usr/bin/env node\n\nimport { cac } from \"cac\";\nimport { serveCommand } from \"./commands/serve\";\nimport collectPreferences from \"./init/collect-preferences\";\nimport { Config } from \"./init/preferences\";\nimport { DEFAULT_PORT } 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.help();\ncli.parse();\n"],"mappings":"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"}
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/index.ts"],"mappings":";iBAAgB,EAAA,CAAA"}
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.mjs","names":[],"sources":["../src/index.ts"],"sourcesContent":["export function fn() {\n return \"Hello, tsdown!\";\n}\n"],"mappings":";AAAA,SAAgB,KAAK;CACnB,OAAO;AACT"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "skullmaster",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.3",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "A simple example library built by tsdown",
|
|
6
6
|
"repository": {
|
|
@@ -38,8 +38,7 @@
|
|
|
38
38
|
"oxfmt": "^0.52.0",
|
|
39
39
|
"ts-morph": "^28.0.0",
|
|
40
40
|
"zod": "^4.4.3",
|
|
41
|
-
"@skullmaster/excarnate": "0.1.
|
|
42
|
-
"@skullmaster/shared": "0.2.1"
|
|
41
|
+
"@skullmaster/excarnate": "0.1.2"
|
|
43
42
|
},
|
|
44
43
|
"devDependencies": {
|
|
45
44
|
"@types/babel__generator": "^7.27.0",
|