docs-i18n 0.6.2 → 0.7.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.
Files changed (169) hide show
  1. package/{src/admin/ui → admin/app}/components/JobDialog.tsx +21 -2
  2. package/{src/admin/ui → admin/app}/components/JobPanel.tsx +1 -1
  3. package/{src/admin/ui → admin/app}/components/Preview.tsx +2 -5
  4. package/{src/admin/ui → admin/app}/lib/api.ts +18 -39
  5. package/admin/app/routeTree.gen.ts +68 -0
  6. package/admin/app/router.tsx +23 -0
  7. package/admin/app/routes/__root.tsx +55 -0
  8. package/admin/app/routes/index.tsx +416 -0
  9. package/{src/admin/ui → admin/app}/styles.css +36 -3
  10. package/admin/package.json +27 -0
  11. package/admin/server/functions/jobs.ts +53 -0
  12. package/admin/server/functions/misc.ts +84 -0
  13. package/{src/admin/server/routes → admin/server/functions}/models.ts +16 -29
  14. package/admin/server/functions/status.ts +61 -0
  15. package/admin/server/index.ts +35 -0
  16. package/admin/server/init.ts +46 -0
  17. package/{src/admin → admin}/server/services/job-manager.ts +39 -10
  18. package/{src/admin → admin}/server/services/status.ts +6 -6
  19. package/admin/tsconfig.json +19 -0
  20. package/{src/admin → admin}/vite.config.ts +8 -2
  21. package/dist/{assemble-7H4QCW35.js → assemble-CP2BRYQJ.js} +6 -4
  22. package/dist/{chunk-A3YQNPKZ.js → chunk-CLYUAWZE.js} +1 -1
  23. package/dist/{chunk-YN4VJHCQ.js → chunk-JHBSHTXC.js} +1 -1
  24. package/dist/chunk-L64GJ4OB.js +32 -0
  25. package/dist/{chunk-SKKZIV3L.js → chunk-PNKVD2UK.js} +1 -29
  26. package/dist/{chunk-XEOYZUHS.js → chunk-QKIR7RKQ.js} +4 -31
  27. package/dist/chunk-TRURQFP4.js +31 -0
  28. package/dist/cli.js +108 -23
  29. package/dist/index.d.ts +41 -1
  30. package/dist/index.js +92 -3
  31. package/dist/{rescan-O5D3CYC2.js → rescan-HXMWFAOC.js} +5 -3
  32. package/dist/{status-F4MYIAAY.js → status-AGZDXOTZ.js} +4 -2
  33. package/dist/{translate-ZIVKNAC4.js → translate-A5X6MX4Y.js} +14 -7
  34. package/dist/upload-XL6KG6S2.js +132 -0
  35. package/package.json +17 -15
  36. package/template/app/components/BlogArticle.tsx +159 -0
  37. package/template/app/components/BlogList.tsx +88 -0
  38. package/template/app/components/Breadcrumbs.tsx +81 -0
  39. package/template/app/components/Card.tsx +31 -0
  40. package/template/app/components/Doc.tsx +191 -0
  41. package/template/app/components/DocBreadcrumb.tsx +60 -0
  42. package/template/app/components/DocContainer.tsx +13 -0
  43. package/template/app/components/DocTitle.tsx +11 -0
  44. package/template/app/components/DocsLayout.tsx +715 -0
  45. package/template/app/components/Dropdown.tsx +116 -0
  46. package/template/app/components/FallbackBanner.tsx +36 -0
  47. package/template/app/components/Footer.tsx +29 -0
  48. package/template/app/components/FrameworkSelect.tsx +150 -0
  49. package/template/app/components/LibraryCard.tsx +178 -0
  50. package/template/app/components/LocaleSwitcher.tsx +43 -0
  51. package/template/app/components/Navbar.tsx +430 -0
  52. package/template/app/components/PostNotFound.tsx +20 -0
  53. package/template/app/components/SearchButton.tsx +32 -0
  54. package/template/app/components/Select.tsx +103 -0
  55. package/template/app/components/Spinner.tsx +18 -0
  56. package/template/app/components/ThemeProvider.tsx +141 -0
  57. package/template/app/components/ThemeToggle.tsx +31 -0
  58. package/template/app/components/Toc.tsx +86 -0
  59. package/template/app/components/VersionSelect.tsx +118 -0
  60. package/template/app/components/icons/BSkyIcon.tsx +27 -0
  61. package/template/app/components/icons/BaseballCapIcon.tsx +25 -0
  62. package/template/app/components/icons/BrandXIcon.tsx +28 -0
  63. package/template/app/components/icons/CheckCircleIcon.tsx +28 -0
  64. package/template/app/components/icons/CogsIcon.tsx +25 -0
  65. package/template/app/components/icons/DiscordIcon.tsx +24 -0
  66. package/template/app/components/icons/GithubIcon.tsx +24 -0
  67. package/template/app/components/icons/GoogleIcon.tsx +24 -0
  68. package/template/app/components/icons/InstagramIcon.tsx +24 -0
  69. package/template/app/components/icons/NpmIcon.tsx +26 -0
  70. package/template/app/components/icons/YinYangIcon.tsx +26 -0
  71. package/template/app/components/icons/YouTubeIcon.tsx +24 -0
  72. package/template/app/components/markdown/CodeBlock.tsx +254 -0
  73. package/template/app/components/markdown/FileTabs.tsx +58 -0
  74. package/template/app/components/markdown/FrameworkContent.tsx +76 -0
  75. package/template/app/components/markdown/Markdown.tsx +216 -0
  76. package/template/app/components/markdown/MarkdownContent.tsx +89 -0
  77. package/template/app/components/markdown/MarkdownFrameworkHandler.tsx +66 -0
  78. package/template/app/components/markdown/MarkdownHeadingContext.tsx +35 -0
  79. package/template/app/components/markdown/MarkdownLink.tsx +46 -0
  80. package/template/app/components/markdown/MarkdownTabsHandler.tsx +109 -0
  81. package/template/app/components/markdown/PackageManagerTabs.tsx +95 -0
  82. package/template/app/components/markdown/Tabs.tsx +139 -0
  83. package/template/app/components/markdown/index.ts +15 -0
  84. package/template/app/components/ui/Button.tsx +141 -0
  85. package/template/app/components/ui/InlineCode.tsx +16 -0
  86. package/template/app/components/ui/MarkdownImg.tsx +21 -0
  87. package/template/app/config/frameworks.ts +93 -0
  88. package/template/app/contexts/SearchContext.tsx +36 -0
  89. package/template/app/db/index.ts +17 -0
  90. package/template/app/db/schema.ts +74 -0
  91. package/template/app/hooks/useClickOutside.ts +106 -0
  92. package/template/app/routeTree.gen.ts +584 -0
  93. package/template/app/router.tsx +29 -0
  94. package/template/app/routes/$lang.$project.$version.docs.$.tsx +128 -0
  95. package/template/app/routes/$lang.$project.$version.docs.framework.$framework.$.tsx +106 -0
  96. package/template/app/routes/$lang.$project.$version.docs.framework.$framework.index.tsx +27 -0
  97. package/template/app/routes/$lang.$project.$version.docs.framework.index.tsx +44 -0
  98. package/template/app/routes/$lang.$project.$version.docs.index.tsx +27 -0
  99. package/template/app/routes/$lang.$project.$version.docs.tsx +70 -0
  100. package/template/app/routes/$lang.$project.$version.tsx +69 -0
  101. package/template/app/routes/$lang.$project.docs.$.tsx +104 -0
  102. package/template/app/routes/$lang.$project.docs.index.tsx +20 -0
  103. package/template/app/routes/$lang.$project.docs.tsx +79 -0
  104. package/template/app/routes/$lang.$project.tsx +89 -0
  105. package/template/app/routes/$lang.blog.$.tsx +82 -0
  106. package/template/app/routes/$lang.blog.index.tsx +56 -0
  107. package/template/app/routes/$lang.blog.tsx +26 -0
  108. package/template/app/routes/$lang.docs.$.tsx +100 -0
  109. package/template/app/routes/$lang.docs.framework.$framework.$.tsx +104 -0
  110. package/template/app/routes/$lang.docs.framework.$framework.index.tsx +32 -0
  111. package/template/app/routes/$lang.docs.framework.index.tsx +47 -0
  112. package/template/app/routes/$lang.docs.index.tsx +20 -0
  113. package/template/app/routes/$lang.docs.tsx +90 -0
  114. package/template/app/routes/$lang.tsx +16 -0
  115. package/template/app/routes/__root.tsx +180 -0
  116. package/template/app/routes/index.tsx +89 -0
  117. package/template/app/site.config.ts +182 -0
  118. package/template/app/styles/app.css +1029 -0
  119. package/template/app/types/index.ts +77 -0
  120. package/template/app/utils/blog.server.ts +193 -0
  121. package/template/app/utils/blog.ts +42 -0
  122. package/template/app/utils/config.ts +120 -0
  123. package/template/app/utils/content-loader.ts +400 -0
  124. package/template/app/utils/dates.ts +29 -0
  125. package/template/app/utils/docs.server.ts +150 -0
  126. package/template/app/utils/markdown/filterFrameworkContent.ts +233 -0
  127. package/template/app/utils/markdown/index.ts +2 -0
  128. package/template/app/utils/markdown/installCommand.ts +143 -0
  129. package/template/app/utils/markdown/plugins/collectHeadings.ts +104 -0
  130. package/template/app/utils/markdown/plugins/extractCodeMeta.ts +57 -0
  131. package/template/app/utils/markdown/plugins/helpers.ts +33 -0
  132. package/template/app/utils/markdown/plugins/index.ts +8 -0
  133. package/template/app/utils/markdown/plugins/parseCommentComponents.ts +103 -0
  134. package/template/app/utils/markdown/plugins/transformCommentComponents.ts +23 -0
  135. package/template/app/utils/markdown/plugins/transformFrameworkComponent.ts +217 -0
  136. package/template/app/utils/markdown/plugins/transformTabsComponent.ts +359 -0
  137. package/template/app/utils/markdown/processor.ts +75 -0
  138. package/template/app/utils/site-config.tsx +11 -0
  139. package/template/app/utils/upload.ts +232 -0
  140. package/template/app/utils/useLocalStorage.ts +65 -0
  141. package/template/app/utils/utils.ts +23 -0
  142. package/template/package.json +54 -0
  143. package/template/public/favicon.svg +1 -0
  144. package/template/public/fonts/Inter-latin-ext.woff2 +0 -0
  145. package/template/public/fonts/Inter-latin.woff2 +0 -0
  146. package/template/public/images/frameworks/angular-logo.svg +1 -0
  147. package/template/public/images/frameworks/js-logo.svg +1 -0
  148. package/template/public/images/frameworks/lit-logo.svg +1 -0
  149. package/template/public/images/frameworks/preact-logo.svg +6 -0
  150. package/template/public/images/frameworks/qwik-logo.svg +1 -0
  151. package/template/public/images/frameworks/react-logo.svg +1 -0
  152. package/template/public/images/frameworks/solid-logo.svg +1 -0
  153. package/template/public/images/frameworks/svelte-logo.svg +1 -0
  154. package/template/public/images/frameworks/vue-logo.svg +4 -0
  155. package/template/tsconfig.json +24 -0
  156. package/template/vite.config.ts +43 -0
  157. package/template/wrangler.jsonc +16 -0
  158. package/README.md +0 -161
  159. package/dist/server-73AVSOL5.js +0 -598
  160. package/src/admin/index.html +0 -13
  161. package/src/admin/server/index.ts +0 -138
  162. package/src/admin/server/routes/jobs.ts +0 -113
  163. package/src/admin/server/routes/status.ts +0 -57
  164. package/src/admin/ui/App.tsx +0 -332
  165. package/src/admin/ui/main.tsx +0 -19
  166. /package/{src/admin/ui → admin/app}/components/FileList.tsx +0 -0
  167. /package/{src/admin/ui → admin/app}/components/LangGrid.tsx +0 -0
  168. /package/{src/admin/ui → admin/app}/components/ProgressBar.tsx +0 -0
  169. /package/{src/admin/ui → admin/app}/lib/flags.ts +0 -0
