sekkei-preview 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
package/dist/cli.js ADDED
@@ -0,0 +1,116 @@
1
+ #!/usr/bin/env node
2
+ import { parseArgs } from 'node:util';
3
+ import { spawn } from 'node:child_process';
4
+ import { existsSync, symlinkSync } from 'node:fs';
5
+ import { resolve, dirname, join } from 'node:path';
6
+ import { fileURLToPath } from 'node:url';
7
+ import { resolveDocsDir } from './resolve-docs-dir.js';
8
+ import { generateIndexIfMissing } from './generate-index.js';
9
+ import { generateVitePressConfig } from './generate-config.js';
10
+ const __dirname = dirname(fileURLToPath(import.meta.url));
11
+ const packageDir = resolve(__dirname, '..');
12
+ function printUsage() {
13
+ console.log(`
14
+ Usage: sekkei-preview [command] [options]
15
+
16
+ Commands:
17
+ dev Start dev server with hot-reload (default)
18
+ build Build static site
19
+ serve Serve built static site
20
+
21
+ Options:
22
+ --docs <path> Docs directory (default: auto-resolve)
23
+ --port <N> Dev server port (default: 5173)
24
+ --edit Enable WYSIWYG editing mode
25
+ --help Show this help
26
+ `);
27
+ }
28
+ function main() {
29
+ const { values, positionals } = parseArgs({
30
+ args: process.argv.slice(2),
31
+ options: {
32
+ docs: { type: 'string' },
33
+ port: { type: 'string' },
34
+ edit: { type: 'boolean', default: false },
35
+ help: { type: 'boolean', default: false },
36
+ },
37
+ allowPositionals: true,
38
+ strict: false,
39
+ });
40
+ if (values.help) {
41
+ printUsage();
42
+ process.exit(0);
43
+ }
44
+ const command = positionals[0] ?? 'dev';
45
+ if (!['dev', 'build', 'serve'].includes(command)) {
46
+ console.error(`Unknown command: ${command}`);
47
+ printUsage();
48
+ process.exit(1);
49
+ }
50
+ const port = values.port ? parseInt(values.port, 10) : 5173;
51
+ if (isNaN(port) || port < 1 || port > 65535) {
52
+ console.error('Error: --port must be a number between 1 and 65535');
53
+ process.exit(1);
54
+ }
55
+ const edit = values.edit;
56
+ // Resolve docs directory
57
+ let docsDir;
58
+ try {
59
+ docsDir = resolveDocsDir(values.docs);
60
+ }
61
+ catch (err) {
62
+ console.error(`Error: ${err.message}`);
63
+ process.exit(1);
64
+ }
65
+ console.log(`Docs directory: ${docsDir}`);
66
+ // Generate index.md if missing
67
+ generateIndexIfMissing(docsDir);
68
+ // Generate VitePress config
69
+ generateVitePressConfig(docsDir, packageDir, {
70
+ edit,
71
+ port,
72
+ });
73
+ console.log(`VitePress config generated at ${docsDir}/.vitepress/config.mts`);
74
+ if (edit) {
75
+ console.log('Edit mode enabled — WYSIWYG editor available');
76
+ }
77
+ // Symlink package's node_modules into docs dir so VitePress can resolve deps
78
+ const pkgNodeModules = resolve(packageDir, 'node_modules');
79
+ const docsNodeModules = join(docsDir, 'node_modules');
80
+ if (!existsSync(docsNodeModules)) {
81
+ symlinkSync(pkgNodeModules, docsNodeModules, 'junction');
82
+ }
83
+ const env = { ...process.env };
84
+ if (edit) {
85
+ env.SEKKEI_EDIT = '1';
86
+ }
87
+ // Build VitePress args — run from docs dir (no srcDir argument needed)
88
+ const vpArgs = [command];
89
+ if (command === 'dev') {
90
+ vpArgs.push('--port', String(port));
91
+ }
92
+ // Resolve VitePress binary
93
+ const vitepressBin = resolve(packageDir, 'node_modules', '.bin', 'vitepress');
94
+ // Spawn VitePress process with CWD = docsDir
95
+ const child = spawn(vitepressBin, vpArgs, {
96
+ stdio: 'inherit',
97
+ env,
98
+ cwd: docsDir,
99
+ });
100
+ child.on('error', (err) => {
101
+ console.error(`Failed to start VitePress: ${err.message}`);
102
+ process.exit(1);
103
+ });
104
+ child.on('close', (code) => {
105
+ process.exit(code ?? 0);
106
+ });
107
+ // Forward SIGINT/SIGTERM to child
108
+ const signals = ['SIGINT', 'SIGTERM'];
109
+ for (const sig of signals) {
110
+ process.on(sig, () => {
111
+ child.kill(sig);
112
+ });
113
+ }
114
+ }
115
+ main();
116
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,22 @@
1
+ export interface ConfigOptions {
2
+ edit: boolean;
3
+ port: number;
4
+ title?: string;
5
+ }
6
+ interface SidebarItem {
7
+ text: string;
8
+ link?: string;
9
+ collapsed?: boolean;
10
+ items?: SidebarItem[];
11
+ }
12
+ /**
13
+ * Build sidebar from docs directory structure.
14
+ * Sorts by numbered prefix (01-, 02-, etc.).
15
+ * Directories become collapsible groups.
16
+ */
17
+ export declare function buildSidebar(docsDir: string, basePath?: string): SidebarItem[];
18
+ /**
19
+ * Generate VitePress config.mts content and write to docsDir/.vitepress/.
20
+ */
21
+ export declare function generateVitePressConfig(docsDir: string, packageDir: string, options: ConfigOptions): void;
22
+ export {};
@@ -0,0 +1,138 @@
1
+ import { existsSync, mkdirSync, readFileSync, readdirSync, writeFileSync } from 'node:fs';
2
+ import { join, resolve, basename, extname } from 'node:path';
3
+ /**
4
+ * Build sidebar from docs directory structure.
5
+ * Sorts by numbered prefix (01-, 02-, etc.).
6
+ * Directories become collapsible groups.
7
+ */
8
+ export function buildSidebar(docsDir, basePath = '') {
9
+ const items = [];
10
+ const fullPath = join(docsDir, basePath);
11
+ if (!existsSync(fullPath))
12
+ return items;
13
+ const entries = readdirSync(fullPath, { withFileTypes: true })
14
+ .filter(e => {
15
+ const name = e.name;
16
+ if (name.startsWith('.') || name.startsWith('_'))
17
+ return false;
18
+ if (name === 'node_modules' || name === 'index.md')
19
+ return false;
20
+ return true;
21
+ })
22
+ .sort((a, b) => a.name.localeCompare(b.name, undefined, { numeric: true }));
23
+ for (const entry of entries) {
24
+ const relPath = basePath ? `${basePath}/${entry.name}` : entry.name;
25
+ if (entry.isDirectory()) {
26
+ const children = buildSidebar(docsDir, relPath);
27
+ if (children.length > 0) {
28
+ items.push({
29
+ text: formatDisplayName(entry.name),
30
+ collapsed: false,
31
+ items: children,
32
+ });
33
+ }
34
+ }
35
+ else if (entry.isFile() && extname(entry.name) === '.md') {
36
+ const title = extractTitle(join(docsDir, relPath));
37
+ const link = '/' + relPath.replace(/\.md$/, '');
38
+ items.push({ text: title, link });
39
+ }
40
+ }
41
+ return items;
42
+ }
43
+ /**
44
+ * Strip numbered prefix and format as display name.
45
+ * "01-overview" → "Overview", "05-features" → "Features"
46
+ */
47
+ function formatDisplayName(name) {
48
+ const stripped = name.replace(/^\d+-/, '');
49
+ return stripped
50
+ .split(/[-_]/)
51
+ .map(w => w.charAt(0).toUpperCase() + w.slice(1))
52
+ .join(' ');
53
+ }
54
+ /**
55
+ * Extract title from markdown: YAML frontmatter title or first H1.
56
+ */
57
+ function extractTitle(filePath) {
58
+ try {
59
+ const raw = readFileSync(filePath, 'utf8');
60
+ const lines = raw.split('\n');
61
+ // Check YAML frontmatter
62
+ if (lines[0]?.trim() === '---') {
63
+ for (let i = 1; i < Math.min(lines.length, 20); i++) {
64
+ if (lines[i]?.trim() === '---')
65
+ break;
66
+ const match = lines[i]?.match(/^title:\s*["']?(.+?)["']?\s*$/);
67
+ if (match)
68
+ return match[1];
69
+ }
70
+ }
71
+ // Check first H1
72
+ for (const line of lines.slice(0, 30)) {
73
+ const h1 = line.match(/^#\s+(.+)/);
74
+ if (h1)
75
+ return h1[1];
76
+ }
77
+ }
78
+ catch {
79
+ // ignore read errors
80
+ }
81
+ // Fallback: format filename
82
+ return formatDisplayName(basename(filePath, '.md'));
83
+ }
84
+ /**
85
+ * Generate VitePress config.mts content and write to docsDir/.vitepress/.
86
+ */
87
+ export function generateVitePressConfig(docsDir, packageDir, options) {
88
+ const sidebar = buildSidebar(docsDir);
89
+ const sidebarJson = JSON.stringify(sidebar, null, 2);
90
+ const themePath = resolve(packageDir, 'theme').replace(/\\/g, '/');
91
+ const pluginPath = resolve(packageDir, 'plugins', 'file-api-plugin.ts').replace(/\\/g, '/');
92
+ const pluginImport = options.edit
93
+ ? `import { sekkeiFileApiPlugin } from '${pluginPath}'`
94
+ : '';
95
+ const nodeModulesPath = resolve(packageDir, 'node_modules').replace(/\\/g, '/');
96
+ const pluginsList = [];
97
+ if (options.edit) {
98
+ pluginsList.push(`sekkeiFileApiPlugin('${docsDir.replace(/\\/g, '/')}')`);
99
+ }
100
+ const editModeConfig = options.edit ? `\n editMode: true,` : '';
101
+ const config = `import path from 'node:path'
102
+ ${pluginImport}
103
+
104
+ export default {
105
+ title: ${JSON.stringify(options.title ?? 'Sekkei Docs')},
106
+ description: 'Japanese specification documents',
107
+ themeConfig: {
108
+ sidebar: ${sidebarJson},
109
+ outline: { level: [2, 3] },
110
+ search: { provider: 'local' },${editModeConfig}
111
+ },
112
+ vite: {
113
+ resolve: {
114
+ alias: {
115
+ 'vitepress/theme': path.join('${nodeModulesPath}', 'vitepress', 'dist', 'client', 'theme-default', 'index.js'),
116
+ },
117
+ },
118
+ server: {
119
+ fs: { allow: ['${packageDir.replace(/\\/g, '/')}', '${docsDir.replace(/\\/g, '/')}'] },
120
+ },
121
+ optimizeDeps: {
122
+ entries: [],
123
+ },${pluginsList.length > 0 ? `\n plugins: [${pluginsList.join(', ')}],` : ''}
124
+ },
125
+ }
126
+ `;
127
+ const vpDir = join(docsDir, '.vitepress');
128
+ if (!existsSync(vpDir))
129
+ mkdirSync(vpDir, { recursive: true });
130
+ writeFileSync(join(vpDir, 'config.mts'), config, 'utf8');
131
+ // Write theme re-export so VitePress picks up the custom theme
132
+ const themeIndex = `export { default } from '${themePath}/index.ts'\n`;
133
+ const themeDir = join(vpDir, 'theme');
134
+ if (!existsSync(themeDir))
135
+ mkdirSync(themeDir, { recursive: true });
136
+ writeFileSync(join(themeDir, 'index.ts'), themeIndex, 'utf8');
137
+ }
138
+ //# sourceMappingURL=generate-config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generate-config.js","sourceRoot":"","sources":["../src/generate-config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,WAAW,EAAY,aAAa,EAAE,MAAM,SAAS,CAAC;AACpG,OAAO,EAAE,IAAI,EAAE,OAAO,EAAY,QAAQ,EAAW,OAAO,EAAE,MAAM,WAAW,CAAC;AAehF;;;;GAIG;AACH,MAAM,UAAU,YAAY,CAAC,OAAe,EAAE,QAAQ,GAAG,EAAE;IACzD,MAAM,KAAK,GAAkB,EAAE,CAAC;IAChC,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;IAEzC,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC;QAAE,OAAO,KAAK,CAAC;IAExC,MAAM,OAAO,GAAG,WAAW,CAAC,QAAQ,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC;SAC3D,MAAM,CAAC,CAAC,CAAC,EAAE;QACV,MAAM,IAAI,GAAG,CAAC,CAAC,IAAI,CAAC;QACpB,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC;YAAE,OAAO,KAAK,CAAC;QAC/D,IAAI,IAAI,KAAK,cAAc,IAAI,IAAI,KAAK,UAAU;YAAE,OAAO,KAAK,CAAC;QACjE,OAAO,IAAI,CAAC;IACd,CAAC,CAAC;SACD,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,EAAE,SAAS,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;IAE9E,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC5B,MAAM,OAAO,GAAG,QAAQ,CAAC,CAAC,CAAC,GAAG,QAAQ,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC;QAEpE,IAAI,KAAK,CAAC,WAAW,EAAE,EAAE,CAAC;YACxB,MAAM,QAAQ,GAAG,YAAY,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;YAChD,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACxB,KAAK,CAAC,IAAI,CAAC;oBACT,IAAI,EAAE,iBAAiB,CAAC,KAAK,CAAC,IAAI,CAAC;oBACnC,SAAS,EAAE,KAAK;oBAChB,KAAK,EAAE,QAAQ;iBAChB,CAAC,CAAC;YACL,CAAC;QACH,CAAC;aAAM,IAAI,KAAK,CAAC,MAAM,EAAE,IAAI,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,KAAK,EAAE,CAAC;YAC3D,MAAM,KAAK,GAAG,YAAY,CAAC,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC;YACnD,MAAM,IAAI,GAAG,GAAG,GAAG,OAAO,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;YAChD,KAAK,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;QACpC,CAAC;IACH,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;GAGG;AACH,SAAS,iBAAiB,CAAC,IAAY;IACrC,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;IAC3C,OAAO,QAAQ;SACZ,KAAK,CAAC,MAAM,CAAC;SACb,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;SAChD,IAAI,CAAC,GAAG,CAAC,CAAC;AACf,CAAC;AAED;;GAEG;AACH,SAAS,YAAY,CAAC,QAAgB;IACpC,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,YAAY,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;QAC3C,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAE9B,yBAAyB;QACzB,IAAI,KAAK,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,KAAK,KAAK,EAAE,CAAC;YAC/B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;gBACpD,IAAI,KAAK,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,KAAK,KAAK;oBAAE,MAAM;gBACtC,MAAM,KAAK,GAAG,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,+BAA+B,CAAC,CAAC;gBAC/D,IAAI,KAAK;oBAAE,OAAO,KAAK,CAAC,CAAC,CAAC,CAAC;YAC7B,CAAC;QACH,CAAC;QAED,iBAAiB;QACjB,KAAK,MAAM,IAAI,IAAI,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC;YACtC,MAAM,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC;YACnC,IAAI,EAAE;gBAAE,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC;QACvB,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,qBAAqB;IACvB,CAAC;IAED,4BAA4B;IAC5B,OAAO,iBAAiB,CAAC,QAAQ,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC,CAAC;AACtD,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,uBAAuB,CACrC,OAAe,EACf,UAAkB,EAClB,OAAsB;IAEtB,MAAM,OAAO,GAAG,YAAY,CAAC,OAAO,CAAC,CAAC;IACtC,MAAM,WAAW,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;IACrD,MAAM,SAAS,GAAG,OAAO,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;IACnE,MAAM,UAAU,GAAG,OAAO,CAAC,UAAU,EAAE,SAAS,EAAE,oBAAoB,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;IAE5F,MAAM,YAAY,GAAG,OAAO,CAAC,IAAI;QAC/B,CAAC,CAAC,wCAAwC,UAAU,GAAG;QACvD,CAAC,CAAC,EAAE,CAAC;IAEP,MAAM,eAAe,GAAG,OAAO,CAAC,UAAU,EAAE,cAAc,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;IAEhF,MAAM,WAAW,GAAa,EAAE,CAAC;IACjC,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC;QACjB,WAAW,CAAC,IAAI,CAAC,wBAAwB,OAAO,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,IAAI,CAAC,CAAC;IAC5E,CAAC;IAED,MAAM,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,uBAAuB,CAAC,CAAC,CAAC,EAAE,CAAC;IAEnE,MAAM,MAAM,GAAG;EACf,YAAY;;;WAGH,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,KAAK,IAAI,aAAa,CAAC;;;eAG1C,WAAW;;oCAEU,cAAc;;;;;wCAKV,eAAe;;;;uBAIhC,UAAU,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,OAAO,OAAO,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC;;;;QAI/E,WAAW,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,mBAAmB,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE;;;CAGlF,CAAC;IAEA,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,EAAE,YAAY,CAAC,CAAC;IAC1C,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC;QAAE,SAAS,CAAC,KAAK,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC9D,aAAa,CAAC,IAAI,CAAC,KAAK,EAAE,YAAY,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;IAEzD,+DAA+D;IAC/D,MAAM,UAAU,GAAG,4BAA4B,SAAS,cAAc,CAAC;IACvE,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;IACtC,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC;QAAE,SAAS,CAAC,QAAQ,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACpE,aAAa,CAAC,IAAI,CAAC,QAAQ,EAAE,UAAU,CAAC,EAAE,UAAU,EAAE,MAAM,CAAC,CAAC;AAChE,CAAC"}
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Generate index.md if missing in docs dir.
3
+ * Uses _index.yaml for structure or falls back to minimal homepage.
4
+ */
5
+ export declare function generateIndexIfMissing(docsDir: string): void;
@@ -0,0 +1,74 @@
1
+ import { existsSync, readFileSync, writeFileSync } from 'node:fs';
2
+ import { join } from 'node:path';
3
+ import { parse as parseYaml } from 'yaml';
4
+ /**
5
+ * Generate index.md if missing in docs dir.
6
+ * Uses _index.yaml for structure or falls back to minimal homepage.
7
+ */
8
+ export function generateIndexIfMissing(docsDir) {
9
+ const indexPath = join(docsDir, 'index.md');
10
+ if (existsSync(indexPath))
11
+ return;
12
+ const indexYamlPath = join(docsDir, '_index.yaml');
13
+ let content;
14
+ if (existsSync(indexYamlPath)) {
15
+ content = generateFromIndexYaml(indexYamlPath);
16
+ }
17
+ else {
18
+ content = generateMinimalIndex(docsDir);
19
+ }
20
+ writeFileSync(indexPath, content, 'utf8');
21
+ }
22
+ function generateFromIndexYaml(yamlPath) {
23
+ const raw = readFileSync(yamlPath, 'utf8');
24
+ const manifest = parseYaml(raw);
25
+ const title = manifest?.title ?? 'Sekkei Documentation';
26
+ const desc = manifest?.description ?? '';
27
+ const lines = [
28
+ '---',
29
+ 'layout: home',
30
+ '---',
31
+ '',
32
+ `# ${title}`,
33
+ '',
34
+ ];
35
+ if (desc)
36
+ lines.push(desc, '');
37
+ if (manifest?.sections?.length) {
38
+ lines.push('## Documents', '');
39
+ for (const section of manifest.sections) {
40
+ const link = section.path.replace(/\.md$/, '');
41
+ lines.push(`- [${section.title}](/${link})${section.description ? ` — ${section.description}` : ''}`);
42
+ }
43
+ lines.push('');
44
+ }
45
+ return lines.join('\n');
46
+ }
47
+ function generateMinimalIndex(docsDir) {
48
+ // Try to get project name from sekkei.config.yaml
49
+ let projectName = 'Sekkei Documentation';
50
+ const configPath = join(process.cwd(), 'sekkei.config.yaml');
51
+ if (existsSync(configPath)) {
52
+ try {
53
+ const raw = readFileSync(configPath, 'utf8');
54
+ const config = parseYaml(raw);
55
+ if (config?.project?.name) {
56
+ projectName = config.project.name;
57
+ }
58
+ }
59
+ catch {
60
+ // ignore
61
+ }
62
+ }
63
+ return [
64
+ '---',
65
+ 'layout: home',
66
+ '---',
67
+ '',
68
+ `# ${projectName}`,
69
+ '',
70
+ `Documentation generated by [Sekkei](https://github.com/bienhoang/sekkei).`,
71
+ '',
72
+ ].join('\n');
73
+ }
74
+ //# sourceMappingURL=generate-index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generate-index.js","sourceRoot":"","sources":["../src/generate-index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Resolve docs directory with priority:
3
+ * 1. --docs CLI flag
4
+ * 2. ./sekkei-docs/ in CWD
5
+ * 3. sekkei.config.yaml → output.directory
6
+ * 4. Error
7
+ */
8
+ export declare function resolveDocsDir(cliDocsFlag?: string): string;
@@ -0,0 +1,46 @@
1
+ import { existsSync, readFileSync } from 'node:fs';
2
+ import { resolve, join } from 'node:path';
3
+ import { parse as parseYaml } from 'yaml';
4
+ /**
5
+ * Resolve docs directory with priority:
6
+ * 1. --docs CLI flag
7
+ * 2. ./sekkei-docs/ in CWD
8
+ * 3. sekkei.config.yaml → output.directory
9
+ * 4. Error
10
+ */
11
+ export function resolveDocsDir(cliDocsFlag) {
12
+ const cwd = process.cwd();
13
+ // Priority 1: CLI flag
14
+ if (cliDocsFlag) {
15
+ const abs = resolve(cwd, cliDocsFlag);
16
+ if (!existsSync(abs)) {
17
+ throw new Error(`Docs directory not found: ${abs}`);
18
+ }
19
+ return abs;
20
+ }
21
+ // Priority 2: ./sekkei-docs/ convention
22
+ const conventionDir = join(cwd, 'sekkei-docs');
23
+ if (existsSync(conventionDir)) {
24
+ return conventionDir;
25
+ }
26
+ // Priority 3: sekkei.config.yaml
27
+ const configPath = join(cwd, 'sekkei.config.yaml');
28
+ if (existsSync(configPath)) {
29
+ try {
30
+ const raw = readFileSync(configPath, 'utf8');
31
+ const config = parseYaml(raw);
32
+ const outputDir = config?.output?.directory;
33
+ if (outputDir) {
34
+ const abs = resolve(cwd, outputDir);
35
+ if (existsSync(abs)) {
36
+ return abs;
37
+ }
38
+ }
39
+ }
40
+ catch {
41
+ // Config parse failed — fall through
42
+ }
43
+ }
44
+ throw new Error('No docs directory found. Use --docs <path>, create ./sekkei-docs/, or set output.directory in sekkei.config.yaml');
45
+ }
46
+ //# sourceMappingURL=resolve-docs-dir.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolve-docs-dir.js","sourceRoot":"","sources":["../src/resolve-docs-dir.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACnD,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,KAAK,IAAI,SAAS,EAAE,MAAM,MAAM,CAAC;AAE1C;;;;;;GAMG;AACH,MAAM,UAAU,cAAc,CAAC,WAAoB;IACjD,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC;IAE1B,uBAAuB;IACvB,IAAI,WAAW,EAAE,CAAC;QAChB,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,EAAE,WAAW,CAAC,CAAC;QACtC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;YACrB,MAAM,IAAI,KAAK,CAAC,6BAA6B,GAAG,EAAE,CAAC,CAAC;QACtD,CAAC;QACD,OAAO,GAAG,CAAC;IACb,CAAC;IAED,wCAAwC;IACxC,MAAM,aAAa,GAAG,IAAI,CAAC,GAAG,EAAE,aAAa,CAAC,CAAC;IAC/C,IAAI,UAAU,CAAC,aAAa,CAAC,EAAE,CAAC;QAC9B,OAAO,aAAa,CAAC;IACvB,CAAC;IAED,iCAAiC;IACjC,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,EAAE,oBAAoB,CAAC,CAAC;IACnD,IAAI,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;QAC3B,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,YAAY,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC;YAC7C,MAAM,MAAM,GAAG,SAAS,CAAC,GAAG,CAAwC,CAAC;YACrE,MAAM,SAAS,GAAG,MAAM,EAAE,MAAM,EAAE,SAAS,CAAC;YAC5C,IAAI,SAAS,EAAE,CAAC;gBACd,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC;gBACpC,IAAI,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;oBACpB,OAAO,GAAG,CAAC;gBACb,CAAC;YACH,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,qCAAqC;QACvC,CAAC;IACH,CAAC;IAED,MAAM,IAAI,KAAK,CACb,kHAAkH,CACnH,CAAC;AACJ,CAAC"}
package/package.json ADDED
@@ -0,0 +1,44 @@
1
+ {
2
+ "name": "sekkei-preview",
3
+ "version": "0.1.0",
4
+ "description": "VitePress-based preview + WYSIWYG editor for Sekkei specification documents",
5
+ "type": "module",
6
+ "bin": {
7
+ "sekkei-preview": "./dist/cli.js"
8
+ },
9
+ "main": "dist/cli.js",
10
+ "files": [
11
+ "dist/",
12
+ "theme/",
13
+ "plugins/"
14
+ ],
15
+ "scripts": {
16
+ "build": "tsc",
17
+ "lint": "tsc --noEmit"
18
+ },
19
+ "dependencies": {
20
+ "vitepress": "^1.6.4",
21
+ "vue": "^3.5.0",
22
+ "yaml": "^2.7.0",
23
+ "@milkdown/kit": "^7.18.0",
24
+ "@milkdown/vue": "^7.18.0",
25
+ "@milkdown/theme-nord": "^7.18.0"
26
+ },
27
+ "devDependencies": {
28
+ "typescript": "^5.7.0",
29
+ "@types/node": "^22.13.0"
30
+ },
31
+ "engines": {
32
+ "node": ">=20.0.0"
33
+ },
34
+ "keywords": [
35
+ "sekkei",
36
+ "vitepress",
37
+ "preview",
38
+ "wysiwyg",
39
+ "milkdown",
40
+ "japanese",
41
+ "specification"
42
+ ],
43
+ "license": "MIT"
44
+ }