-
-
Notifications
You must be signed in to change notification settings - Fork 834
Expand file tree
/
Copy pathgen-presets.ts
More file actions
105 lines (95 loc) · 3.32 KB
/
gen-presets.ts
File metadata and controls
105 lines (95 loc) · 3.32 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
import { existsSync, readFileSync, readdirSync, writeFileSync } from "node:fs";
import { resolve } from "node:path";
import { fileURLToPath, pathToFileURL } from "node:url";
import { consola } from "consola";
import { findTypeExports } from "mlly";
import type { NitroPreset, NitroPresetMeta } from "nitro/types";
import { camelCase, kebabCase, pascalCase, snakeCase } from "scule";
const autoGenHeader = /* ts */ `// Auto-generated using gen-presets script\n`;
// --- Scan presets/ directory ---
const presetsDir = fileURLToPath(new URL("../src/presets", import.meta.url));
const presetDirs: string[] = readdirSync(presetsDir, { withFileTypes: true })
.filter(
(dir) =>
dir.name !== "_utils" &&
dir.isDirectory() &&
existsSync(resolve(presetsDir, dir.name, "preset.ts"))
)
.map((dir) => dir.name);
// --- Load presets ---
const allPresets: (NitroPreset & { _meta?: NitroPresetMeta })[] = [];
for (const preset of presetDirs) {
const presetPath = resolve(presetsDir, preset, "preset.ts");
const _presets = await import(pathToFileURL(presetPath).href).then(
(mod) => (mod as any).default || mod
);
if (!Array.isArray(_presets)) {
throw new TypeError(`Preset ${preset} does not export an array`);
}
allPresets.push(..._presets);
}
// --- Validate names ---
const _names = new Set<string>();
for (const preset of allPresets) {
if (!preset._meta?.name) {
consola.warn(`Preset ${preset} does not have a name`);
continue;
}
const names = [preset._meta.name, ...(preset._meta.aliases || [])];
for (const name of names) {
if (_names.has(name)) {
if (!preset._meta.compatibilityDate && !preset._meta.dev) {
consola.warn(`Preset ${name} is duplicated`);
}
continue;
}
if (kebabCase(name) !== name) {
consola.warn(`Preset ${name} is not kebab-case`);
}
_names.add(name);
}
}
const names = [..._names].sort();
consola.log(names.join(", "));
// --- Generate presets/_all.gen.ts ---
writeFileSync(
resolve(presetsDir, "_all.gen.ts"),
/* ts */ `${autoGenHeader}
${presetDirs
.map((preset) => `import _${camelCase(preset)} from "./${preset}/preset.ts";`)
.join("\n")}
export default [
${presetDirs.map((preset) => ` ..._${camelCase(preset)},`).join("\n")}
] as const;
`
);
// --- Generate presets/_types.gen.ts ---
const presetsWithType = presetDirs.filter((presetDir) => {
const presetPath = resolve(presetsDir, presetDir, "preset.ts");
const content = readFileSync(presetPath, "utf8");
const typeExports = findTypeExports(content);
return typeExports.some((type) => type.name === "PresetOptions");
});
writeFileSync(
resolve(presetsDir, "_types.gen.ts"),
/* ts */ `${autoGenHeader}
${presetsWithType
.map(
(preset) =>
`import type { PresetOptions as ${pascalCase(preset)}Options } from "./${preset}/preset.ts";`
)
.join("\n")}
export interface PresetOptions {
${presetsWithType
.map((preset) => ` ${camelCase(preset)}?: ${pascalCase(preset)}Options;`)
.join("\n")}
}
export const presetsWithConfig = ${JSON.stringify(presetsWithType.map((p) => camelCase(p)))} as const;
export type PresetName = ${names.map((name) => `"${name}"`).join(" | ")};
export type PresetNameInput = ${names
.flatMap((name) =>
[...new Set([kebabCase(name), camelCase(name), snakeCase(name)])].map((n) => `"${n}"`)
)
.join(" | ")} | (string & {});
`
);