@@ -0,0 +1,61 @@
1
+ import { createServerFn } from '@tanstack/react-start';
2
+ import {
3
+ getCache,
4
+ getFileBlocks,
5
+ getFileCoverage,
6
+ getLangs,
7
+ getOverview,
8
+ getVersions,
9
+ rescan,
10
+ } from '../services/status';
11
+ import { ensureInit } from '../init';
12
+
13
+ export const fetchStatus = createServerFn({ method: 'GET' }).handler(async () => {
14
+ await ensureInit();
15
+ return {
16
+ versions: getVersions(),
17
+ langs: ['en', ...getLangs()],
18
+ data: getOverview(),
19
+ };
20
+ });
21
+
22
+ export const fetchFileCoverage = createServerFn({ method: 'GET' })
23
+ .inputValidator((d: { version: string; lang: string }) => d)
24
+ .handler(async ({ data }) => {
25
+ await ensureInit();
26
+ const { version, lang } = data;
27
+ if (lang === 'en') {
28
+ const anyLang = getLangs()[0];
29
+ const coverage = getFileCoverage(version, anyLang);
30
+ return coverage.map((f) => ({ file: f.file, total: f.total, translated: f.total }));
31
+ }
32
+ return getFileCoverage(version, lang);
33
+ });
34
+
35
+ export const fetchFileBlocks = createServerFn({ method: 'GET' })
36
+ .inputValidator((d: { version: string; lang: string; path: string }) => d)
37
+ .handler(async ({ data }) => {
38
+ await ensureInit();
39
+ const { version, lang, path } = data;
40
+ const blocks = getFileBlocks(version, lang, path);
41
+ if (!blocks) throw new Error('File not found');
42
+ return { file: path, lang, version, blocks };
43
+ });
44
+
45
+ export const deleteCacheEntry = createServerFn({ method: 'POST' })
46
+ .inputValidator((d: { version: string; lang: string; key: string }) => d)
47
+ .handler(async ({ data }) => {
48
+ await ensureInit();
49
+ const { lang, key } = data;
50
+ const cache = getCache();
51
+ cache.db.prepare('DELETE FROM translations WHERE lang = ? AND key = ?').run(lang, key);
52
+ return { deleted: key, lang };
53
+ });
54
+
55
+ export const rescanVersion = createServerFn({ method: 'POST' })
56
+ .inputValidator((d: { version: string }) => d)
57
+ .handler(async ({ data }) => {
58
+ await ensureInit();
59
+ const count = rescan(data.version);
60
+ return { version: data.version, files: count };
61
+ });
@@ -0,0 +1,35 @@
1
+ import { resolve, dirname } from 'node:path';
2
+ import { fileURLToPath } from 'node:url';
3
+ import { writeFileSync } from 'node:fs';
4
+ import { spawn } from 'node:child_process';
5
+ import { tmpdir } from 'node:os';
6
+ import type { DocsI18nConfig } from 'docs-i18n';
7
+ import { initAdmin } from './init';
8
+
9
+ /**
10
+ * Start the admin dashboard dev server.
11
+ * Called by the CLI `docs-i18n admin` command.
12
+ */
13
+ export async function startAdmin(config: DocsI18nConfig, port: number) {
14
+ initAdmin(config);
15
+
16
+ const thisFile = fileURLToPath(import.meta.url);
17
+ // Admin package root is the directory containing this server/ folder
18
+ const adminRoot = resolve(dirname(thisFile), '..');
19
+
20
+ // Write project root so the admin server functions can find config + content.
21
+ const tmpFile = resolve(tmpdir(), 'docs-i18n-project-root');
22
+ writeFileSync(tmpFile, process.cwd());
23
+
24
+ const child = spawn('npx', ['vite', '--port', String(port)], {
25
+ cwd: adminRoot,
26
+ stdio: 'inherit',
27
+ env: { ...process.env, DOCS_I18N_PROJECT_ROOT: process.cwd() },
28
+ shell: true,
29
+ });
30
+
31
+ child.on('exit', (code) => process.exit(code ?? 0));
32
+
33
+ // Keep the process alive until the child exits.
34
+ await new Promise<void>(() => {});
35
+ }
@@ -0,0 +1,46 @@
1
+ import { readFileSync } from 'node:fs';
2
+ import { resolve, dirname } from 'node:path';
3
+ import { fileURLToPath } from 'node:url';
4
+ import type { DocsI18nConfig } from 'docs-i18n';
5
+ import { initStatus } from './services/status';
6
+ import { setConfig } from './services/job-manager';
7
+
8
+ let _initialized = false;
9
+ let _config: DocsI18nConfig | undefined;
10
+
11
+ /**
12
+ * Initialize admin server services with the project config.
13
+ */
14
+ export function initAdmin(config: DocsI18nConfig) {
15
+ _config = config;
16
+ initStatus(config);
17
+ setConfig(config);
18
+ _initialized = true;
19
+ }
20
+
21
+ export function getConfig(): DocsI18nConfig | undefined {
22
+ return _config;
23
+ }
24
+
25
+ export function getProjectRoot(): string {
26
+ if (process.env.DOCS_I18N_PROJECT_ROOT) return process.env.DOCS_I18N_PROJECT_ROOT;
27
+ // Read from temp file written by CLI at startup
28
+ try {
29
+ const tmpDir = process.env.TMPDIR || process.env.TEMP || '/tmp';
30
+ return readFileSync(resolve(tmpDir, 'docs-i18n-project-root'), 'utf-8').trim();
31
+ } catch {}
32
+ return process.cwd();
33
+ }
34
+
35
+ /**
36
+ * Ensure admin is initialized. Lazy-loads config on first call.
37
+ */
38
+ export async function ensureInit() {
39
+ if (_initialized) return;
40
+ if (typeof window !== 'undefined') return;
41
+ const projectRoot = getProjectRoot();
42
+ const configPath = `${projectRoot}/docs-i18n.config.ts`;
43
+ const mod = await import(/* @vite-ignore */ configPath);
44
+ const config: DocsI18nConfig = mod.default ?? mod;
45
+ initAdmin(config);
46
+ }
@@ -1,10 +1,16 @@
1
1
  import { type ChildProcess, spawn } from 'node:child_process';
