@life-and-dev/mdsite 0.0.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/README.md +228 -0
- package/bin/mdsite.js +3 -0
- package/dist/commands/commands.test.d.ts +1 -0
- package/dist/commands/commands.test.js +302 -0
- package/dist/commands/commands.test.js.map +1 -0
- package/dist/commands/generate.d.ts +1 -0
- package/dist/commands/generate.js +20 -0
- package/dist/commands/generate.js.map +1 -0
- package/dist/commands/init.d.ts +1 -0
- package/dist/commands/init.js +16 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/prepare.d.ts +1 -0
- package/dist/commands/prepare.js +111 -0
- package/dist/commands/prepare.js.map +1 -0
- package/dist/commands/prepare.test.d.ts +1 -0
- package/dist/commands/prepare.test.js +131 -0
- package/dist/commands/prepare.test.js.map +1 -0
- package/dist/commands/preview.d.ts +5 -0
- package/dist/commands/preview.js +62 -0
- package/dist/commands/preview.js.map +1 -0
- package/dist/commands/start.d.ts +5 -0
- package/dist/commands/start.js +50 -0
- package/dist/commands/start.js.map +1 -0
- package/dist/commands/stop.d.ts +1 -0
- package/dist/commands/stop.js +26 -0
- package/dist/commands/stop.js.map +1 -0
- package/dist/commands/workflows.test.d.ts +1 -0
- package/dist/commands/workflows.test.js +183 -0
- package/dist/commands/workflows.test.js.map +1 -0
- package/dist/config/default-mdsite-config.d.ts +2 -0
- package/dist/config/default-mdsite-config.js +82 -0
- package/dist/config/default-mdsite-config.js.map +1 -0
- package/dist/config/default-mdsite-config.test.d.ts +1 -0
- package/dist/config/default-mdsite-config.test.js +42 -0
- package/dist/config/default-mdsite-config.test.js.map +1 -0
- package/dist/config/mdsite-config.d.ts +42 -0
- package/dist/config/mdsite-config.js +74 -0
- package/dist/config/mdsite-config.js.map +1 -0
- package/dist/config/mdsite-config.test.d.ts +1 -0
- package/dist/config/mdsite-config.test.js +115 -0
- package/dist/config/mdsite-config.test.js.map +1 -0
- package/dist/config/menu.d.ts +3 -0
- package/dist/config/menu.js +58 -0
- package/dist/config/menu.js.map +1 -0
- package/dist/config/menu.test.d.ts +1 -0
- package/dist/config/menu.test.js +53 -0
- package/dist/config/menu.test.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +99 -0
- package/dist/index.js.map +1 -0
- package/dist/index.test.d.ts +1 -0
- package/dist/index.test.js +133 -0
- package/dist/index.test.js.map +1 -0
- package/dist/process/child-process.d.ts +9 -0
- package/dist/process/child-process.js +142 -0
- package/dist/process/child-process.js.map +1 -0
- package/dist/process/child-process.test.d.ts +1 -0
- package/dist/process/child-process.test.js +131 -0
- package/dist/process/child-process.test.js.map +1 -0
- package/dist/process/runtime-state.d.ts +16 -0
- package/dist/process/runtime-state.js +42 -0
- package/dist/process/runtime-state.js.map +1 -0
- package/dist/process/runtime-state.test.d.ts +1 -0
- package/dist/process/runtime-state.test.js +57 -0
- package/dist/process/runtime-state.test.js.map +1 -0
- package/dist/renderer/mdsite-nuxt.d.ts +22 -0
- package/dist/renderer/mdsite-nuxt.js +194 -0
- package/dist/renderer/mdsite-nuxt.js.map +1 -0
- package/dist/renderer/mdsite-nuxt.test.d.ts +1 -0
- package/dist/renderer/mdsite-nuxt.test.js +226 -0
- package/dist/renderer/mdsite-nuxt.test.js.map +1 -0
- package/mdsite-nuxt/app/app.vue +7 -0
- package/mdsite-nuxt/app/assets/css/bible-tooltips.css +87 -0
- package/mdsite-nuxt/app/assets/css/markdown.css +195 -0
- package/mdsite-nuxt/app/assets/css/print.css +133 -0
- package/mdsite-nuxt/app/components/AppBar.vue +138 -0
- package/mdsite-nuxt/app/components/AppFooter.vue +88 -0
- package/mdsite-nuxt/app/components/AppNavigation.vue +162 -0
- package/mdsite-nuxt/app/components/AppTableOfContents.vue +149 -0
- package/mdsite-nuxt/app/components/BreadcrumbNav.vue +139 -0
- package/mdsite-nuxt/app/components/NavigationTree.vue +169 -0
- package/mdsite-nuxt/app/components/SearchBox.vue +212 -0
- package/mdsite-nuxt/app/components/TocItem.vue +75 -0
- package/mdsite-nuxt/app/components/TreeNode.vue +264 -0
- package/mdsite-nuxt/app/components/content/MarkdownAlert.vue +42 -0
- package/mdsite-nuxt/app/components/content/Mermaid.vue +103 -0
- package/mdsite-nuxt/app/components/content/ProseA.vue +57 -0
- package/mdsite-nuxt/app/components/content/ProseBlockquote.vue +14 -0
- package/mdsite-nuxt/app/components/content/ProsePre.vue +49 -0
- package/mdsite-nuxt/app/components/content/ProseTable.vue +143 -0
- package/mdsite-nuxt/app/composables/useAppTheme.ts +89 -0
- package/mdsite-nuxt/app/composables/useBibleTooltips.ts +21 -0
- package/mdsite-nuxt/app/composables/useBreadcrumbs.ts +70 -0
- package/mdsite-nuxt/app/composables/useContentPostProcessing.ts +89 -0
- package/mdsite-nuxt/app/composables/useNavigationTree.ts +174 -0
- package/mdsite-nuxt/app/composables/useSearchIndex.ts +47 -0
- package/mdsite-nuxt/app/composables/useSearchRelevance.test.ts +255 -0
- package/mdsite-nuxt/app/composables/useSearchRelevance.ts +207 -0
- package/mdsite-nuxt/app/composables/useSidebarState.ts +62 -0
- package/mdsite-nuxt/app/composables/useSiteConfig.ts +37 -0
- package/mdsite-nuxt/app/composables/useSourceEdit.ts +69 -0
- package/mdsite-nuxt/app/composables/useTableOfContents.ts +141 -0
- package/mdsite-nuxt/app/composables/useTableParser.ts +106 -0
- package/mdsite-nuxt/app/composables/useTooltipConfig.ts +20 -0
- package/mdsite-nuxt/app/config/themes.ts +17 -0
- package/mdsite-nuxt/app/layouts/default.vue +376 -0
- package/mdsite-nuxt/app/pages/[...slug].vue +56 -0
- package/mdsite-nuxt/app/pages/index.vue +54 -0
- package/mdsite-nuxt/app/plugins/bible-tooltips.client.ts +401 -0
- package/mdsite-nuxt/app/plugins/bible-tooltips.test.ts +284 -0
- package/mdsite-nuxt/app/types/content.d.ts +10 -0
- package/mdsite-nuxt/app/types/table.ts +57 -0
- package/mdsite-nuxt/app/utils/bible-book-names.ts +37 -0
- package/mdsite-nuxt/app/utils/bible-verse-utils.test.ts +148 -0
- package/mdsite-nuxt/app/utils/bible-verse-utils.ts +236 -0
- package/mdsite-nuxt/content.config.ts +18 -0
- package/mdsite-nuxt/example.config.yml +67 -0
- package/mdsite-nuxt/nuxt.config.ts +247 -0
- package/mdsite-nuxt/package-lock.json +15922 -0
- package/mdsite-nuxt/package.json +50 -0
- package/mdsite-nuxt/playwright.config.js +47 -0
- package/mdsite-nuxt/public/robots.txt +2 -0
- package/mdsite-nuxt/scripts/generate-favicons.ts +192 -0
- package/mdsite-nuxt/scripts/generate-indices.ts +508 -0
- package/mdsite-nuxt/scripts/renderer-hooks.test.ts +277 -0
- package/mdsite-nuxt/scripts/renderer-hooks.ts +141 -0
- package/mdsite-nuxt/scripts/start.test.ts +164 -0
- package/mdsite-nuxt/scripts/start.ts +55 -0
- package/mdsite-nuxt/scripts/sync-content.ts +504 -0
- package/mdsite-nuxt/tsconfig.json +18 -0
- package/mdsite-nuxt/utils/mdsite-config.ts +240 -0
- package/mdsite-nuxt/vitest.config.ts +7 -0
- package/package.json +36 -0
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { mkdir, writeFile } from 'node:fs/promises';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { loadMdsiteConfig } from '../config/mdsite-config.js';
|
|
4
|
+
import { ensureConfiguredRendererInstalled, ensureRendererDependencies, prepareConfiguredRenderer, prepareRendererBackend } from '../renderer/mdsite-nuxt.js';
|
|
5
|
+
export async function runPrepareGithubCommand(contentDir) {
|
|
6
|
+
const loaded = await loadMdsiteConfig(contentDir);
|
|
7
|
+
await ensureConfiguredRendererInstalled(loaded.contentDir, loaded.config, loaded);
|
|
8
|
+
const { rendererDir, rendererEnv } = await prepareConfiguredRenderer(loaded.contentDir, loaded.config, loaded);
|
|
9
|
+
await ensureRendererDependencies(rendererDir);
|
|
10
|
+
await prepareRendererBackend(rendererDir, rendererEnv);
|
|
11
|
+
const workflowPath = path.join(contentDir, '.github', 'workflows', 'deploy.yml');
|
|
12
|
+
await mkdir(path.dirname(workflowPath), { recursive: true });
|
|
13
|
+
await writeFile(workflowPath, buildGithubWorkflow(loaded.config), 'utf8');
|
|
14
|
+
return `Generated GitHub Pages workflow at ${workflowPath}`;
|
|
15
|
+
}
|
|
16
|
+
function buildGithubWorkflow(config) {
|
|
17
|
+
const rendererPath = path.posix.normalize(config.server.path.replace(/\\/g, '/'));
|
|
18
|
+
const outputPath = path.posix.join(rendererPath, path.posix.normalize(config.server.output.replace(/\\/g, '/')));
|
|
19
|
+
const workflowName = `Deploy ${config.site.name} to GitHub Pages`;
|
|
20
|
+
const artifactPath = `./${outputPath}/public`;
|
|
21
|
+
const workspaceContentPath = config.content?.path ? `\${{ github.workspace }}/${path.posix.normalize(config.content.path.replace(/\\/g, '/'))}` : '${{ github.workspace }}';
|
|
22
|
+
return [
|
|
23
|
+
`name: ${JSON.stringify(workflowName)}`,
|
|
24
|
+
'',
|
|
25
|
+
'on:',
|
|
26
|
+
' push:',
|
|
27
|
+
' branches: ["main"]',
|
|
28
|
+
' workflow_dispatch:',
|
|
29
|
+
'',
|
|
30
|
+
'permissions:',
|
|
31
|
+
' contents: read',
|
|
32
|
+
' pages: write',
|
|
33
|
+
' id-token: write',
|
|
34
|
+
'',
|
|
35
|
+
'concurrency:',
|
|
36
|
+
' group: "pages"',
|
|
37
|
+
' cancel-in-progress: false',
|
|
38
|
+
'',
|
|
39
|
+
'jobs:',
|
|
40
|
+
' build:',
|
|
41
|
+
' runs-on: ubuntu-latest',
|
|
42
|
+
' env:',
|
|
43
|
+
` NUXT_CONTENT_PATH: "${workspaceContentPath}"`,
|
|
44
|
+
` CONTENT_DIR: "${workspaceContentPath}"`,
|
|
45
|
+
' MDSITE_CONFIG_PATH: "${{ github.workspace }}/mdsite.yml"',
|
|
46
|
+
' steps:',
|
|
47
|
+
' - name: Checkout',
|
|
48
|
+
' uses: actions/checkout@v4',
|
|
49
|
+
'',
|
|
50
|
+
' - name: Setup mdsite renderer',
|
|
51
|
+
' run: |',
|
|
52
|
+
' npm install --no-save mdsite',
|
|
53
|
+
" node <<'NODE'",
|
|
54
|
+
" const fs = require('node:fs')",
|
|
55
|
+
" const path = require('node:path')",
|
|
56
|
+
" const ignored = new Set(['node_modules', '.nuxt', '.output', 'dist', '.cache'])",
|
|
57
|
+
" const source = path.join(process.cwd(), 'node_modules', 'mdsite', 'mdsite-nuxt')",
|
|
58
|
+
` const target = path.join(process.cwd(), ${JSON.stringify(rendererPath)})`,
|
|
59
|
+
' fs.cpSync(source, target, { recursive: true, force: true, filter: (sourcePath) => !ignored.has(path.basename(sourcePath)) })',
|
|
60
|
+
' NODE',
|
|
61
|
+
'',
|
|
62
|
+
' - name: Setup Node',
|
|
63
|
+
' uses: actions/setup-node@v4',
|
|
64
|
+
' with:',
|
|
65
|
+
' node-version: "24"',
|
|
66
|
+
' cache: npm',
|
|
67
|
+
` cache-dependency-path: ${JSON.stringify(`${rendererPath}/package-lock.json`)}`,
|
|
68
|
+
'',
|
|
69
|
+
' - name: Setup Pages',
|
|
70
|
+
' id: pages',
|
|
71
|
+
' uses: actions/configure-pages@v5',
|
|
72
|
+
'',
|
|
73
|
+
' - name: Restore cache',
|
|
74
|
+
' uses: actions/cache@v4',
|
|
75
|
+
' with:',
|
|
76
|
+
' path: |',
|
|
77
|
+
` ${rendererPath}/node_modules`,
|
|
78
|
+
` ${rendererPath}/.nuxt`,
|
|
79
|
+
` ${outputPath}`,
|
|
80
|
+
" key: ${{ runner.os }}-nuxt-build-${{ hashFiles('" + rendererPath + "/package-lock.json') }}",
|
|
81
|
+
' restore-keys: |',
|
|
82
|
+
' ${{ runner.os }}-nuxt-build-',
|
|
83
|
+
'',
|
|
84
|
+
' - name: Install dependencies',
|
|
85
|
+
` working-directory: ${rendererPath}`,
|
|
86
|
+
' run: npm install',
|
|
87
|
+
'',
|
|
88
|
+
' - name: Generate static site',
|
|
89
|
+
` working-directory: ${rendererPath}`,
|
|
90
|
+
' run: npm run generate',
|
|
91
|
+
' env:',
|
|
92
|
+
' NUXT_APP_BASE_URL: ${{ steps.pages.outputs.base_path }}',
|
|
93
|
+
'',
|
|
94
|
+
' - name: Upload artifact',
|
|
95
|
+
' uses: actions/upload-pages-artifact@v3',
|
|
96
|
+
' with:',
|
|
97
|
+
` path: ${JSON.stringify(artifactPath)}`,
|
|
98
|
+
'',
|
|
99
|
+
' deploy:',
|
|
100
|
+
' environment:',
|
|
101
|
+
' name: github-pages',
|
|
102
|
+
' url: ${{ steps.deployment.outputs.page_url }}',
|
|
103
|
+
' runs-on: ubuntu-latest',
|
|
104
|
+
' needs: build',
|
|
105
|
+
' steps:',
|
|
106
|
+
' - name: Deploy to GitHub Pages',
|
|
107
|
+
' id: deployment',
|
|
108
|
+
' uses: actions/deploy-pages@v4'
|
|
109
|
+
].join('\n') + '\n';
|
|
110
|
+
}
|
|
111
|
+
//# sourceMappingURL=prepare.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prepare.js","sourceRoot":"","sources":["../../src/commands/prepare.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import os from 'node:os';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { mkdtemp, mkdir, readFile, rm, writeFile } from 'node:fs/promises';
|
|
4
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
5
|
+
vi.mock('../process/child-process.js', () => ({
|
|
6
|
+
runBackground: vi.fn(),
|
|
7
|
+
runForeground: vi.fn()
|
|
8
|
+
}));
|
|
9
|
+
import { runForeground } from '../process/child-process.js';
|
|
10
|
+
import { runPrepareGithubCommand } from './prepare.js';
|
|
11
|
+
const runForegroundMock = vi.mocked(runForeground);
|
|
12
|
+
describe('runPrepareGithubCommand', () => {
|
|
13
|
+
const tempDirs = [];
|
|
14
|
+
beforeEach(() => {
|
|
15
|
+
vi.clearAllMocks();
|
|
16
|
+
runForegroundMock.mockResolvedValue(undefined);
|
|
17
|
+
});
|
|
18
|
+
afterEach(async () => {
|
|
19
|
+
for (const tempDir of tempDirs.splice(0)) {
|
|
20
|
+
await rm(tempDir, { force: true, recursive: true });
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
it('reads mdsite.yml, generates in the configured renderer path, and writes the GitHub Pages workflow', async () => {
|
|
24
|
+
const contentDir = await mkdtemp(path.join(os.tmpdir(), 'mdsite-prepare-'));
|
|
25
|
+
tempDirs.push(contentDir);
|
|
26
|
+
const rendererDir = path.join(contentDir, 'renderer');
|
|
27
|
+
await mkdir(path.join(rendererDir, 'node_modules'), { recursive: true });
|
|
28
|
+
await writeFile(path.join(contentDir, 'mdsite.yml'), [
|
|
29
|
+
'site:',
|
|
30
|
+
' name: Example Docs',
|
|
31
|
+
'server:',
|
|
32
|
+
' path: renderer',
|
|
33
|
+
' output: build/site',
|
|
34
|
+
''
|
|
35
|
+
].join('\n'), 'utf8');
|
|
36
|
+
await writeFile(path.join(contentDir, 'index.md'), '# Example Docs\n', 'utf8');
|
|
37
|
+
await writeFile(path.join(contentDir, 'guide.md'), '# Guide\n', 'utf8');
|
|
38
|
+
const result = await runPrepareGithubCommand(contentDir);
|
|
39
|
+
const workflowPath = path.join(contentDir, '.github', 'workflows', 'deploy.yml');
|
|
40
|
+
const workflow = await readFile(workflowPath, 'utf8');
|
|
41
|
+
expect(result).toBe(`Generated GitHub Pages workflow at ${workflowPath}`);
|
|
42
|
+
expect(workflow).toContain('name: "Deploy Example Docs to GitHub Pages"');
|
|
43
|
+
expect(workflow).toContain('runs-on: ubuntu-latest');
|
|
44
|
+
expect(workflow).toContain('node-version: "24"');
|
|
45
|
+
expect(workflow).toContain('working-directory: renderer');
|
|
46
|
+
expect(workflow).toContain('NUXT_APP_BASE_URL: ${{ steps.pages.outputs.base_path }}');
|
|
47
|
+
expect(workflow).toContain('NUXT_CONTENT_PATH: "${{ github.workspace }}"');
|
|
48
|
+
expect(workflow).toContain('CONTENT_DIR: "${{ github.workspace }}"');
|
|
49
|
+
expect(workflow).toContain('MDSITE_CONFIG_PATH: "${{ github.workspace }}/mdsite.yml"');
|
|
50
|
+
expect(workflow).toContain('cache-dependency-path: "renderer/package-lock.json"');
|
|
51
|
+
expect(workflow).toContain('name: Setup mdsite renderer');
|
|
52
|
+
expect(workflow).toContain('npm install --no-save mdsite');
|
|
53
|
+
expect(workflow).toContain("node_modules', 'mdsite', 'mdsite-nuxt");
|
|
54
|
+
expect(workflow).toContain('renderer/build/site');
|
|
55
|
+
expect(workflow).toContain('path: "./renderer/build/site/public"');
|
|
56
|
+
expect(workflow).toContain('run: npm run generate');
|
|
57
|
+
expect(workflow).not.toContain('npm start -- --generate');
|
|
58
|
+
expect(workflow).toContain('actions/upload-pages-artifact@v3');
|
|
59
|
+
expect(workflow).toContain('actions/deploy-pages@v4');
|
|
60
|
+
expect(runForegroundMock).toHaveBeenCalledTimes(1);
|
|
61
|
+
expect(runForegroundMock).toHaveBeenCalledWith('npm', ['run', 'prepare:renderer'], rendererDir, expect.objectContaining({
|
|
62
|
+
CONTENT_DIR: contentDir,
|
|
63
|
+
MDSITE_CONFIG_PATH: path.join(contentDir, 'mdsite.yml'),
|
|
64
|
+
NUXT_CONTENT_PATH: contentDir
|
|
65
|
+
}));
|
|
66
|
+
});
|
|
67
|
+
it('writes GitHub workflow paths for a root config with content.path', async () => {
|
|
68
|
+
const configDir = await mkdtemp(path.join(os.tmpdir(), 'mdsite-prepare-'));
|
|
69
|
+
tempDirs.push(configDir);
|
|
70
|
+
const contentDir = path.join(configDir, 'docs');
|
|
71
|
+
const rendererDir = path.join(configDir, 'renderer');
|
|
72
|
+
await mkdir(path.join(contentDir), { recursive: true });
|
|
73
|
+
await mkdir(path.join(rendererDir, 'node_modules'), { recursive: true });
|
|
74
|
+
await writeFile(path.join(configDir, 'mdsite.yml'), [
|
|
75
|
+
'content:',
|
|
76
|
+
' path: docs',
|
|
77
|
+
'site:',
|
|
78
|
+
' name: Root Docs',
|
|
79
|
+
'server:',
|
|
80
|
+
' path: renderer',
|
|
81
|
+
' output: build/site',
|
|
82
|
+
''
|
|
83
|
+
].join('\n'), 'utf8');
|
|
84
|
+
await writeFile(path.join(contentDir, 'index.md'), '# Root Docs\n', 'utf8');
|
|
85
|
+
await runPrepareGithubCommand(configDir);
|
|
86
|
+
const workflow = await readFile(path.join(configDir, '.github', 'workflows', 'deploy.yml'), 'utf8');
|
|
87
|
+
expect(workflow).toContain('NUXT_CONTENT_PATH: "${{ github.workspace }}/docs"');
|
|
88
|
+
expect(workflow).toContain('CONTENT_DIR: "${{ github.workspace }}/docs"');
|
|
89
|
+
expect(workflow).toContain('MDSITE_CONFIG_PATH: "${{ github.workspace }}/mdsite.yml"');
|
|
90
|
+
expect(workflow).toContain('working-directory: renderer');
|
|
91
|
+
expect(workflow).toContain('node-version: "24"');
|
|
92
|
+
expect(workflow).toContain('run: npm run generate');
|
|
93
|
+
expect(workflow).not.toContain('npm start -- --generate');
|
|
94
|
+
expect(workflow).toContain('path: "./renderer/build/site/public"');
|
|
95
|
+
expect(runForegroundMock).toHaveBeenCalledWith('npm', ['run', 'prepare:renderer'], rendererDir, expect.objectContaining({
|
|
96
|
+
CONTENT_DIR: contentDir,
|
|
97
|
+
MDSITE_CONFIG_PATH: path.join(configDir, 'mdsite.yml'),
|
|
98
|
+
NUXT_CONTENT_PATH: contentDir
|
|
99
|
+
}));
|
|
100
|
+
});
|
|
101
|
+
it('creates the configured renderer before preparing the GitHub workflow', async () => {
|
|
102
|
+
const contentDir = await mkdtemp(path.join(os.tmpdir(), 'mdsite-prepare-'));
|
|
103
|
+
tempDirs.push(contentDir);
|
|
104
|
+
const rendererDir = path.join(contentDir, '.mdsite');
|
|
105
|
+
await writeFile(path.join(contentDir, 'mdsite.yml'), [
|
|
106
|
+
'site:',
|
|
107
|
+
' name: Default Renderer Docs',
|
|
108
|
+
'server:',
|
|
109
|
+
' path: .mdsite',
|
|
110
|
+
' output: .output',
|
|
111
|
+
''
|
|
112
|
+
].join('\n'), 'utf8');
|
|
113
|
+
await writeFile(path.join(contentDir, 'index.md'), '# Default Renderer Docs\n', 'utf8');
|
|
114
|
+
await runPrepareGithubCommand(contentDir);
|
|
115
|
+
const workflow = await readFile(path.join(contentDir, '.github', 'workflows', 'deploy.yml'), 'utf8');
|
|
116
|
+
expect(await readFile(path.join(rendererDir, 'package.json'), 'utf8')).toContain('mdsite-nuxt');
|
|
117
|
+
expect(workflow).toContain('working-directory: .mdsite');
|
|
118
|
+
expect(workflow).toContain('node-version: "24"');
|
|
119
|
+
expect(workflow).toContain('cache-dependency-path: ".mdsite/package-lock.json"');
|
|
120
|
+
expect(workflow).toContain('path: "./.mdsite/.output/public"');
|
|
121
|
+
expect(workflow).toContain('run: npm run generate');
|
|
122
|
+
expect(workflow).not.toContain('npm start -- --generate');
|
|
123
|
+
expect(runForegroundMock).toHaveBeenCalledWith('npm', ['ci'], rendererDir, process.env);
|
|
124
|
+
expect(runForegroundMock).toHaveBeenCalledWith('npm', ['run', 'prepare:renderer'], rendererDir, expect.objectContaining({
|
|
125
|
+
CONTENT_DIR: contentDir,
|
|
126
|
+
MDSITE_CONFIG_PATH: path.join(contentDir, 'mdsite.yml'),
|
|
127
|
+
NUXT_CONTENT_PATH: contentDir
|
|
128
|
+
}));
|
|
129
|
+
});
|
|
130
|
+
});
|
|
131
|
+
//# sourceMappingURL=prepare.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prepare.test.js","sourceRoot":"","sources":["../../src/commands/prepare.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { loadMdsiteConfig } from '../config/mdsite-config.js';
|
|
2
|
+
import { openUrlInBrowser, waitForTcpPort } from '../process/child-process.js';
|
|
3
|
+
import { getRuntimeLogPath, isProcessRunning, readRuntimeState, writeRuntimeState } from '../process/runtime-state.js';
|
|
4
|
+
import { ensurePreviewArtifacts, ensureRendererDependencies, prepareRenderer, previewRendererForeground, previewRendererInBackground } from '../renderer/mdsite-nuxt.js';
|
|
5
|
+
export async function runPreviewCommand(contentDir, options = {}) {
|
|
6
|
+
if (options.detached) {
|
|
7
|
+
return runDetachedPreviewCommand(contentDir);
|
|
8
|
+
}
|
|
9
|
+
const loaded = await loadMdsiteConfig(contentDir);
|
|
10
|
+
const { rendererDir, rendererEnv } = await prepareRenderer(loaded.contentDir, loaded.config, loaded);
|
|
11
|
+
await ensureRendererDependencies(rendererDir);
|
|
12
|
+
await ensurePreviewArtifacts(rendererDir);
|
|
13
|
+
await previewRendererForeground(rendererDir, getPreviewEnv(rendererEnv));
|
|
14
|
+
return undefined;
|
|
15
|
+
}
|
|
16
|
+
async function runDetachedPreviewCommand(contentDir) {
|
|
17
|
+
const existingState = await readRuntimeState(contentDir, 'preview');
|
|
18
|
+
if (existingState && isProcessRunning(existingState.pid)) {
|
|
19
|
+
throw new Error(`mdsite preview is already running with PID ${existingState.pid}.`);
|
|
20
|
+
}
|
|
21
|
+
const loaded = await loadMdsiteConfig(contentDir);
|
|
22
|
+
const { rendererDir, rendererEnv } = await prepareRenderer(loaded.contentDir, loaded.config, loaded);
|
|
23
|
+
await ensureRendererDependencies(rendererDir);
|
|
24
|
+
await ensurePreviewArtifacts(rendererDir);
|
|
25
|
+
const previewEnv = getPreviewEnv(rendererEnv);
|
|
26
|
+
const logPath = getRuntimeLogPath(contentDir, 'preview');
|
|
27
|
+
const pid = await previewRendererInBackground(rendererDir, previewEnv, logPath);
|
|
28
|
+
const previewUrl = getPreviewUrl(previewEnv);
|
|
29
|
+
await writeRuntimeState(contentDir, {
|
|
30
|
+
kind: 'preview',
|
|
31
|
+
pid,
|
|
32
|
+
logPath,
|
|
33
|
+
rendererDir,
|
|
34
|
+
contentDir,
|
|
35
|
+
command: ['npm', 'run', 'preview'],
|
|
36
|
+
startedAt: new Date().toISOString()
|
|
37
|
+
});
|
|
38
|
+
const previewReady = await waitForTcpPort(previewEnv.HOST ?? 'localhost', Number.parseInt(previewEnv.PORT ?? '3000', 10)).catch(() => false);
|
|
39
|
+
if (previewReady) {
|
|
40
|
+
await openUrlInBrowser(previewUrl);
|
|
41
|
+
}
|
|
42
|
+
return `mdsite preview running in background (PID ${pid}). URL: ${previewUrl} Log: ${logPath}`;
|
|
43
|
+
}
|
|
44
|
+
function getPreviewUrl(env) {
|
|
45
|
+
const host = env.NUXT_HOST ?? env.HOST ?? 'localhost';
|
|
46
|
+
const port = env.NUXT_PORT ?? env.PORT ?? '3000';
|
|
47
|
+
return `http://${host}:${port}`;
|
|
48
|
+
}
|
|
49
|
+
function getPreviewEnv(env) {
|
|
50
|
+
const host = env.NUXT_HOST ?? env.HOST ?? 'localhost';
|
|
51
|
+
const port = env.NUXT_PORT ?? env.PORT ?? '3000';
|
|
52
|
+
return {
|
|
53
|
+
...env,
|
|
54
|
+
NUXT_HOST: host,
|
|
55
|
+
NUXT_PORT: port,
|
|
56
|
+
HOST: host,
|
|
57
|
+
PORT: port,
|
|
58
|
+
NITRO_HOST: host,
|
|
59
|
+
NITRO_PORT: port
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
//# sourceMappingURL=preview.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"preview.js","sourceRoot":"","sources":["../../src/commands/preview.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAA;AAC7D,OAAO,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAA;AAC9E,OAAO,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAA;AACtH,OAAO,EAAE,sBAAsB,EAAE,0BAA0B,EAAE,eAAe,EAAE,yBAAyB,EAAE,2BAA2B,EAAE,MAAM,4BAA4B,CAAA;AAMxK,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,UAAkB,EAAE,UAAiC,EAAE;IAC7F,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;QACrB,OAAO,yBAAyB,CAAC,UAAU,CAAC,CAAA;IAC9C,CAAC;IAED,MAAM,MAAM,GAAG,MAAM,gBAAgB,CAAC,UAAU,CAAC,CAAA;IACjD,MAAM,EAAE,WAAW,EAAE,WAAW,EAAE,GAAG,MAAM,eAAe,CAAC,MAAM,CAAC,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAEpG,MAAM,0BAA0B,CAAC,WAAW,CAAC,CAAA;IAC7C,MAAM,sBAAsB,CAAC,WAAW,CAAC,CAAA;IACzC,MAAM,yBAAyB,CAAC,WAAW,EAAE,aAAa,CAAC,WAAW,CAAC,CAAC,CAAA;IAExE,OAAO,SAAS,CAAA;AAClB,CAAC;AAED,KAAK,UAAU,yBAAyB,CAAC,UAAkB;IACzD,MAAM,aAAa,GAAG,MAAM,gBAAgB,CAAC,UAAU,EAAE,SAAS,CAAC,CAAA;IACnE,IAAI,aAAa,IAAI,gBAAgB,CAAC,aAAa,CAAC,GAAG,CAAC,EAAE,CAAC;QACzD,MAAM,IAAI,KAAK,CAAC,8CAA8C,aAAa,CAAC,GAAG,GAAG,CAAC,CAAA;IACrF,CAAC;IAED,MAAM,MAAM,GAAG,MAAM,gBAAgB,CAAC,UAAU,CAAC,CAAA;IACjD,MAAM,EAAE,WAAW,EAAE,WAAW,EAAE,GAAG,MAAM,eAAe,CAAC,MAAM,CAAC,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAEpG,MAAM,0BAA0B,CAAC,WAAW,CAAC,CAAA;IAC7C,MAAM,sBAAsB,CAAC,WAAW,CAAC,CAAA;IAEzC,MAAM,UAAU,GAAG,aAAa,CAAC,WAAW,CAAC,CAAA;IAC7C,MAAM,OAAO,GAAG,iBAAiB,CAAC,UAAU,EAAE,SAAS,CAAC,CAAA;IACxD,MAAM,GAAG,GAAG,MAAM,2BAA2B,CAAC,WAAW,EAAE,UAAU,EAAE,OAAO,CAAC,CAAA;IAC/E,MAAM,UAAU,GAAG,aAAa,CAAC,UAAU,CAAC,CAAA;IAE5C,MAAM,iBAAiB,CAAC,UAAU,EAAE;QAClC,IAAI,EAAE,SAAS;QACf,GAAG;QACH,OAAO;QACP,WAAW;QACX,UAAU;QACV,OAAO,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,SAAS,CAAC;QAClC,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;KACpC,CAAC,CAAA;IAEF,MAAM,YAAY,GAAG,MAAM,cAAc,CAAC,UAAU,CAAC,IAAI,IAAI,WAAW,EAAE,MAAM,CAAC,QAAQ,CAAC,UAAU,CAAC,IAAI,IAAI,MAAM,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC,CAAA;IAC5I,IAAI,YAAY,EAAE,CAAC;QACjB,MAAM,gBAAgB,CAAC,UAAU,CAAC,CAAA;IACpC,CAAC;IAED,OAAO,6CAA6C,GAAG,WAAW,UAAU,SAAS,OAAO,EAAE,CAAA;AAChG,CAAC;AAED,SAAS,aAAa,CAAC,GAAsB;IAC3C,MAAM,IAAI,GAAG,GAAG,CAAC,SAAS,IAAI,GAAG,CAAC,IAAI,IAAI,WAAW,CAAA;IACrD,MAAM,IAAI,GAAG,GAAG,CAAC,SAAS,IAAI,GAAG,CAAC,IAAI,IAAI,MAAM,CAAA;IAEhD,OAAO,UAAU,IAAI,IAAI,IAAI,EAAE,CAAA;AACjC,CAAC;AAED,SAAS,aAAa,CAAC,GAAsB;IAC3C,MAAM,IAAI,GAAG,GAAG,CAAC,SAAS,IAAI,GAAG,CAAC,IAAI,IAAI,WAAW,CAAA;IACrD,MAAM,IAAI,GAAG,GAAG,CAAC,SAAS,IAAI,GAAG,CAAC,IAAI,IAAI,MAAM,CAAA;IAEhD,OAAO;QACL,GAAG,GAAG;QACN,SAAS,EAAE,IAAI;QACf,SAAS,EAAE,IAAI;QACf,IAAI,EAAE,IAAI;QACV,IAAI,EAAE,IAAI;QACV,UAAU,EAAE,IAAI;QAChB,UAAU,EAAE,IAAI;KACjB,CAAA;AACH,CAAC"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { loadMdsiteConfig } from '../config/mdsite-config.js';
|
|
2
|
+
import { openUrlInBrowser, waitForTcpPort } from '../process/child-process.js';
|
|
3
|
+
import { getRuntimeLogPath, isProcessRunning, readRuntimeState, writeRuntimeState } from '../process/runtime-state.js';
|
|
4
|
+
import { ensureRendererDependencies, prepareRenderer, startRendererForeground, startRendererInBackground } from '../renderer/mdsite-nuxt.js';
|
|
5
|
+
export async function runStartCommand(contentDir, options = {}) {
|
|
6
|
+
if (options.detached) {
|
|
7
|
+
return runDetachedStartCommand(contentDir);
|
|
8
|
+
}
|
|
9
|
+
const loaded = await loadMdsiteConfig(contentDir);
|
|
10
|
+
const { rendererDir, rendererEnv } = await prepareRenderer(loaded.contentDir, loaded.config, loaded);
|
|
11
|
+
await ensureRendererDependencies(rendererDir);
|
|
12
|
+
await startRendererForeground(rendererDir, rendererEnv);
|
|
13
|
+
return undefined;
|
|
14
|
+
}
|
|
15
|
+
async function runDetachedStartCommand(contentDir) {
|
|
16
|
+
const existingState = await readRuntimeState(contentDir, 'start');
|
|
17
|
+
if (existingState && isProcessRunning(existingState.pid)) {
|
|
18
|
+
throw new Error(`mdsite start is already running with PID ${existingState.pid}.`);
|
|
19
|
+
}
|
|
20
|
+
const loaded = await loadMdsiteConfig(contentDir);
|
|
21
|
+
const { rendererDir, rendererEnv } = await prepareRenderer(loaded.contentDir, loaded.config, loaded);
|
|
22
|
+
await ensureRendererDependencies(rendererDir);
|
|
23
|
+
const logPath = getRuntimeLogPath(contentDir, 'start');
|
|
24
|
+
const pid = await startRendererInBackground(rendererDir, rendererEnv, logPath);
|
|
25
|
+
const startUrl = getStartUrl(rendererEnv);
|
|
26
|
+
await writeRuntimeState(contentDir, {
|
|
27
|
+
kind: 'start',
|
|
28
|
+
pid,
|
|
29
|
+
logPath,
|
|
30
|
+
rendererDir,
|
|
31
|
+
contentDir,
|
|
32
|
+
command: ['npm', 'run', 'dev'],
|
|
33
|
+
startedAt: new Date().toISOString()
|
|
34
|
+
});
|
|
35
|
+
const startReady = await waitForTcpPort(getStartHost(rendererEnv), Number.parseInt(getStartPort(rendererEnv), 10)).catch(() => false);
|
|
36
|
+
if (startReady) {
|
|
37
|
+
await openUrlInBrowser(startUrl);
|
|
38
|
+
}
|
|
39
|
+
return `mdsite start running in background (PID ${pid}). Log: ${logPath}`;
|
|
40
|
+
}
|
|
41
|
+
function getStartUrl(env) {
|
|
42
|
+
return `http://${getStartHost(env)}:${getStartPort(env)}`;
|
|
43
|
+
}
|
|
44
|
+
function getStartHost(env) {
|
|
45
|
+
return env.NUXT_HOST ?? env.HOST ?? 'localhost';
|
|
46
|
+
}
|
|
47
|
+
function getStartPort(env) {
|
|
48
|
+
return env.NUXT_PORT ?? env.PORT ?? '3000';
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=start.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"start.js","sourceRoot":"","sources":["../../src/commands/start.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function runStopCommand(contentDir: string): Promise<string>;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { clearRuntimeState, readRuntimeState } from '../process/runtime-state.js';
|
|
2
|
+
import { stopProcess } from '../process/child-process.js';
|
|
3
|
+
export async function runStopCommand(contentDir) {
|
|
4
|
+
const states = await Promise.all([
|
|
5
|
+
readRuntimeState(contentDir, 'start'),
|
|
6
|
+
readRuntimeState(contentDir, 'preview')
|
|
7
|
+
]);
|
|
8
|
+
const messages = [];
|
|
9
|
+
for (const state of states) {
|
|
10
|
+
if (!state) {
|
|
11
|
+
continue;
|
|
12
|
+
}
|
|
13
|
+
const stopped = await stopProcess(state.pid);
|
|
14
|
+
await clearRuntimeState(contentDir, state.kind);
|
|
15
|
+
if (stopped) {
|
|
16
|
+
messages.push(`Stopped ${state.kind} process ${state.pid}.`);
|
|
17
|
+
continue;
|
|
18
|
+
}
|
|
19
|
+
messages.push(`Removed stale ${state.kind} state for PID ${state.pid}.`);
|
|
20
|
+
}
|
|
21
|
+
if (messages.length === 0) {
|
|
22
|
+
return 'Nothing is running.';
|
|
23
|
+
}
|
|
24
|
+
return messages.join(' ');
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=stop.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stop.js","sourceRoot":"","sources":["../../src/commands/stop.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAA;AACjF,OAAO,EAAE,WAAW,EAAE,MAAM,6BAA6B,CAAA;AAEzD,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,UAAkB;IACrD,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;QAC/B,gBAAgB,CAAC,UAAU,EAAE,OAAO,CAAC;QACrC,gBAAgB,CAAC,UAAU,EAAE,SAAS,CAAC;KACxC,CAAC,CAAA;IAEF,MAAM,QAAQ,GAAa,EAAE,CAAA;IAE7B,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,SAAQ;QACV,CAAC;QAED,MAAM,OAAO,GAAG,MAAM,WAAW,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;QAC5C,MAAM,iBAAiB,CAAC,UAAU,EAAE,KAAK,CAAC,IAAI,CAAC,CAAA;QAE/C,IAAI,OAAO,EAAE,CAAC;YACZ,QAAQ,CAAC,IAAI,CAAC,WAAW,KAAK,CAAC,IAAI,YAAY,KAAK,CAAC,GAAG,GAAG,CAAC,CAAA;YAC5D,SAAQ;QACV,CAAC;QAED,QAAQ,CAAC,IAAI,CAAC,iBAAiB,KAAK,CAAC,IAAI,kBAAkB,KAAK,CAAC,GAAG,GAAG,CAAC,CAAA;IAC1E,CAAC;IAED,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC1B,OAAO,qBAAqB,CAAA;IAC9B,CAAC;IAED,OAAO,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;AAC3B,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
import { access, mkdir, mkdtemp, readFile, rm, writeFile } from 'node:fs/promises';
|
|
2
|
+
import os from 'node:os';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
5
|
+
const waitForTcpPortMock = vi.hoisted(() => vi.fn());
|
|
6
|
+
vi.mock('../process/child-process.js', () => ({
|
|
7
|
+
openUrlInBrowser: vi.fn(),
|
|
8
|
+
runBackground: vi.fn(),
|
|
9
|
+
runForeground: vi.fn(),
|
|
10
|
+
waitForTcpPort: waitForTcpPortMock,
|
|
11
|
+
stopProcess: vi.fn()
|
|
12
|
+
}));
|
|
13
|
+
import { serializeMdsiteConfig } from '../config/mdsite-config.js';
|
|
14
|
+
import { openUrlInBrowser, stopProcess, waitForTcpPort, runBackground, runForeground } from '../process/child-process.js';
|
|
15
|
+
import { readRuntimeState } from '../process/runtime-state.js';
|
|
16
|
+
import { runGenerateCommand } from './generate.js';
|
|
17
|
+
import { runInitCommand } from './init.js';
|
|
18
|
+
import { runPreviewCommand } from './preview.js';
|
|
19
|
+
import { runStartCommand } from './start.js';
|
|
20
|
+
import { runStopCommand } from './stop.js';
|
|
21
|
+
const runBackgroundMock = vi.mocked(runBackground);
|
|
22
|
+
const runForegroundMock = vi.mocked(runForeground);
|
|
23
|
+
const openUrlInBrowserMock = vi.mocked(openUrlInBrowser);
|
|
24
|
+
const stopProcessMock = vi.mocked(stopProcess);
|
|
25
|
+
const waitForTcpPortMocked = vi.mocked(waitForTcpPort);
|
|
26
|
+
const tempDirs = [];
|
|
27
|
+
async function makeTempDir() {
|
|
28
|
+
const dir = await mkdtemp(path.join(os.tmpdir(), 'mdsite-workflows-'));
|
|
29
|
+
tempDirs.push(dir);
|
|
30
|
+
return dir;
|
|
31
|
+
}
|
|
32
|
+
async function createContentDir() {
|
|
33
|
+
const contentDir = await makeTempDir();
|
|
34
|
+
await mkdir(path.join(contentDir, 'docs'), { recursive: true });
|
|
35
|
+
await writeFile(path.join(contentDir, 'index.md'), '# Workspace Docs\n', 'utf8');
|
|
36
|
+
await writeFile(path.join(contentDir, 'docs', 'guide.md'), '# Guide\n', 'utf8');
|
|
37
|
+
return contentDir;
|
|
38
|
+
}
|
|
39
|
+
async function createRendererDir(contentDir, withNodeModules = true) {
|
|
40
|
+
const rendererDir = path.join(contentDir, '.renderer');
|
|
41
|
+
await mkdir(rendererDir, { recursive: true });
|
|
42
|
+
if (withNodeModules) {
|
|
43
|
+
await mkdir(path.join(rendererDir, 'node_modules'), { recursive: true });
|
|
44
|
+
}
|
|
45
|
+
return rendererDir;
|
|
46
|
+
}
|
|
47
|
+
async function writeConfig(contentDir, overrides = {}) {
|
|
48
|
+
const config = {
|
|
49
|
+
favicon: '',
|
|
50
|
+
features: { bibleTooltips: true, sourceEdit: true },
|
|
51
|
+
menu: [],
|
|
52
|
+
server: {
|
|
53
|
+
output: '.output',
|
|
54
|
+
path: '.renderer',
|
|
55
|
+
repo: 'https://github.com/life-and-dev/mdsite',
|
|
56
|
+
...overrides.server
|
|
57
|
+
},
|
|
58
|
+
site: {
|
|
59
|
+
canonical: '',
|
|
60
|
+
name: 'Workspace Docs',
|
|
61
|
+
...overrides.site
|
|
62
|
+
},
|
|
63
|
+
themes: {
|
|
64
|
+
light: { colors: {} },
|
|
65
|
+
dark: { colors: {} }
|
|
66
|
+
},
|
|
67
|
+
...overrides
|
|
68
|
+
};
|
|
69
|
+
await writeFile(path.join(contentDir, 'mdsite.yml'), serializeMdsiteConfig(config), 'utf8');
|
|
70
|
+
return config;
|
|
71
|
+
}
|
|
72
|
+
afterEach(async () => {
|
|
73
|
+
vi.restoreAllMocks();
|
|
74
|
+
await Promise.all(tempDirs.splice(0).map((dir) => rm(dir, { recursive: true, force: true })));
|
|
75
|
+
});
|
|
76
|
+
describe('CLI workflow coverage', () => {
|
|
77
|
+
beforeEach(() => {
|
|
78
|
+
vi.clearAllMocks();
|
|
79
|
+
openUrlInBrowserMock.mockResolvedValue(true);
|
|
80
|
+
waitForTcpPortMocked.mockResolvedValue(true);
|
|
81
|
+
});
|
|
82
|
+
it('runInitCommand creates a valid mdsite.yml for the current markdown directory', async () => {
|
|
83
|
+
const contentDir = await createContentDir();
|
|
84
|
+
await expect(runInitCommand(contentDir)).resolves.toBeUndefined();
|
|
85
|
+
const configPath = path.join(contentDir, 'mdsite.yml');
|
|
86
|
+
const configText = await readFile(configPath, 'utf8');
|
|
87
|
+
expect(configText).toContain('name: Workspace Docs');
|
|
88
|
+
expect(configText).toContain('output: .output');
|
|
89
|
+
expect(configText).toContain('- docs/guide');
|
|
90
|
+
});
|
|
91
|
+
it('runStartCommand in detached mode prepares the renderer against the current markdown directory and tracks the background process', async () => {
|
|
92
|
+
const contentDir = await createContentDir();
|
|
93
|
+
const rendererDir = await createRendererDir(contentDir);
|
|
94
|
+
await writeConfig(contentDir);
|
|
95
|
+
runBackgroundMock.mockResolvedValueOnce(4321);
|
|
96
|
+
await expect(runStartCommand(contentDir, { detached: true })).resolves.toBe(`mdsite start running in background (PID 4321). Log: ${path.join(contentDir, '.mdsite-runtime', 'start.log')}`);
|
|
97
|
+
expect(runBackgroundMock).toHaveBeenCalledWith('npm', ['run', 'dev'], rendererDir, expect.objectContaining({
|
|
98
|
+
NUXT_CONTENT_PATH: contentDir,
|
|
99
|
+
CONTENT_DIR: contentDir,
|
|
100
|
+
MDSITE_CONFIG_PATH: path.join(contentDir, 'mdsite.yml')
|
|
101
|
+
}), path.join(contentDir, '.mdsite-runtime', 'start.log'));
|
|
102
|
+
expect(waitForTcpPortMocked).toHaveBeenCalledWith('localhost', 3000);
|
|
103
|
+
expect(openUrlInBrowserMock).toHaveBeenCalledWith('http://localhost:3000');
|
|
104
|
+
expect(await readFile(path.join(contentDir, '_menu.yml'), 'utf8')).toContain('- docs/guide');
|
|
105
|
+
expect(await readFile(path.join(rendererDir, '.env'), 'utf8')).toContain(`NUXT_CONTENT_PATH=${JSON.stringify(contentDir)}`);
|
|
106
|
+
expect(await readFile(path.join(rendererDir, 'content.config.yml'), 'utf8')).toContain('siteName: Workspace Docs');
|
|
107
|
+
await expect(readRuntimeState(contentDir, 'start')).resolves.toEqual(expect.objectContaining({
|
|
108
|
+
pid: 4321,
|
|
109
|
+
rendererDir,
|
|
110
|
+
contentDir,
|
|
111
|
+
command: ['npm', 'run', 'dev']
|
|
112
|
+
}));
|
|
113
|
+
});
|
|
114
|
+
it('runGenerateCommand writes generated output to the configured destination', async () => {
|
|
115
|
+
const contentDir = await createContentDir();
|
|
116
|
+
const rendererDir = await createRendererDir(contentDir);
|
|
117
|
+
await writeConfig(contentDir, {
|
|
118
|
+
server: {
|
|
119
|
+
output: 'public/site',
|
|
120
|
+
path: '.renderer',
|
|
121
|
+
repo: 'https://github.com/life-and-dev/mdsite'
|
|
122
|
+
}
|
|
123
|
+
});
|
|
124
|
+
runForegroundMock.mockImplementation(async (_command, args, cwd) => {
|
|
125
|
+
if (args[0] === 'run' && args[1] === 'generate') {
|
|
126
|
+
await mkdir(path.join(cwd, '.output', 'public'), { recursive: true });
|
|
127
|
+
await writeFile(path.join(cwd, '.output', 'public', 'index.html'), '<h1>generated</h1>', 'utf8');
|
|
128
|
+
}
|
|
129
|
+
});
|
|
130
|
+
await expect(runGenerateCommand(contentDir)).resolves.toBe(`Generated site synced to ${path.join(contentDir, 'public', 'site')}`);
|
|
131
|
+
expect(await readFile(path.join(contentDir, 'public', 'site', 'index.html'), 'utf8')).toBe('<h1>generated</h1>');
|
|
132
|
+
expect(runForegroundMock).toHaveBeenCalledWith('npm', ['run', 'generate'], rendererDir, expect.objectContaining({
|
|
133
|
+
NUXT_CONTENT_PATH: contentDir
|
|
134
|
+
}));
|
|
135
|
+
});
|
|
136
|
+
it('runPreviewCommand works after runGenerateCommand creates only the public artifact', async () => {
|
|
137
|
+
const contentDir = await createContentDir();
|
|
138
|
+
const rendererDir = await createRendererDir(contentDir);
|
|
139
|
+
await writeConfig(contentDir);
|
|
140
|
+
runForegroundMock.mockImplementation(async (_command, args, cwd) => {
|
|
141
|
+
if (args[0] === 'run' && args[1] === 'generate') {
|
|
142
|
+
await mkdir(path.join(cwd, '.output', 'public'), { recursive: true });
|
|
143
|
+
await writeFile(path.join(cwd, '.output', 'public', 'index.html'), '<h1>generated</h1>', 'utf8');
|
|
144
|
+
}
|
|
145
|
+
});
|
|
146
|
+
await expect(runGenerateCommand(contentDir)).resolves.toBe(`Generated site synced to ${path.join(contentDir, '.output')}`);
|
|
147
|
+
runBackgroundMock.mockResolvedValueOnce(2468);
|
|
148
|
+
stopProcessMock.mockResolvedValueOnce(true);
|
|
149
|
+
await expect(runPreviewCommand(contentDir, { detached: true })).resolves.toBe(`mdsite preview running in background (PID 2468). URL: http://localhost:3000 Log: ${path.join(contentDir, 'mdsite.log')}`);
|
|
150
|
+
expect(openUrlInBrowserMock).toHaveBeenCalledWith('http://localhost:3000');
|
|
151
|
+
await expect(runStopCommand(contentDir)).resolves.toBe('Stopped preview process 2468.');
|
|
152
|
+
await expect(readRuntimeState(contentDir, 'preview')).resolves.toBeNull();
|
|
153
|
+
});
|
|
154
|
+
it('rejects start when mdsite.yml is missing', async () => {
|
|
155
|
+
const contentDir = await createContentDir();
|
|
156
|
+
await expect(runStartCommand(contentDir)).rejects.toThrow(`Missing mdsite.yml in ${contentDir}. Run \`mdsite init\` first.`);
|
|
157
|
+
});
|
|
158
|
+
it('rejects invalid config files before starting the renderer', async () => {
|
|
159
|
+
const contentDir = await createContentDir();
|
|
160
|
+
await writeFile(path.join(contentDir, 'mdsite.yml'), 'site: [broken\n', 'utf8');
|
|
161
|
+
await expect(runStartCommand(contentDir)).rejects.toThrow();
|
|
162
|
+
await expect(readRuntimeState(contentDir, 'start')).resolves.toBeNull();
|
|
163
|
+
});
|
|
164
|
+
it('surfaces install failures and does not persist start state', async () => {
|
|
165
|
+
const contentDir = await createContentDir();
|
|
166
|
+
await createRendererDir(contentDir, false);
|
|
167
|
+
await writeConfig(contentDir);
|
|
168
|
+
runForegroundMock.mockRejectedValueOnce(new Error('npm install failed'));
|
|
169
|
+
await expect(runStartCommand(contentDir)).rejects.toThrow('npm install failed');
|
|
170
|
+
await expect(readRuntimeState(contentDir, 'start')).resolves.toBeNull();
|
|
171
|
+
});
|
|
172
|
+
it('does not leave tracked start state or logs behind when foreground renderer fails to boot', async () => {
|
|
173
|
+
const contentDir = await createContentDir();
|
|
174
|
+
await createRendererDir(contentDir);
|
|
175
|
+
await writeConfig(contentDir);
|
|
176
|
+
runForegroundMock.mockRejectedValueOnce(new Error('Failed to start npm run dev.'));
|
|
177
|
+
await expect(runStartCommand(contentDir)).rejects.toThrow('Failed to start npm run dev.');
|
|
178
|
+
await expect(readRuntimeState(contentDir, 'start')).resolves.toBeNull();
|
|
179
|
+
await expect(access(path.join(contentDir, '.mdsite-runtime', 'start.json'))).rejects.toThrow();
|
|
180
|
+
await expect(access(path.join(contentDir, '.mdsite-runtime', 'start.log'))).rejects.toThrow();
|
|
181
|
+
});
|
|
182
|
+
});
|
|
183
|
+
//# sourceMappingURL=workflows.test.js.map
|