@doxbrix/doxloop-generator-markdoc 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/LICENSE +93 -0
- package/README.md +64 -0
- package/dist/index.d.ts +31 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +257 -0
- package/dist/index.js.map +1 -0
- package/package.json +49 -0
- package/skills/doxloop-markdoc/SKILL.md +37 -0
- package/skills/doxloop-markdoc/agents/openai.yaml +4 -0
- package/skills/doxloop-markdoc/references/project-format.md +35 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
DOXLOOP PROPRIETARY SOFTWARE LICENSE
|
|
2
|
+
Version 1.0, 21 July 2026
|
|
3
|
+
|
|
4
|
+
Copyright (c) 2026 Doxbrix. All rights reserved.
|
|
5
|
+
|
|
6
|
+
1. Definitions
|
|
7
|
+
|
|
8
|
+
"Software" means the Doxloop software and all source code, object code,
|
|
9
|
+
documentation, assets, and other materials distributed with this license.
|
|
10
|
+
|
|
11
|
+
2. Limited License to Use
|
|
12
|
+
|
|
13
|
+
Subject to your compliance with this license, Doxbrix grants you a worldwide,
|
|
14
|
+
royalty-free, non-exclusive, non-transferable, and non-sublicensable license to
|
|
15
|
+
download, install, and run unmodified copies of the Software for any lawful
|
|
16
|
+
personal or commercial purpose.
|
|
17
|
+
|
|
18
|
+
You may make only the copies technically necessary to download, install, run,
|
|
19
|
+
and back up the Software. No other rights are granted.
|
|
20
|
+
|
|
21
|
+
3. Restrictions
|
|
22
|
+
|
|
23
|
+
Unless you first obtain explicit written permission from Doxbrix, you may not:
|
|
24
|
+
|
|
25
|
+
a. copy or reproduce the Software except as expressly permitted in Section 2;
|
|
26
|
+
b. modify, adapt, translate, or create derivative works of the Software;
|
|
27
|
+
c. distribute, publish, sublicense, sell, rent, lease, transfer, mirror,
|
|
28
|
+
repackage, or otherwise make the Software or any part of it available to
|
|
29
|
+
another person or entity;
|
|
30
|
+
d. incorporate any source code from the Software into another work, product,
|
|
31
|
+
or service;
|
|
32
|
+
e. remove, alter, or obscure any copyright, license, attribution, or other
|
|
33
|
+
proprietary notice; or
|
|
34
|
+
f. reverse engineer, decompile, or disassemble the Software, except to the
|
|
35
|
+
limited extent that applicable law expressly permits despite this
|
|
36
|
+
restriction.
|
|
37
|
+
|
|
38
|
+
For clarity, prohibited redistribution includes publishing a copy or fork of
|
|
39
|
+
the source code outside the rights that GitHub's Terms of Service require for a
|
|
40
|
+
public repository, and republishing any Doxloop package or a modified version
|
|
41
|
+
of it to a package registry.
|
|
42
|
+
|
|
43
|
+
4. GitHub Public Repository Rights
|
|
44
|
+
|
|
45
|
+
If the Software is made available in a public repository on GitHub, GitHub and
|
|
46
|
+
GitHub users receive the limited rights required by GitHub's applicable Terms
|
|
47
|
+
of Service, including rights to view and fork the repository through GitHub's
|
|
48
|
+
service. Those platform rights do not grant permission to use, copy, modify, or
|
|
49
|
+
redistribute the Software beyond GitHub's service or beyond the permissions in
|
|
50
|
+
Section 2.
|
|
51
|
+
|
|
52
|
+
5. Ownership and Reservation of Rights
|
|
53
|
+
|
|
54
|
+
The Software is licensed, not sold. Doxbrix and its licensors retain all
|
|
55
|
+
right, title, and interest in and to the Software. All rights not expressly
|
|
56
|
+
granted by this license are reserved. No patent, trademark, or other license is
|
|
57
|
+
granted by implication or estoppel.
|
|
58
|
+
|
|
59
|
+
6. Third-Party Materials
|
|
60
|
+
|
|
61
|
+
Third-party software and materials included with or used by the Software remain
|
|
62
|
+
subject to their respective licenses. This license does not restrict any rights
|
|
63
|
+
granted under those third-party licenses.
|
|
64
|
+
|
|
65
|
+
7. Termination
|
|
66
|
+
|
|
67
|
+
This license terminates automatically if you violate any of its terms. Upon
|
|
68
|
+
termination, you must stop using the Software and delete all copies in your
|
|
69
|
+
possession or control, except copies that applicable law requires you to keep.
|
|
70
|
+
|
|
71
|
+
8. Disclaimer of Warranty
|
|
72
|
+
|
|
73
|
+
THE SOFTWARE IS PROVIDED "AS IS" AND "AS AVAILABLE," WITHOUT WARRANTIES OR
|
|
74
|
+
CONDITIONS OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING WARRANTIES OF
|
|
75
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE, AND NON-INFRINGEMENT.
|
|
76
|
+
|
|
77
|
+
9. Limitation of Liability
|
|
78
|
+
|
|
79
|
+
TO THE MAXIMUM EXTENT PERMITTED BY LAW, DOXBRIX AND ITS LICENSORS WILL NOT BE
|
|
80
|
+
LIABLE FOR ANY INDIRECT, INCIDENTAL, SPECIAL, CONSEQUENTIAL, EXEMPLARY, OR
|
|
81
|
+
PUNITIVE DAMAGES, OR FOR ANY LOSS OF DATA, PROFITS, REVENUE, BUSINESS, OR
|
|
82
|
+
GOODWILL, ARISING FROM OR RELATED TO THE SOFTWARE OR THIS LICENSE, REGARDLESS OF
|
|
83
|
+
THE THEORY OF LIABILITY AND EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
|
|
84
|
+
|
|
85
|
+
10. Severability
|
|
86
|
+
|
|
87
|
+
If any provision of this license is held unenforceable, that provision will be
|
|
88
|
+
enforced to the maximum extent permitted and the remaining provisions will
|
|
89
|
+
remain in effect.
|
|
90
|
+
|
|
91
|
+
Use of the Software indicates acceptance of this license. For permissions not
|
|
92
|
+
granted here, contact Doxbrix and obtain explicit written permission before
|
|
93
|
+
proceeding.
|
package/README.md
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# @doxbrix/doxloop-generator-markdoc
|
|
2
|
+
|
|
3
|
+
Markdoc support for [Doxloop](https://github.com/doxbrix/doxloop). This package
|
|
4
|
+
connects Doxloop to a native Markdoc documentation project and includes the
|
|
5
|
+
`doxloop-markdoc` authoring skill used by supported coding agents.
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
Install the Doxloop CLI and this generator in your documentation project:
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
npm install --save-dev \
|
|
13
|
+
@doxbrix/doxloop \
|
|
14
|
+
@doxbrix/doxloop-generator-markdoc
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Node.js 20.12 or later is required.
|
|
18
|
+
|
|
19
|
+
## Create documentation
|
|
20
|
+
|
|
21
|
+
Initialize a Markdoc documentation project and connect the product source that
|
|
22
|
+
Doxloop should research:
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
npx doxloop init . \
|
|
26
|
+
--source product=../my-product \
|
|
27
|
+
--generator markdoc
|
|
28
|
+
|
|
29
|
+
npx doxloop create
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Doxloop scaffolds Markdoc configuration, content, generator-native navigation,
|
|
33
|
+
and the project-local authoring skill.
|
|
34
|
+
|
|
35
|
+
## Use with an existing project
|
|
36
|
+
|
|
37
|
+
Install Markdoc support in an existing Doxloop project with:
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
npx doxloop generator add markdoc
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
Adding the package does not convert existing content or change the generator
|
|
44
|
+
selected in `.doxloop/project.json`.
|
|
45
|
+
|
|
46
|
+
## Preview and verify
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
npx doxloop preview --open
|
|
50
|
+
npx doxloop test
|
|
51
|
+
npm run build
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
| Detail | Value |
|
|
55
|
+
| --- | --- |
|
|
56
|
+
| Content | Markdoc (`.md`) |
|
|
57
|
+
| Native build | `npm run build` |
|
|
58
|
+
| Build output | `dist/` |
|
|
59
|
+
|
|
60
|
+
Run `npx doxloop generator info markdoc` to inspect the installed adapter.
|
|
61
|
+
|
|
62
|
+
## License
|
|
63
|
+
|
|
64
|
+
[Doxloop Proprietary Software License](./LICENSE)
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { type GeneratorPreviewOptions, type GeneratorScaffoldContext, type GeneratorValidationContext, type ValidationIssue } from '@doxbrix/doxloop/generator-api';
|
|
2
|
+
declare const adapter: {
|
|
3
|
+
apiVersion: 1;
|
|
4
|
+
id: string;
|
|
5
|
+
displayName: string;
|
|
6
|
+
packageName: string;
|
|
7
|
+
packageVersion: string;
|
|
8
|
+
authoring: {
|
|
9
|
+
skillName: string;
|
|
10
|
+
skillDirectory: string;
|
|
11
|
+
};
|
|
12
|
+
project: {
|
|
13
|
+
defaultContentDir: string;
|
|
14
|
+
pageExtensions: string[];
|
|
15
|
+
gitignore: string[];
|
|
16
|
+
contentFormat: "markdown";
|
|
17
|
+
};
|
|
18
|
+
build: {
|
|
19
|
+
command: string;
|
|
20
|
+
outputDir: string;
|
|
21
|
+
};
|
|
22
|
+
scaffold: typeof scaffoldMarkdoc;
|
|
23
|
+
preview: typeof startMarkdocPreview;
|
|
24
|
+
resolveLocalAsset({ root, reference }: import("@doxbrix/doxloop/generator-api").GeneratorAssetContext): string | undefined;
|
|
25
|
+
validate: typeof validateMarkdoc;
|
|
26
|
+
};
|
|
27
|
+
export default adapter;
|
|
28
|
+
declare function scaffoldMarkdoc(context: GeneratorScaffoldContext): Promise<void>;
|
|
29
|
+
declare function startMarkdocPreview(options: GeneratorPreviewOptions): Promise<void>;
|
|
30
|
+
declare function validateMarkdoc(context: GeneratorValidationContext): Promise<ValidationIssue[]>;
|
|
31
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAIA,OAAO,EAGL,KAAK,uBAAuB,EAC5B,KAAK,wBAAwB,EAC7B,KAAK,0BAA0B,EAC/B,KAAK,eAAe,EACrB,MAAM,gCAAgC,CAAA;AAoBvC,QAAA,MAAM,OAAO;;;;;;;;;;;;;;;;;;;;;;;;CA2BX,CAAA;AAEF,eAAe,OAAO,CAAA;AAEtB,iBAAe,eAAe,CAAC,OAAO,EAAE,wBAAwB,GAAG,OAAO,CAAC,IAAI,CAAC,CAyJ/E;AAED,iBAAe,mBAAmB,CAAC,OAAO,EAAE,uBAAuB,GAAG,OAAO,CAAC,IAAI,CAAC,CASlF;AAED,iBAAe,eAAe,CAC5B,OAAO,EAAE,0BAA0B,GAClC,OAAO,CAAC,eAAe,EAAE,CAAC,CA0E5B"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
import { readFileSync } from 'node:fs';
|
|
2
|
+
import { mkdir, readFile, writeFile } from 'node:fs/promises';
|
|
3
|
+
import { join, relative } from 'node:path';
|
|
4
|
+
import { fileURLToPath } from 'node:url';
|
|
5
|
+
import { DoxloopError, defineGenerator, } from '@doxbrix/doxloop/generator-api';
|
|
6
|
+
import { ensureNodeModule, isRecord, pathExists, readPackageJson, resolvePublicAsset, runCommand, serveStaticDirectory, slugFromTitle, writeJsonFile, } from '@doxbrix/doxloop/generator-runtime';
|
|
7
|
+
const PACKAGE_NAME = '@doxbrix/doxloop-generator-markdoc';
|
|
8
|
+
const PACKAGE_VERSION = JSON.parse(readFileSync(new URL('../package.json', import.meta.url), 'utf8')).version;
|
|
9
|
+
const adapter = defineGenerator({
|
|
10
|
+
apiVersion: 1,
|
|
11
|
+
id: 'markdoc',
|
|
12
|
+
displayName: 'Markdoc',
|
|
13
|
+
packageName: PACKAGE_NAME,
|
|
14
|
+
packageVersion: PACKAGE_VERSION,
|
|
15
|
+
authoring: {
|
|
16
|
+
skillName: 'doxloop-markdoc',
|
|
17
|
+
skillDirectory: fileURLToPath(new URL('../skills/doxloop-markdoc', import.meta.url)),
|
|
18
|
+
},
|
|
19
|
+
project: {
|
|
20
|
+
defaultContentDir: 'docs',
|
|
21
|
+
pageExtensions: ['.md'],
|
|
22
|
+
gitignore: ['dist/', 'node_modules/'],
|
|
23
|
+
contentFormat: 'markdown',
|
|
24
|
+
},
|
|
25
|
+
build: { command: 'npm run build', outputDir: 'dist' },
|
|
26
|
+
scaffold: scaffoldMarkdoc,
|
|
27
|
+
preview: startMarkdocPreview,
|
|
28
|
+
resolveLocalAsset({ root, reference }) {
|
|
29
|
+
return reference.startsWith('/assets/')
|
|
30
|
+
? resolvePublicAsset(root, 'assets', reference.slice('/assets'.length))
|
|
31
|
+
: undefined;
|
|
32
|
+
},
|
|
33
|
+
validate: validateMarkdoc,
|
|
34
|
+
});
|
|
35
|
+
export default adapter;
|
|
36
|
+
async function scaffoldMarkdoc(context) {
|
|
37
|
+
const { root, title, contentDir } = context;
|
|
38
|
+
await mkdir(join(root, contentDir), { recursive: true });
|
|
39
|
+
await mkdir(join(root, 'scripts'), { recursive: true });
|
|
40
|
+
await mkdir(join(root, 'assets'), { recursive: true });
|
|
41
|
+
await mkdir(join(root, 'assets', 'guides'), { recursive: true });
|
|
42
|
+
const existing = await readPackageJson(root);
|
|
43
|
+
await writeJsonFile(join(root, 'package.json'), {
|
|
44
|
+
...existing,
|
|
45
|
+
name: typeof existing.name === 'string' && existing.name
|
|
46
|
+
? existing.name
|
|
47
|
+
: slugFromTitle(title),
|
|
48
|
+
private: true,
|
|
49
|
+
version: typeof existing.version === 'string' && existing.version
|
|
50
|
+
? existing.version
|
|
51
|
+
: '0.0.0',
|
|
52
|
+
type: 'module',
|
|
53
|
+
scripts: {
|
|
54
|
+
...(isRecord(existing.scripts) ? existing.scripts : {}),
|
|
55
|
+
dev: 'doxloop preview',
|
|
56
|
+
build: 'node scripts/build.mjs',
|
|
57
|
+
'docs:test': 'doxloop test',
|
|
58
|
+
},
|
|
59
|
+
dependencies: {
|
|
60
|
+
...(isRecord(existing.dependencies) ? existing.dependencies : {}),
|
|
61
|
+
'@markdoc/markdoc': '0.5.8',
|
|
62
|
+
'gray-matter': '4.0.3',
|
|
63
|
+
},
|
|
64
|
+
devDependencies: {
|
|
65
|
+
...(isRecord(existing.devDependencies) ? existing.devDependencies : {}),
|
|
66
|
+
[context.corePackage.name]: `^${context.corePackage.version}`,
|
|
67
|
+
[context.generatorPackage.name]: `^${context.generatorPackage.version}`,
|
|
68
|
+
},
|
|
69
|
+
engines: {
|
|
70
|
+
...(isRecord(existing.engines) ? existing.engines : {}),
|
|
71
|
+
node: '>=20.12.0',
|
|
72
|
+
},
|
|
73
|
+
});
|
|
74
|
+
await writeFile(join(root, 'markdoc.config.mjs'), `export default {
|
|
75
|
+
tags: {
|
|
76
|
+
callout: {
|
|
77
|
+
render: 'aside',
|
|
78
|
+
attributes: {
|
|
79
|
+
title: { type: String },
|
|
80
|
+
},
|
|
81
|
+
},
|
|
82
|
+
},
|
|
83
|
+
}
|
|
84
|
+
`, { encoding: 'utf8', flag: 'wx' });
|
|
85
|
+
await writeJsonFile(join(root, 'navigation.json'), [
|
|
86
|
+
{ title: title, file: 'index.md', href: '/' },
|
|
87
|
+
{ title: 'Quickstart', file: 'quickstart.md', href: '/quickstart/' },
|
|
88
|
+
]);
|
|
89
|
+
await writeFile(join(root, 'assets', 'site.css'), `:root { font-family: Inter, system-ui, sans-serif; --brand: #4f46e5; color: #1f2937; }
|
|
90
|
+
body { margin: 0; } header { border-bottom: 1px solid #e5e7eb; padding: 1rem 2rem; }
|
|
91
|
+
.brand { color: var(--brand); font-weight: 700; text-decoration: none; }
|
|
92
|
+
.markdoc-layout { display: grid; grid-template-columns: 16rem minmax(0, 48rem); gap: 3rem; max-width: 72rem; margin: 0 auto; padding: 2rem; }
|
|
93
|
+
nav ul { list-style: none; padding: 0; } nav a { display: block; padding: .5rem; }
|
|
94
|
+
.markdoc-content { line-height: 1.7; min-width: 0; } aside { border-left: 4px solid var(--brand); padding: 1rem; background: #eef2ff; }
|
|
95
|
+
pre { overflow: auto; padding: 1rem; background: #111827; color: #f9fafb; border-radius: .5rem; }
|
|
96
|
+
@media (max-width: 720px) { .markdoc-layout { grid-template-columns: 1fr; } }
|
|
97
|
+
`, { encoding: 'utf8', flag: 'wx' });
|
|
98
|
+
await writeFile(join(root, 'scripts', 'build.mjs'), `import { cp, mkdir, readFile, rm, writeFile } from 'node:fs/promises'
|
|
99
|
+
import { dirname, join } from 'node:path'
|
|
100
|
+
import Markdoc from '@markdoc/markdoc'
|
|
101
|
+
import matter from 'gray-matter'
|
|
102
|
+
import config from '../markdoc.config.mjs'
|
|
103
|
+
|
|
104
|
+
const root = process.cwd()
|
|
105
|
+
const navigation = JSON.parse(await readFile(join(root, 'navigation.json'), 'utf8'))
|
|
106
|
+
const output = join(root, 'dist')
|
|
107
|
+
await rm(output, { recursive: true, force: true })
|
|
108
|
+
await mkdir(output, { recursive: true })
|
|
109
|
+
|
|
110
|
+
const escapeHtml = (value) => String(value).replace(/[&<>"']/g, (character) => ({
|
|
111
|
+
'&': '&', '<': '<', '>': '>', '"': '"', "'": ''',
|
|
112
|
+
})[character])
|
|
113
|
+
|
|
114
|
+
for (const item of navigation) {
|
|
115
|
+
const sourcePath = join(root, ${JSON.stringify(contentDir)}, item.file)
|
|
116
|
+
const parsed = matter(await readFile(sourcePath, 'utf8'))
|
|
117
|
+
const ast = Markdoc.parse(parsed.content)
|
|
118
|
+
const errors = Markdoc.validate(ast, config)
|
|
119
|
+
if (errors.length > 0) {
|
|
120
|
+
throw new Error(\`\${item.file}: \${errors.map((error) => error.error?.message ?? error.type).join(', ')}\`)
|
|
121
|
+
}
|
|
122
|
+
const rendered = Markdoc.renderers.html(Markdoc.transform(ast, config))
|
|
123
|
+
const target = item.href === '/' ? join(output, 'index.html') : join(output, item.href, 'index.html')
|
|
124
|
+
await mkdir(dirname(target), { recursive: true })
|
|
125
|
+
const nav = navigation.map((entry) => \`<li><a href="\${entry.href}">\${escapeHtml(entry.title)}</a></li>\`).join('')
|
|
126
|
+
const title = parsed.data.title ?? item.title
|
|
127
|
+
const description = parsed.data.description ?? ''
|
|
128
|
+
await writeFile(target, \`<!doctype html>
|
|
129
|
+
<html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1">
|
|
130
|
+
<meta name="description" content="\${escapeHtml(description)}"><title>\${escapeHtml(title)}</title><link rel="stylesheet" href="/site.css"></head>
|
|
131
|
+
<body><header><a class="brand" href="/">${escapeForTemplate(title)}</a></header><div class="markdoc-layout">
|
|
132
|
+
<aside class="markdoc-sidebar"><nav aria-label="Documentation"><ul>\${nav}</ul></nav></aside>
|
|
133
|
+
<main class="markdoc-content"><article>\${rendered}</article></main></div></body></html>\`)
|
|
134
|
+
}
|
|
135
|
+
await cp(join(root, 'assets', 'site.css'), join(output, 'site.css'))
|
|
136
|
+
await cp(join(root, 'assets', 'guides'), join(output, 'assets', 'guides'), { recursive: true })
|
|
137
|
+
console.log(\`Built \${navigation.length} Markdoc pages in dist/\`)
|
|
138
|
+
`, { encoding: 'utf8', flag: 'wx' });
|
|
139
|
+
await writeFile(join(root, contentDir, 'index.md'), `---
|
|
140
|
+
title: ${JSON.stringify(title)}
|
|
141
|
+
description: "Understand what ${title} helps you accomplish and choose your first workflow."
|
|
142
|
+
---
|
|
143
|
+
|
|
144
|
+
# ${title}
|
|
145
|
+
|
|
146
|
+
<!-- doxloop:starter-page -->
|
|
147
|
+
|
|
148
|
+
{% callout title="Starter content" %}
|
|
149
|
+
The authoring agent will replace this starter with an evidence-backed product overview.
|
|
150
|
+
{% /callout %}
|
|
151
|
+
|
|
152
|
+
[Follow the quickstart](/quickstart/) to reach your first successful result.
|
|
153
|
+
`, { encoding: 'utf8', flag: 'wx' });
|
|
154
|
+
await writeFile(join(root, contentDir, 'quickstart.md'), `---
|
|
155
|
+
title: "Quickstart"
|
|
156
|
+
description: "Reach your first successful result with verified product instructions."
|
|
157
|
+
---
|
|
158
|
+
|
|
159
|
+
# Quickstart
|
|
160
|
+
|
|
161
|
+
<!-- doxloop:starter-page -->
|
|
162
|
+
|
|
163
|
+
1. Confirm prerequisites from the configured product source.
|
|
164
|
+
2. Complete the first supported workflow.
|
|
165
|
+
3. Verify the observable result.
|
|
166
|
+
`, { encoding: 'utf8', flag: 'wx' });
|
|
167
|
+
}
|
|
168
|
+
async function startMarkdocPreview(options) {
|
|
169
|
+
await ensureNodeModule(options.root, '@markdoc/markdoc/package.json', 'Markdoc');
|
|
170
|
+
const code = await runCommand(process.execPath, [join(options.root, 'scripts', 'build.mjs')], options.root);
|
|
171
|
+
if (code !== 0)
|
|
172
|
+
throw new DoxloopError('Markdoc build failed.', 2);
|
|
173
|
+
await serveStaticDirectory(options, 'dist', 'Markdoc');
|
|
174
|
+
}
|
|
175
|
+
async function validateMarkdoc(context) {
|
|
176
|
+
const issues = [];
|
|
177
|
+
for (const file of [
|
|
178
|
+
'package.json',
|
|
179
|
+
'markdoc.config.mjs',
|
|
180
|
+
'navigation.json',
|
|
181
|
+
'scripts/build.mjs',
|
|
182
|
+
]) {
|
|
183
|
+
if (!(await pathExists(join(context.root, file)))) {
|
|
184
|
+
issues.push({
|
|
185
|
+
severity: 'error',
|
|
186
|
+
code: 'missing-generator-file',
|
|
187
|
+
message: `Markdoc project is missing ${file}.`,
|
|
188
|
+
file,
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
const navigationPath = join(context.root, 'navigation.json');
|
|
193
|
+
if (!(await pathExists(navigationPath)))
|
|
194
|
+
return issues;
|
|
195
|
+
let navigation;
|
|
196
|
+
try {
|
|
197
|
+
navigation = JSON.parse(await readFile(navigationPath, 'utf8'));
|
|
198
|
+
}
|
|
199
|
+
catch (error) {
|
|
200
|
+
return [
|
|
201
|
+
...issues,
|
|
202
|
+
{
|
|
203
|
+
severity: 'error',
|
|
204
|
+
code: 'generator-config',
|
|
205
|
+
message: `Cannot parse navigation.json: ${errorMessage(error)}`,
|
|
206
|
+
file: 'navigation.json',
|
|
207
|
+
},
|
|
208
|
+
];
|
|
209
|
+
}
|
|
210
|
+
if (!Array.isArray(navigation)) {
|
|
211
|
+
issues.push({
|
|
212
|
+
severity: 'error',
|
|
213
|
+
code: 'generator-config',
|
|
214
|
+
message: 'navigation.json must contain an array.',
|
|
215
|
+
file: 'navigation.json',
|
|
216
|
+
});
|
|
217
|
+
return issues;
|
|
218
|
+
}
|
|
219
|
+
const navigationFiles = new Set(navigation
|
|
220
|
+
.filter(isRecord)
|
|
221
|
+
.map((item) => item.file)
|
|
222
|
+
.filter((file) => typeof file === 'string'));
|
|
223
|
+
const pageFiles = new Set(context.pages.map((page) => relative(context.contentRoot, page).split('\\').join('/')));
|
|
224
|
+
for (const file of navigationFiles) {
|
|
225
|
+
if (!pageFiles.has(file)) {
|
|
226
|
+
issues.push({
|
|
227
|
+
severity: 'error',
|
|
228
|
+
code: 'missing-page',
|
|
229
|
+
message: `Markdoc navigation references missing page "${file}".`,
|
|
230
|
+
file: 'navigation.json',
|
|
231
|
+
});
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
for (const file of pageFiles) {
|
|
235
|
+
if (!navigationFiles.has(file)) {
|
|
236
|
+
issues.push({
|
|
237
|
+
severity: 'error',
|
|
238
|
+
code: 'unnavigated-page',
|
|
239
|
+
message: `Page "${file}" is not in Markdoc navigation.`,
|
|
240
|
+
file,
|
|
241
|
+
});
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
return issues;
|
|
245
|
+
}
|
|
246
|
+
function escapeForTemplate(value) {
|
|
247
|
+
return value
|
|
248
|
+
.replaceAll('&', '&')
|
|
249
|
+
.replaceAll('<', '<')
|
|
250
|
+
.replaceAll('>', '>')
|
|
251
|
+
.replaceAll('"', '"')
|
|
252
|
+
.replaceAll("'", ''');
|
|
253
|
+
}
|
|
254
|
+
function errorMessage(error) {
|
|
255
|
+
return error instanceof Error ? error.message : String(error);
|
|
256
|
+
}
|
|
257
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@doxbrix/doxloop-generator-markdoc",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Markdoc generator adapter and authoring skill for Doxloop.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"license": "SEE LICENSE IN LICENSE",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "git+https://github.com/doxbrix/doxloop.git",
|
|
10
|
+
"directory": "packages/generator-markdoc"
|
|
11
|
+
},
|
|
12
|
+
"exports": {
|
|
13
|
+
".": {
|
|
14
|
+
"types": "./dist/index.d.ts",
|
|
15
|
+
"import": "./dist/index.js",
|
|
16
|
+
"default": "./dist/index.js"
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
"files": [
|
|
20
|
+
"dist",
|
|
21
|
+
"skills"
|
|
22
|
+
],
|
|
23
|
+
"doxloop": {
|
|
24
|
+
"type": "generator",
|
|
25
|
+
"apiVersion": 1,
|
|
26
|
+
"id": "markdoc",
|
|
27
|
+
"skill": "./skills/doxloop-markdoc"
|
|
28
|
+
},
|
|
29
|
+
"publishConfig": {
|
|
30
|
+
"registry": "https://registry.npmjs.org",
|
|
31
|
+
"access": "public"
|
|
32
|
+
},
|
|
33
|
+
"peerDependencies": {
|
|
34
|
+
"@doxbrix/doxloop": "^0.1.0"
|
|
35
|
+
},
|
|
36
|
+
"devDependencies": {
|
|
37
|
+
"@types/node": "^22.15.3",
|
|
38
|
+
"typescript": "^5.8.3",
|
|
39
|
+
"@doxbrix/doxloop": "0.1.0"
|
|
40
|
+
},
|
|
41
|
+
"engines": {
|
|
42
|
+
"node": ">=20.12.0"
|
|
43
|
+
},
|
|
44
|
+
"scripts": {
|
|
45
|
+
"build": "rm -rf dist && tsc -p tsconfig.json",
|
|
46
|
+
"typecheck": "tsc --noEmit -p tsconfig.json",
|
|
47
|
+
"validate:skill": "python3 ../../scripts/validate-skill.py skills/doxloop-markdoc"
|
|
48
|
+
}
|
|
49
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: doxloop-markdoc
|
|
3
|
+
description: Author and maintain native Markdoc documentation, including Markdown, Markdoc tags, schemas, navigation metadata, renderer-safe content, and static output. Use for Doxloop projects whose generator is markdoc.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Doxloop Markdoc
|
|
7
|
+
|
|
8
|
+
Use this skill with `$doxloop-authoring`. Use only tags, nodes, and schemas
|
|
9
|
+
registered by the Markdoc project.
|
|
10
|
+
|
|
11
|
+
## Work natively
|
|
12
|
+
|
|
13
|
+
1. Confirm `.doxloop/project.json` selects `markdoc`.
|
|
14
|
+
2. Read [references/project-format.md](references/project-format.md).
|
|
15
|
+
3. Inspect `markdoc.config.mjs`, `navigation.json`, the renderer, and existing
|
|
16
|
+
pages.
|
|
17
|
+
4. Keep pages in `docs/` with `title` and outcome-focused `description`.
|
|
18
|
+
5. Maintain navigation and stable routes when pages change.
|
|
19
|
+
|
|
20
|
+
Implement the semantic top/left navigation plan from `$doxloop-authoring` in
|
|
21
|
+
`navigation.json` and the renderer's supported header and sidebar structures.
|
|
22
|
+
Preserve planned labels, order, hierarchy, and routes; omit empty template
|
|
23
|
+
groups and verify every page is reachable exactly once.
|
|
24
|
+
|
|
25
|
+
Prefer CommonMark unless a registered tag adds meaningful semantics. Never
|
|
26
|
+
invent a tag without defining and testing its schema and renderer. Preserve the
|
|
27
|
+
parse, validate, transform, and render pipeline. Map branding through renderer
|
|
28
|
+
templates and shared CSS, not page-specific inline presentation.
|
|
29
|
+
|
|
30
|
+
## Verify
|
|
31
|
+
|
|
32
|
+
Run `doxloop test`, then `npm run build`. Treat Markdoc validation diagnostics,
|
|
33
|
+
unknown tags, invalid attributes, unsafe rendered HTML, missing navigation, and
|
|
34
|
+
broken routes as failures. Inspect representative output with
|
|
35
|
+
`doxloop preview --open`.
|
|
36
|
+
|
|
37
|
+
Do not emit JSX, generator-specific directives, or edit `dist/`.
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# Markdoc project format
|
|
2
|
+
|
|
3
|
+
- Content root: `docs/`
|
|
4
|
+
- Schema/configuration: `markdoc.config.mjs`
|
|
5
|
+
- Navigation and routes: `navigation.json`
|
|
6
|
+
- Static renderer: `scripts/build.mjs`
|
|
7
|
+
- Required frontmatter: `title` and `description`
|
|
8
|
+
- Custom syntax: `{% tag attribute="value" %}...{% /tag %}`
|
|
9
|
+
- Use only tags registered in `markdoc.config.mjs`.
|
|
10
|
+
- Preserve `parse` → `validate` → `transform` → `renderers.html`.
|
|
11
|
+
- Build: `npm run build`; output: `dist/`
|
|
12
|
+
|
|
13
|
+
## Navigation and routes
|
|
14
|
+
|
|
15
|
+
- Keep every reader page in `navigation.json` exactly once.
|
|
16
|
+
- Preserve explicit route identifiers when reorganizing labels or groups.
|
|
17
|
+
- Validate navigation targets against source files before building.
|
|
18
|
+
|
|
19
|
+
## Tags and rendering
|
|
20
|
+
|
|
21
|
+
- Define attributes, types, defaults, required values, and child constraints in
|
|
22
|
+
`markdoc.config.mjs`.
|
|
23
|
+
- Prefer transform-safe data over raw HTML.
|
|
24
|
+
- Escape content in custom renderers and preserve semantic HTML.
|
|
25
|
+
- Keep theme tokens and layouts in renderer-owned assets.
|
|
26
|
+
- Put committed guide screenshots under `assets/guides/<guide>/`, reference
|
|
27
|
+
them as `/assets/guides/<guide>/<image>.png`, and preserve the scaffolded
|
|
28
|
+
build copy step that publishes them.
|
|
29
|
+
|
|
30
|
+
## Common failures
|
|
31
|
+
|
|
32
|
+
- Unknown tags may parse but fail validation.
|
|
33
|
+
- Attribute expressions can produce unexpected types after transformation.
|
|
34
|
+
- Rendering without validation can publish malformed or unsafe output.
|
|
35
|
+
- `dist/` is generated and never a source of documentation truth.
|