2
+ import { readFileSync } from 'node:fs';
2
3
  import { resolve } from 'node:path';
3
- import type { DocsI18nConfig } from '../../../config';
4
-
5
- const PROJECT_ROOT = process.cwd();
6
- // CLI binary path — reuse the same entry that started this process
7
- const CLI_BIN = process.argv[1] ?? 'docs-i18n';
4
+ import type { DocsI18nConfig } from 'docs-i18n';
5
+
6
+ function getProjectRoot(): string {
7
+ if (process.env.DOCS_I18N_PROJECT_ROOT) return process.env.DOCS_I18N_PROJECT_ROOT;
8
+ try {
9
+ const tmpDir = process.env.TMPDIR || process.env.TEMP || '/tmp';
10
+ return readFileSync(resolve(tmpDir, 'docs-i18n-project-root'), 'utf-8').trim();
11
+ } catch {}
12
+ return process.cwd();
13
+ }
8
14
 
9
15
  let _config: DocsI18nConfig | undefined;
10
16
  export function setConfig(config: DocsI18nConfig) { _config = config; }
@@ -70,15 +76,25 @@ export class JobManager {
70
76
  };
71
77
  this.jobs.set(id, job);
72
78
 
79
+ // The version may be a compound key "project/version" from the admin UI.
80
+ // Split it into separate --project and --version args for the CLI.
81
+ let projectArg = opts.project ?? '';
82
+ let versionArg = opts.version;
83
+ if (!projectArg && opts.version.includes('/')) {
84
+ const parts = opts.version.split('/');
85
+ projectArg = parts.slice(0, -1).join('/');
86
+ versionArg = parts[parts.length - 1];
87
+ }
88
+
73
89
  const args = [
74
90
  'translate',
75
91
  '--lang', opts.lang,
76
- '--version', opts.version,
92
+ '--version', versionArg,
77
93
  '--max', String(opts.max ?? 999),
78
94
  '--concurrency', String(opts.concurrency ?? 3),
79
95
  ];
80
96
 
81
- if (opts.project) args.push('--project', opts.project);
97
+ if (projectArg) args.push('--project', projectArg);
82
98
  if (opts.model) args.push('--model', opts.model);
83
99
  if (opts.files?.length) args.push('--files', opts.files.join(','));
84
100
 
@@ -86,10 +102,23 @@ export class JobManager {
86
102
  const apiKey = _config?.llm?.apiKey || process.env.OPENROUTER_API_KEY || process.env.OPENAI_API_KEY || '';
87
103
  if (apiKey) args.push('--api-key', apiKey);
88
104
 
89
- const proc = spawn(CLI_BIN, args, {
90
- cwd: PROJECT_ROOT,
105
+ const projectRoot = getProjectRoot();
106
+
107
+ // Load .env from project root so child process has access to env vars
108
+ const childEnv: Record<string, string> = { ...process.env, NO_TTY: '1', FORCE_COLOR: '0' };
109
+ try {
110
+ const envContent = readFileSync(resolve(projectRoot, '.env'), 'utf-8');
111
+ for (const line of envContent.split('\n')) {
112
+ const match = line.match(/^\s*([A-Z_][A-Z0-9_]*)\s*=\s*(.*)\s*$/);
113
+ if (match && !childEnv[match[1]]) childEnv[match[1]] = match[2];
114
+ }
115
+ } catch {}
116
+
117
+ const proc = spawn('npx', ['docs-i18n', ...args], {
118
+ cwd: projectRoot,
91
119
  stdio: ['ignore', 'pipe', 'pipe'],
92
- env: { ...process.env, NO_TTY: '1', FORCE_COLOR: '0' },
120
+ env: childEnv,
121
+ shell: true,
93
122
  });
94
123
  this.processes.set(id, proc);
95
124
 
@@ -1,16 +1,16 @@
1
1
  import { existsSync, readdirSync, readFileSync } from 'node:fs';
2
2
  import { join, resolve } from 'node:path';
3
- import type { DocsI18nConfig } from '../../../config';
4
- import { flattenSources } from '../../../config';
5
- import { TranslationCache } from '../../../core/cache';
6
- import { parseMdx } from '../../../core/parser';
3
+ import type { DocsI18nConfig } from 'docs-i18n';
4
+ import { flattenSources, TranslationCache, parseMdx } from 'docs-i18n';
7
5
 
8
6
  let _config: DocsI18nConfig;
9
7
  let _cache: TranslationCache | null = null;
8
+ let _projectRoot: string = process.cwd();
10
9
 
11
10
  export function initStatus(config: DocsI18nConfig) {
12
11
  _config = config;
13
12
  _cache = null; // reset
13
+ _projectRoot = process.env.DOCS_I18N_PROJECT_ROOT || process.cwd();
14
14
  }
15
15
 
16
16
  export function getVersions(): string[] {
@@ -23,14 +23,14 @@ export function getLangs(): string[] {
23
23
 
24
24
  export function getCache(): TranslationCache {
25
25
  if (!_cache) {
26
- _cache = new TranslationCache(resolve(_config.cacheDir ?? '.cache'));
26
+ _cache = new TranslationCache(resolve(_projectRoot, _config.cacheDir ?? '.cache'));
27
27
  }
28
28
  return _cache;
29
29
  }
30
30
 
31
31
  function getSourcePath(versionKey: string): string | null {
32
32
  const source = flattenSources(_config).find((s) => s.versionKey === versionKey);
33
- return source ? resolve(source.sourcePath) : null;
33
+ return source ? resolve(_projectRoot, source.sourcePath) : null;
34
34
  }
35
35
 
36
36
  function walkFiles(dir: string): string[] {
@@ -0,0 +1,19 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "module": "ESNext",
5
+ "moduleResolution": "bundler",
6
+ "strict": true,
7
+ "esModuleInterop": true,
8
+ "skipLibCheck": true,
9
+ "forceConsistentCasingInFileNames": true,
10
+ "resolveJsonModule": true,
11
+ "isolatedModules": true,
12
+ "jsx": "react-jsx",
13
+ "paths": {
14
+ "docs-i18n": ["../core/src/index.ts"]
15
+ }
16
+ },
17
+ "include": ["app", "server"],
18
+ "exclude": ["node_modules"]
19
+ }
@@ -1,7 +1,13 @@
1
1
  // @ts-nocheck — Vite config, not checked by project tsc
2
- import react from '@vitejs/plugin-react';
3
2
  import { defineConfig } from 'vite';
3
+ import { tanstackStart } from '@tanstack/react-start/plugin/vite';
4
+ import react from '@vitejs/plugin-react';
4
5
 
5
6
  export default defineConfig({
6
- plugins: [react()],
7
+ plugins: [
8
+ tanstackStart({
9
+ srcDirectory: 'app',
10
+ }),
11
+ react(),
12
+ ],
7
13
  });
@@ -1,13 +1,15 @@
1
1
  import {
2
2
  assemble
3
- } from "./chunk-A3YQNPKZ.js";
4
- import "./chunk-YN4VJHCQ.js";
3
+ } from "./chunk-CLYUAWZE.js";
4
+ import "./chunk-JHBSHTXC.js";
5
5
  import {
6
6
  TranslationCache
7
- } from "./chunk-XEOYZUHS.js";
7
+ } from "./chunk-QKIR7RKQ.js";
8
8
  import {
9
9
  flattenSources
10
- } from "./chunk-SKKZIV3L.js";
10
+ } from "./chunk-TRURQFP4.js";
11
+ import "./chunk-L64GJ4OB.js";
12
+ import "./chunk-PNKVD2UK.js";
11
13
 
12
14
  // src/commands/assemble.ts
13
15
  import {
@@ -3,7 +3,7 @@ import {
3
3
  init_parser,
4
4
  normalize,
5
5
  parseMdx
6
- } from "./chunk-YN4VJHCQ.js";
6
+ } from "./chunk-JHBSHTXC.js";
7
7
 
8
8
  // src/core/assembler.ts
9
9
  init_normalize();
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  __esm
3
- } from "./chunk-SKKZIV3L.js";
3
+ } from "./chunk-PNKVD2UK.js";
4
4
 
5
5
  // src/core/normalize.ts
6
6
  function normalize(content) {
@@ -0,0 +1,32 @@
1
+ // src/core/sqlite.ts
2
+ import { createRequire } from "module";
3
+ var isBun = typeof globalThis.Bun !== "undefined";
4
+ function openDatabase(filepath) {
5
+ if (isBun) {
6
+ const req2 = createRequire(import.meta.url);
7
+ const mod = req2("bun:sqlite");
8
+ const Database2 = mod.Database ?? mod.default ?? mod;
9
+ const raw = new Database2(filepath);
10
+ return {
11
+ prepare: (sql) => {
12
+ const stmt = raw.query(sql);
13
+ return {
14
+ run: (...params) => stmt.run(...params),
15
+ get: (...params) => stmt.get(...params),
16
+ all: (...params) => stmt.all(...params)
17
+ };
18
+ },
19
+ exec: (sql) => raw.run(sql),
20
+ pragma: (p) => raw.run(`PRAGMA ${p}`),
21
+ transaction: (fn) => raw.transaction(fn),
22
+ close: () => raw.close()
23
+ };
24
+ }
25
+ const req = createRequire(import.meta.url);
26
+ const Database = req("better-sqlite3");
27
+ return new Database(filepath);
28
+ }
29
+
30
+ export {
31
+ openDatabase
32
+ };
@@ -19,36 +19,8 @@ var __copyProps = (to, from, except, desc) => {
19
19
  };
20
20
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
21
21
 
22
- // src/config.ts
23
- async function loadConfig(path) {
24
- const configPath = path ?? "docs-i18n.config.ts";
25
- try {
26
- const mod = await import(
27
- /* @vite-ignore */
28
- `${process.cwd()}/${configPath}`
29
- );
30
- return mod.default ?? mod;
31
- } catch {
32
- throw new Error(`Cannot load config from ${configPath}. Create a docs-i18n.config.ts file.`);
33
- }
34
- }
35
- function flattenSources(config) {
36
- const projects = Object.entries(config.projects);
37
- const singleProject = projects.length === 1;
38
- return projects.flatMap(
39
- ([projectId, project]) => Object.entries(project.sources).map(([version, sourcePath]) => ({
40
- project: projectId,
41
- version,
42
- sourcePath,
43
- versionKey: singleProject ? version : `${projectId}/${version}`
44
- }))
45
- );
46
- }
47
-
48
22
  export {
49
23
  __esm,
50
24
  __export,
51
- __toCommonJS,
52
- loadConfig,
53
- flattenSources
25
+ __toCommonJS
54
26
  };
@@ -1,37 +1,10 @@
1
+ import {
2
+ openDatabase
3
+ } from "./chunk-L64GJ4OB.js";
4
+
1
5
  // src/core/cache.ts
2
6
  import fs from "fs";
3
7
  import path from "path";
4
-
5
- // src/core/sqlite.ts
6
- import { createRequire } from "module";
7
- var isBun = typeof globalThis.Bun !== "undefined";
8
- function openDatabase(filepath) {
9
- if (isBun) {
10
- const req2 = createRequire(import.meta.url);
11
- const mod = req2("bun:sqlite");
12
- const Database2 = mod.Database ?? mod.default ?? mod;
13
- const raw = new Database2(filepath);
14
- return {
15
- prepare: (sql) => {
16
- const stmt = raw.query(sql);
17
- return {
18
- run: (...params) => stmt.run(...params),
19
- get: (...params) => stmt.get(...params),
20
- all: (...params) => stmt.all(...params)
21
- };
22
- },
23
- exec: (sql) => raw.run(sql),
24
- pragma: (p) => raw.run(`PRAGMA ${p}`),
25
- transaction: (fn) => raw.transaction(fn),
26
- close: () => raw.close()
27
- };
28
- }
29
- const req = createRequire(import.meta.url);
30
- const Database = req("better-sqlite3");
31
- return new Database(filepath);
32
- }
33
-
34
- // src/core/cache.ts
35
8
  var TranslationCache = class {
36
9
  db;
37
10
  cacheDir;
@@ -0,0 +1,31 @@
1
+ // src/config.ts
2
+ async function loadConfig(path) {
3
+ const configPath = path ?? "docs-i18n.config.ts";
4
+ const fullPath = configPath.startsWith("/") ? configPath : `${process.cwd()}/${configPath}`;
5
+ try {
6
+ const mod = await import(
7
+ /* @vite-ignore */
8
+ fullPath
9
+ );
10
+ return mod.default ?? mod;
11
+ } catch {
12
+ throw new Error(`Cannot load config from ${fullPath}. Create a docs-i18n.config.ts file.`);
13
+ }
14
+ }
15
+ function flattenSources(config) {
16
+ const projects = Object.entries(config.projects);
17
+ const singleProject = projects.length === 1;
18
+ return projects.flatMap(
19
+ ([projectId, project]) => Object.entries(project.sources).map(([version, sourcePath]) => ({
20
+ project: projectId,
21
+ version,
22
+ sourcePath,
23
+ versionKey: singleProject ? version : `${projectId}/${version}`
24
+ }))
25
+ );
26
+ }
27
+
28
+ export {
29
+ loadConfig,
30
+ flattenSources
31
+ };
package/dist/cli.js CHANGED
@@ -1,26 +1,11 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  loadConfig
4
- } from "./chunk-SKKZIV3L.js";
4
+ } from "./chunk-TRURQFP4.js";
5
+ import "./chunk-PNKVD2UK.js";
5
6
 
6
7
  // src/cli.ts
7
- import { existsSync, readFileSync } from "fs";
8
- import { resolve } from "path";
9
8
  import { createRequire } from "module";
10
- var envPath = resolve(process.cwd(), ".env");
11
- if (existsSync(envPath)) {
12
- for (const line of readFileSync(envPath, "utf-8").split("\n")) {
13
- const trimmed = line.trim();
14
- if (!trimmed || trimmed.startsWith("#")) continue;
15
- const eq = trimmed.indexOf("=");
16
- if (eq < 0) continue;
17
- const key = trimmed.slice(0, eq).trim();
18
- let val = trimmed.slice(eq + 1).trim();
19
- if (val.startsWith('"') && val.endsWith('"') || val.startsWith("'") && val.endsWith("'"))
20
- val = val.slice(1, -1);
21
- if (!process.env[key]) process.env[key] = val;
22
- }
23
- }
24
9
  var args = process.argv.slice(2);
25
10
  if (args[0] === "--version" || args[0] === "-v") {
26
11
  const require2 = createRequire(import.meta.url);
@@ -36,6 +21,92 @@ function getOpt(name, def = "") {
36
21
  function hasFlag(name) {
37
22
  return args.includes(`--${name}`);
38
23
  }
24
+ async function handleSiteCommand() {
25
+ const validSub = /* @__PURE__ */ new Set(["dev", "build", "upload", "deploy"]);
26
+ const subCommand = args.slice(1).find((a) => validSub.has(a));
27
+ const port = Number(getOpt("port", "3000"));
28
+ const { resolve, dirname } = await import("path");
29
+ const { fileURLToPath } = await import("url");
30
+ const { writeFileSync } = await import("fs");
31
+ const { spawn } = await import("child_process");
32
+ const os = await import("os");
33
+ const thisFile = fileURLToPath(import.meta.url);
34
+ const pkgRoot = resolve(dirname(thisFile), "..");
35
+ const { existsSync: exists } = await import("fs");
36
+ let templateRoot;
37
+ const nmPath = resolve(pkgRoot, "node_modules", "@docs-i18n", "template");
38
+ if (exists(nmPath)) {
39
+ const { realpathSync } = await import("fs");
40
+ templateRoot = realpathSync(nmPath);
41
+ } else {
42
+ templateRoot = resolve(pkgRoot, "template");
43
+ }
44
+ const tmpFile = resolve(os.tmpdir(), "docs-i18n-project-root");
45
+ writeFileSync(tmpFile, process.cwd());
46
+ const { existsSync } = await import("fs");
47
+ const { execSync } = await import("child_process");
48
+ if (!existsSync(resolve(templateRoot, "node_modules"))) {
49
+ console.log("Installing template dependencies...");
50
+ execSync("npm install --no-audit --no-fund", {
51
+ cwd: templateRoot,
52
+ stdio: "inherit"
53
+ });
54
+ }
55
+ if (!subCommand || subCommand === "dev") {
56
+ const child = spawn("npx", ["vite", "--port", String(port)], {
57
+ cwd: templateRoot,
58
+ stdio: "inherit",
59
+ env: { ...process.env, DOCS_I18N_PROJECT_ROOT: process.cwd() },
60
+ shell: true
61
+ });
62
+ child.on("exit", (code) => process.exit(code ?? 0));
63
+ } else if (subCommand === "build") {
64
+ const child = spawn("npx", ["vite", "build"], {
65
+ cwd: templateRoot,
66
+ stdio: "inherit",
67
+ env: { ...process.env, DOCS_I18N_PROJECT_ROOT: process.cwd() },
68
+ shell: true
69
+ });
70
+ child.on("exit", (code) => process.exit(code ?? 0));
71
+ } else if (subCommand === "upload") {
72
+ console.log("Uploading content to D1...");
73
+ const { collectContentFiles, generateContentSql, collectTranslations, generateTranslationSql } = await import("./upload-XL6KG6S2.js");
74
+ const projectRoot = process.cwd();
75
+ const contentRows = collectContentFiles(projectRoot);
76
+ const contentSql = generateContentSql(contentRows);
77
+ console.log(`Collected ${contentRows.length} content files.`);
78
+ const translationData = collectTranslations(projectRoot);
79
+ const translationSql = generateTranslationSql(translationData);
80
+ console.log(`Collected ${translationData.sources.length} sources, ${translationData.translations.length} translations.`);
81
+ const allSql = [...contentSql, ...translationSql];
82
+ const sqlFile = resolve(os.tmpdir(), "docs-i18n-upload.sql");
83
+ writeFileSync(sqlFile, allSql.join("\n"));
84
+ const dbName = getOpt("db", "docs-i18n-db");
85
+ const child = spawn("npx", ["wrangler", "d1", "execute", dbName, "--file", sqlFile], {
86
+ cwd: templateRoot,
87
+ stdio: "inherit",
88
+ shell: true
89
+ });
90
+ child.on("exit", (code) => {
91
+ if (code === 0) {
92
+ console.log("Upload complete.");
93
+ }
94
+ process.exit(code ?? 0);
95
+ });
96
+ } else if (subCommand === "deploy") {
97
+ const child = spawn("npx", ["wrangler", "deploy"], {
98
+ cwd: templateRoot,
99
+ stdio: "inherit",
100
+ env: { ...process.env },
101
+ shell: true
102
+ });
103
+ child.on("exit", (code) => process.exit(code ?? 0));
104
+ } else {
105
+ console.error(`Unknown site subcommand: ${subCommand}`);
106
+ console.log("Usage: docs-i18n site [dev|build|upload|deploy]");
107
+ process.exit(1);
108
+ }
109
+ }
39
110
  async function main() {
40
111
  if (!command || command === "--help" || command === "-h") {
41
112
  console.log(`
@@ -47,6 +118,7 @@ Commands:
47
118
  rescan Rescan source files and clean orphans
48
119
  status Show translation coverage
49
120
  admin Start admin dashboard
121
+ site Manage documentation site (dev, build, upload, deploy)
50
122
 
51
123
  Options:
52
124
  --lang <code> Target language (e.g., zh-hans)
@@ -59,10 +131,14 @@ Options:
59
131
  --max-tokens <n> Max output tokens (default: 16384)
60
132
  --context-length <n> Model context window (default: 32768)
61
133
  --dry-run Preview without making changes
62
- --port <n> Admin dashboard port (default: 3456)
134
+ --port <n> Admin dashboard port (default: 3456) / Site dev port (default: 3000)
63
135
  `);
64
136
  return;
65
137
  }
138
+ if (command === "site") {
139
+ await handleSiteCommand();
140
+ return;
141
+ }
66
142
  const configPath = getOpt("config") || void 0;
67
143
  const config = await loadConfig(configPath);
68
144
  switch (command) {
@@ -72,7 +148,7 @@ Options:
72
148
  console.error("Error: --lang is required");
73
149
  process.exit(1);
74
150
  }
75
- const { translate } = await import("./translate-ZIVKNAC4.js");
151
+ const { translate } = await import("./translate-A5X6MX4Y.js");
76
152
  await translate(config, {
77
153
  lang,
78
154
  project: getOpt("project") || void 0,
@@ -89,7 +165,7 @@ Options:
89
165
  break;
90
166
  }
91
167
  case "assemble": {
92
- const { assembleAll } = await import("./assemble-7H4QCW35.js");
168
+ const { assembleAll } = await import("./assemble-CP2BRYQJ.js");
93
169
  await assembleAll(config, {
94
170
  project: getOpt("project") || void 0,
95
171
  version: getOpt("version") || void 0,
@@ -98,7 +174,7 @@ Options:
98
174
  break;
99
175
  }
100
176
  case "rescan": {
101
- const { rescan } = await import("./rescan-O5D3CYC2.js");
177
+ const { rescan } = await import("./rescan-HXMWFAOC.js");
102
178
  await rescan(config, {
103
179
  project: getOpt("project") || void 0,
104
180
  version: getOpt("version") || void 0
@@ -106,13 +182,22 @@ Options:
106
182
  break;
107
183
  }
108
184
  case "status": {
109
- const { status } = await import("./status-F4MYIAAY.js");
185
+ const { status } = await import("./status-AGZDXOTZ.js");
110
186
  await status(config, { lang: getOpt("lang") || void 0 });
111
187
  break;
112
188
  }
113
189
  case "admin": {
114
190
  const port = Number(getOpt("port", "3456"));
115
- const { startAdmin } = await import("./server-73AVSOL5.js");
191
+ const { resolve: res, dirname: dn } = await import("path");
192
+ const { fileURLToPath: toPath } = await import("url");
193
+ const { existsSync: ex, realpathSync: rp } = await import("fs");
194
+ const coreRoot = res(dn(toPath(import.meta.url)), "..");
195
+ const adminNm = res(coreRoot, "node_modules", "@docs-i18n", "admin");
196
+ const adminRoot = ex(adminNm) ? rp(adminNm) : res(coreRoot, "admin");
197
+ const { startAdmin } = await import(
198
+ /* @vite-ignore */
199
+ res(adminRoot, "server", "index.ts")
200
+ );
116
201
  await startAdmin(config, port);
117
202
  break;
118
203
  }