create-asciidoc-multi-book-workspace 0.1.1 → 0.1.7
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/CHANGELOG.md +72 -0
- package/README.md +16 -2
- package/dist/build-template-preview.d.ts +17 -0
- package/dist/create.d.ts +2 -0
- package/dist/create.js +2 -2
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1 -0
- package/dist/init-workspace.d.ts +9 -0
- package/dist/init-workspace.js +1 -1
- package/dist/runtime/adoc-books.mjs +149 -20
- package/dist/template-manifest.d.ts +3 -0
- package/package.json +10 -1
- package/templates/default-workspace/README.md +1 -1
- package/templates/default-workspace/books/00-book-anatomy/backmatter/appendix-a.adoc +7 -2
- package/templates/default-workspace/books/00-book-anatomy/backmatter/bibliography.adoc +2 -0
- package/templates/default-workspace/books/00-book-anatomy/backmatter/glossary.adoc +3 -1
- package/templates/default-workspace/books/00-book-anatomy/backmatter/index.adoc +31 -3
- package/templates/default-workspace/books/00-book-anatomy/book.adoc +2 -0
- package/templates/default-workspace/books/00-book-anatomy/frontmatter/abstract.adoc +2 -2
- package/templates/default-workspace/books/00-book-anatomy/frontmatter/preface.adoc +2 -0
- package/templates/default-workspace/books/00-book-anatomy/parts/01-front-structure/01-frontmatter-map.adoc +2 -0
- package/templates/default-workspace/books/00-book-anatomy/parts/02-body-structure/01-body-map.adoc +7 -3
- package/templates/default-workspace/books/00-book-anatomy/parts/02-body-structure/02-inline-structure.adoc +32 -0
- package/templates/default-workspace/books/07-structured-writing-conventions/backmatter/appendix-a.adoc +62 -0
- package/templates/default-workspace/books/07-structured-writing-conventions/backmatter/bibliography.adoc +7 -0
- package/templates/default-workspace/books/07-structured-writing-conventions/backmatter/glossary.adoc +14 -0
- package/templates/default-workspace/books/07-structured-writing-conventions/backmatter/index.adoc +37 -0
- package/templates/default-workspace/books/07-structured-writing-conventions/book.adoc +71 -0
- package/templates/default-workspace/books/07-structured-writing-conventions/frontmatter/abstract.adoc +3 -0
- package/templates/default-workspace/books/07-structured-writing-conventions/frontmatter/acknowledgments.adoc +3 -0
- package/templates/default-workspace/books/07-structured-writing-conventions/frontmatter/colophon.adoc +5 -0
- package/templates/default-workspace/books/07-structured-writing-conventions/frontmatter/dedication.adoc +3 -0
- package/templates/default-workspace/books/07-structured-writing-conventions/frontmatter/preface.adoc +7 -0
- package/templates/default-workspace/books/07-structured-writing-conventions/parts/100-source-surface/010-source-and-projection.adoc +44 -0
- package/templates/default-workspace/books/07-structured-writing-conventions/parts/100-source-surface/020-default-semantics.adoc +26 -0
- package/templates/default-workspace/books/07-structured-writing-conventions/parts/100-source-surface/030-source-order-notation.adoc +23 -0
- package/templates/default-workspace/books/07-structured-writing-conventions/parts/100-source-surface/_partintro.adoc +1 -0
- package/templates/default-workspace/books/07-structured-writing-conventions/parts/200-identity-and-relation/010-role-identity.adoc +37 -0
- package/templates/default-workspace/books/07-structured-writing-conventions/parts/200-identity-and-relation/020-relation-predicate.adoc +22 -0
- package/templates/default-workspace/books/07-structured-writing-conventions/parts/200-identity-and-relation/_partintro.adoc +1 -0
- package/templates/default-workspace/books/07-structured-writing-conventions/parts/300-fields-and-lookup/010-surface-fields.adoc +18 -0
- package/templates/default-workspace/books/07-structured-writing-conventions/parts/300-fields-and-lookup/020-index-and-glossary.adoc +14 -0
- package/templates/default-workspace/books/07-structured-writing-conventions/parts/300-fields-and-lookup/_partintro.adoc +1 -0
- package/templates/default-workspace/catalog.adoc +6 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,77 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.1.7 - 2026-06-13
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
|
|
7
|
+
- Add a `复制本书为纯文本` control to each generated book page so readers can copy the expanded single-file book text for saving, note-taking, or model analysis.
|
|
8
|
+
- Add a browser fallback that opens the expanded book text as a UTF-8 plain-text page when clipboard access is unavailable.
|
|
9
|
+
|
|
10
|
+
### Changed
|
|
11
|
+
|
|
12
|
+
- Keep the generated book page controls self-contained by embedding the already-reduced book text in the HTML instead of adding another published source file.
|
|
13
|
+
|
|
14
|
+
## 0.1.6 - 2026-06-09
|
|
15
|
+
|
|
16
|
+
### Added
|
|
17
|
+
|
|
18
|
+
- Accept typed explicit anchors such as `[#id.role, key=value]` when validating user-authored xrefs.
|
|
19
|
+
- Add optional `adoc-books.config.mjs` support so generated workspaces can customize the root redirect and book home-link copy.
|
|
20
|
+
- Add a structured writing conventions reference document and expand the generated sample's appendix with cross-file xref path guidance.
|
|
21
|
+
|
|
22
|
+
### Changed
|
|
23
|
+
|
|
24
|
+
- Keep generated workspaces catalog-oriented by default while allowing user-owned navigation semantics through configuration.
|
|
25
|
+
|
|
26
|
+
## 0.1.5 - 2026-06-07
|
|
27
|
+
|
|
28
|
+
### Added
|
|
29
|
+
|
|
30
|
+
- Add a maintainer guide for Asciidoctor book part numbering, including the boundary between `sectnums`, `partnums`, and `part-signifier`.
|
|
31
|
+
- Add runtime and sample contract coverage for the structured writing conventions book's generated part labels.
|
|
32
|
+
|
|
33
|
+
### Changed
|
|
34
|
+
|
|
35
|
+
- Enable native `Part I` style part numbering in `07-structured-writing-conventions`.
|
|
36
|
+
- Expand the structured writing conventions sample text with additional reader-facing context.
|
|
37
|
+
|
|
38
|
+
## 0.1.4 - 2026-06-06
|
|
39
|
+
|
|
40
|
+
### Added
|
|
41
|
+
|
|
42
|
+
- Add `07-structured-writing-conventions`, a default workspace sample book for structured writing conventions.
|
|
43
|
+
- Document how headings, stable IDs, role tokens, xrefs, rel predicates, and named attributes form a readable and projection-friendly source surface.
|
|
44
|
+
- Add sample contract coverage for the structured writing conventions book.
|
|
45
|
+
|
|
46
|
+
### Changed
|
|
47
|
+
|
|
48
|
+
- Update the default workspace catalog and README to include structured writing conventions without tying README wording to a fixed sample count.
|
|
49
|
+
|
|
50
|
+
## 0.1.3 - 2026-06-06
|
|
51
|
+
|
|
52
|
+
### Added
|
|
53
|
+
|
|
54
|
+
- Expand the book anatomy sample with part directory guidance, chapter numbering notes, and inline structure markers.
|
|
55
|
+
- Add sample contract checks for semantic inline roles, path roles, explicit anchors, xrefs, and index term macro usage.
|
|
56
|
+
- Guard the npm package boundary against generated HTML output entering the published template.
|
|
57
|
+
|
|
58
|
+
### Changed
|
|
59
|
+
|
|
60
|
+
- Clarify that the anatomy sample shows structure positions and combinations, not a required checklist for every book.
|
|
61
|
+
- Use explicit `indexterm2` and `indexterm` macro syntax in the anatomy sample.
|
|
62
|
+
|
|
63
|
+
## 0.1.2 - 2026-06-06
|
|
64
|
+
|
|
65
|
+
### Added
|
|
66
|
+
|
|
67
|
+
- Export the workspace initializer from the package root for host CLI integration.
|
|
68
|
+
- Publish TypeScript declaration files for the public initializer API.
|
|
69
|
+
|
|
70
|
+
### Changed
|
|
71
|
+
|
|
72
|
+
- Return the resolved target directory and generated package name from `initWorkspace`.
|
|
73
|
+
- Document the library entrypoint while keeping command parsing and user-facing output owned by host CLIs.
|
|
74
|
+
|
|
3
75
|
## 0.1.1 - 2026-06-06
|
|
4
76
|
|
|
5
77
|
### Added
|
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
`create-asciidoc-multi-book-workspace` is an npm initializer for a complete AsciiDoc multi-book workspace.
|
|
4
4
|
|
|
5
|
-
It creates a user-owned workspace with
|
|
5
|
+
It creates a user-owned workspace with sample books, a catalog, shared assets, explicit AsciiDoc dependencies, and one local build script at `tools/adoc-books.mjs`.
|
|
6
6
|
|
|
7
7
|
## Usage
|
|
8
8
|
|
|
@@ -23,6 +23,19 @@ npm create asciidoc-multi-book-workspace@latest my-books
|
|
|
23
23
|
npx create-asciidoc-multi-book-workspace@latest my-books
|
|
24
24
|
```
|
|
25
25
|
|
|
26
|
+
## Library API
|
|
27
|
+
|
|
28
|
+
Host CLIs can create the same workspace through the package entrypoint:
|
|
29
|
+
|
|
30
|
+
```ts
|
|
31
|
+
import { initWorkspace } from "create-asciidoc-multi-book-workspace";
|
|
32
|
+
|
|
33
|
+
const result = await initWorkspace({ targetDir: "my-books", force: false });
|
|
34
|
+
console.log(result.targetDir);
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
The host CLI owns command parsing and user-facing output. This package owns the workspace files it creates.
|
|
38
|
+
|
|
26
39
|
The generated workspace contains:
|
|
27
40
|
|
|
28
41
|
```text
|
|
@@ -38,6 +51,7 @@ books/03-technical-book-workflow
|
|
|
38
51
|
books/04-reference-manual
|
|
39
52
|
books/05-upper-volume
|
|
40
53
|
books/06-lower-volume
|
|
54
|
+
books/07-structured-writing-conventions
|
|
41
55
|
shared/attributes.adoc
|
|
42
56
|
shared/images/workspace-map.svg
|
|
43
57
|
```
|
|
@@ -72,7 +86,7 @@ DESIGN.adoc # maintainer design specification
|
|
|
72
86
|
.github/ # maintainer CI
|
|
73
87
|
```
|
|
74
88
|
|
|
75
|
-
The
|
|
89
|
+
The sample books live only under `templates/default-workspace/books/`.
|
|
76
90
|
|
|
77
91
|
## Maintainer Commands
|
|
78
92
|
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
export interface RunCommandOptions {
|
|
3
|
+
cwd: string;
|
|
4
|
+
}
|
|
5
|
+
export type RunCommand = (command: string, args: string[], options: RunCommandOptions) => Promise<void>;
|
|
6
|
+
export interface BuildTemplatePreviewOptions {
|
|
7
|
+
previewRoot?: string;
|
|
8
|
+
runCommand?: RunCommand;
|
|
9
|
+
fresh?: boolean;
|
|
10
|
+
install?: boolean;
|
|
11
|
+
}
|
|
12
|
+
export interface BuildTemplatePreviewResult {
|
|
13
|
+
previewRoot: string;
|
|
14
|
+
workspaceDir: string;
|
|
15
|
+
htmlDir: string;
|
|
16
|
+
}
|
|
17
|
+
export declare function buildTemplatePreview(options?: BuildTemplatePreviewOptions): Promise<BuildTemplatePreviewResult>;
|
package/dist/create.d.ts
ADDED
package/dist/create.js
CHANGED
|
@@ -23,8 +23,8 @@ async function main() {
|
|
|
23
23
|
process.exitCode = 1;
|
|
24
24
|
return;
|
|
25
25
|
}
|
|
26
|
-
const
|
|
27
|
-
const displayTarget = path.relative(process.cwd(),
|
|
26
|
+
const result = await initWorkspace({ targetDir: target, force: args.includes("--force") });
|
|
27
|
+
const displayTarget = path.relative(process.cwd(), result.targetDir) || ".";
|
|
28
28
|
console.log(`Created AsciiDoc multi-book workspace in ${displayTarget}`);
|
|
29
29
|
console.log("");
|
|
30
30
|
console.log("Next:");
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { initWorkspace } from "./init-workspace.js";
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export interface InitWorkspaceOptions {
|
|
2
|
+
targetDir: string;
|
|
3
|
+
force?: boolean;
|
|
4
|
+
}
|
|
5
|
+
export interface InitWorkspaceResult {
|
|
6
|
+
targetDir: string;
|
|
7
|
+
packageName: string;
|
|
8
|
+
}
|
|
9
|
+
export declare function initWorkspace(options: InitWorkspaceOptions): Promise<InitWorkspaceResult>;
|
package/dist/init-workspace.js
CHANGED
|
@@ -54,5 +54,5 @@ export async function initWorkspace(options) {
|
|
|
54
54
|
await writeFile(path.join(targetDir, ".gitignore"), await readFile(path.join(templateRoot, "gitignore.template"), "utf8"), "utf8");
|
|
55
55
|
await mkdir(path.join(targetDir, "tools"), { recursive: true });
|
|
56
56
|
await cp(runtimeScript, path.join(targetDir, "tools", "adoc-books.mjs"), { force: true });
|
|
57
|
-
return targetDir;
|
|
57
|
+
return { targetDir, packageName };
|
|
58
58
|
}
|
|
@@ -2,16 +2,55 @@
|
|
|
2
2
|
import { createRequire } from "node:module";
|
|
3
3
|
import { cp, mkdir, readdir, readFile, rm, stat, writeFile } from "node:fs/promises";
|
|
4
4
|
import path from "node:path";
|
|
5
|
-
import { fileURLToPath } from "node:url";
|
|
5
|
+
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
6
6
|
const require = createRequire(import.meta.url);
|
|
7
7
|
const DIAGRAM_BLOCK_PATTERN = /^\[(?:actdiag|blockdiag|bpmn|bytefield|c4plantuml|d2|dbml|ditaa|erd|excalidraw|graphviz|mermaid|nomnoml|nwdiag|packetdiag|pikchr|plantuml|rackdiag|seqdiag|svgbob|symbolator|umlet|vega|vegalite|wavedrom|structurizr|diagramsnet|wireviz)(?:,|\])/m;
|
|
8
8
|
const CATALOG_BOOK_XREF_PATTERN = /xref:books\/([^/\]]+)\/book\.adoc(?:#[^\[]+)?\[/g;
|
|
9
9
|
const XREF_PATTERN = /xref:([^\[#]+)(?:#([A-Za-z0-9_-]+))?\[/g;
|
|
10
|
-
const ANCHOR_PATTERN = /^\[#([A-Za-z0-9_-]+)
|
|
10
|
+
const ANCHOR_PATTERN = /^\[#([A-Za-z0-9_-]+)(?:[.,][^\]]*)?\]$/gm;
|
|
11
11
|
const LOCAL_TARGET_PATTERN = /\b(?:href|src)="([^"]+)"/g;
|
|
12
12
|
const SCHEME_PATTERN = /^[a-zA-Z][a-zA-Z0-9+.-]*:/;
|
|
13
13
|
const HOME_MARKER = "data-multi-book-home";
|
|
14
|
+
const CONTROLS_MARKER = "data-multi-book-controls";
|
|
14
15
|
const FETCH_DIAGRAMS_ENV = "ADOC_BOOKS_FETCH_DIAGRAMS";
|
|
16
|
+
const CONFIG_FILE = "adoc-books.config.mjs";
|
|
17
|
+
const DEFAULT_CONFIG = {
|
|
18
|
+
rootIndex: {
|
|
19
|
+
redirectTo: "catalog.html",
|
|
20
|
+
title: "AsciiDoc Multi-Book Workspace"
|
|
21
|
+
},
|
|
22
|
+
homeLink: {
|
|
23
|
+
label: "Back to catalog",
|
|
24
|
+
subtitle: "AsciiDoc multi-book workspace"
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
function objectValue(value) {
|
|
28
|
+
return typeof value === "object" && value !== null ? value : {};
|
|
29
|
+
}
|
|
30
|
+
function stringValue(value, fallback) {
|
|
31
|
+
return typeof value === "string" && value.trim() !== "" ? value : fallback;
|
|
32
|
+
}
|
|
33
|
+
async function loadRuntimeConfig(rootDir) {
|
|
34
|
+
const configPath = path.join(rootDir, CONFIG_FILE);
|
|
35
|
+
if (!await existsFile(configPath))
|
|
36
|
+
return DEFAULT_CONFIG;
|
|
37
|
+
const configUrl = pathToFileURL(configPath);
|
|
38
|
+
configUrl.search = `mtime=${(await stat(configPath)).mtimeMs}`;
|
|
39
|
+
const module = await import(configUrl.href);
|
|
40
|
+
const rawConfig = objectValue(module.default ?? module);
|
|
41
|
+
const rawRootIndex = objectValue(rawConfig.rootIndex);
|
|
42
|
+
const rawHomeLink = objectValue(rawConfig.homeLink);
|
|
43
|
+
return {
|
|
44
|
+
rootIndex: {
|
|
45
|
+
redirectTo: stringValue(rawRootIndex.redirectTo, DEFAULT_CONFIG.rootIndex.redirectTo),
|
|
46
|
+
title: stringValue(rawRootIndex.title, DEFAULT_CONFIG.rootIndex.title)
|
|
47
|
+
},
|
|
48
|
+
homeLink: {
|
|
49
|
+
label: stringValue(rawHomeLink.label, DEFAULT_CONFIG.homeLink.label),
|
|
50
|
+
subtitle: stringValue(rawHomeLink.subtitle, DEFAULT_CONFIG.homeLink.subtitle)
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
}
|
|
15
54
|
async function existsFile(filePath) {
|
|
16
55
|
try {
|
|
17
56
|
const stats = await stat(filePath);
|
|
@@ -170,29 +209,35 @@ function escapeHtmlAttribute(value) {
|
|
|
170
209
|
.replaceAll("<", "<")
|
|
171
210
|
.replaceAll(">", ">");
|
|
172
211
|
}
|
|
173
|
-
function
|
|
174
|
-
|
|
212
|
+
function escapeJsonScript(value) {
|
|
213
|
+
return JSON.stringify(value)
|
|
214
|
+
.replaceAll("<", "\\u003c")
|
|
215
|
+
.replaceAll("\u2028", "\\u2028")
|
|
216
|
+
.replaceAll("\u2029", "\\u2029");
|
|
217
|
+
}
|
|
218
|
+
function addBookControlsToBookHtml(html, href, homeLink, bookSource) {
|
|
219
|
+
if (html.includes(CONTROLS_MARKER))
|
|
175
220
|
return html;
|
|
176
221
|
const marker = '<div id="toc" class="toc2">';
|
|
177
222
|
const index = html.indexOf(marker);
|
|
178
223
|
if (index === -1)
|
|
179
224
|
throw new Error("book HTML is missing the left TOC container");
|
|
180
225
|
const insertAt = index + marker.length;
|
|
181
|
-
const
|
|
226
|
+
const controlsBlock = `
|
|
182
227
|
<style>
|
|
183
|
-
.multi-book-
|
|
228
|
+
.multi-book-controls {
|
|
184
229
|
margin: 0 0 1rem;
|
|
185
230
|
padding-bottom: .75rem;
|
|
186
231
|
border-bottom: 1px solid #e5e7eb;
|
|
187
232
|
}
|
|
188
|
-
.multi-book-home
|
|
233
|
+
.multi-book-home {
|
|
189
234
|
color: #1f2937;
|
|
190
235
|
display: block;
|
|
191
236
|
font-weight: 600;
|
|
192
237
|
line-height: 1.35;
|
|
193
238
|
text-decoration: none;
|
|
194
239
|
}
|
|
195
|
-
.multi-book-home
|
|
240
|
+
.multi-book-home:hover {
|
|
196
241
|
color: #0f766e;
|
|
197
242
|
text-decoration: underline;
|
|
198
243
|
}
|
|
@@ -203,33 +248,116 @@ function addHomeLinkToBookHtml(html, href) {
|
|
|
203
248
|
font-weight: 400;
|
|
204
249
|
margin-top: .15rem;
|
|
205
250
|
}
|
|
251
|
+
.multi-book-copy-source {
|
|
252
|
+
appearance: none;
|
|
253
|
+
background: #ffffff;
|
|
254
|
+
border: 1px solid #cbd5e1;
|
|
255
|
+
border-radius: 4px;
|
|
256
|
+
color: #1f2937;
|
|
257
|
+
cursor: pointer;
|
|
258
|
+
display: block;
|
|
259
|
+
font-size: .82rem;
|
|
260
|
+
font-weight: 600;
|
|
261
|
+
line-height: 1.2;
|
|
262
|
+
margin-top: .75rem;
|
|
263
|
+
padding: .42rem .5rem;
|
|
264
|
+
text-align: center;
|
|
265
|
+
width: 100%;
|
|
266
|
+
}
|
|
267
|
+
.multi-book-copy-source:hover,
|
|
268
|
+
.multi-book-copy-source:focus {
|
|
269
|
+
border-color: #0f766e;
|
|
270
|
+
color: #0f766e;
|
|
271
|
+
}
|
|
272
|
+
.multi-book-copy-status {
|
|
273
|
+
color: #64748b;
|
|
274
|
+
display: block;
|
|
275
|
+
font-size: .75rem;
|
|
276
|
+
line-height: 1.35;
|
|
277
|
+
margin-top: .4rem;
|
|
278
|
+
min-height: 1em;
|
|
279
|
+
}
|
|
206
280
|
</style>
|
|
207
|
-
<div class="multi-book-
|
|
208
|
-
<a href="${escapeHtmlAttribute(href)}"
|
|
209
|
-
|
|
210
|
-
|
|
281
|
+
<div class="multi-book-controls" ${CONTROLS_MARKER}>
|
|
282
|
+
<a class="multi-book-home" ${HOME_MARKER} href="${escapeHtmlAttribute(href)}">${escapeHtmlAttribute(homeLink.label)}<span>${escapeHtmlAttribute(homeLink.subtitle)}</span></a>
|
|
283
|
+
<button type="button" class="multi-book-copy-source" data-multi-book-source-copy>复制本书为纯文本</button>
|
|
284
|
+
<span class="multi-book-copy-status" data-multi-book-source-status aria-live="polite"></span>
|
|
285
|
+
</div>
|
|
286
|
+
<script type="application/json" id="multi-book-source-data">${escapeJsonScript(bookSource)}</script>
|
|
287
|
+
<script>
|
|
288
|
+
(function () {
|
|
289
|
+
var sourceElement = document.getElementById("multi-book-source-data");
|
|
290
|
+
var button = document.querySelector("[data-multi-book-source-copy]");
|
|
291
|
+
var status = document.querySelector("[data-multi-book-source-status]");
|
|
292
|
+
if (!sourceElement || !button) return;
|
|
293
|
+
|
|
294
|
+
var source = "";
|
|
295
|
+
var fallbackMode = false;
|
|
296
|
+
try {
|
|
297
|
+
source = JSON.parse(sourceElement.textContent || '""');
|
|
298
|
+
} catch (error) {
|
|
299
|
+
if (status) status.textContent = "纯文本数据读取失败";
|
|
300
|
+
button.disabled = true;
|
|
301
|
+
return;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
function setStatus(message) {
|
|
305
|
+
if (status) status.textContent = message;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
function openSourcePage() {
|
|
309
|
+
var blob = new Blob([source], { type: "text/plain;charset=utf-8" });
|
|
310
|
+
var url = URL.createObjectURL(blob);
|
|
311
|
+
window.open(url, "_blank", "noopener");
|
|
312
|
+
setTimeout(function () { URL.revokeObjectURL(url); }, 60000);
|
|
313
|
+
setStatus("已尝试打开纯文本页;如果没有出现,请允许弹出窗口后再试");
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
button.addEventListener("click", async function () {
|
|
317
|
+
if (fallbackMode) {
|
|
318
|
+
openSourcePage();
|
|
319
|
+
return;
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
try {
|
|
323
|
+
if (!navigator.clipboard || !navigator.clipboard.writeText) throw new Error("clipboard unavailable");
|
|
324
|
+
await navigator.clipboard.writeText(source);
|
|
325
|
+
button.textContent = "已复制";
|
|
326
|
+
setStatus("");
|
|
327
|
+
setTimeout(function () { button.textContent = "复制本书为纯文本"; }, 1800);
|
|
328
|
+
} catch (error) {
|
|
329
|
+
fallbackMode = true;
|
|
330
|
+
button.textContent = "打开纯文本页";
|
|
331
|
+
openSourcePage();
|
|
332
|
+
}
|
|
333
|
+
});
|
|
334
|
+
}());
|
|
335
|
+
</script>`;
|
|
336
|
+
return `${html.slice(0, insertAt)}${controlsBlock}${html.slice(insertAt)}`;
|
|
211
337
|
}
|
|
212
|
-
async function addHomeLinks(rootDir, books) {
|
|
338
|
+
async function addHomeLinks(rootDir, books, homeLink) {
|
|
213
339
|
const catalog = path.join(rootDir, "build", "html", "catalog.html");
|
|
214
340
|
for (const book of books) {
|
|
215
341
|
const htmlFile = path.join(book.htmlOutputDir, "book.html");
|
|
216
342
|
const html = await readFile(htmlFile, "utf8");
|
|
217
343
|
const href = path.relative(path.dirname(htmlFile), catalog);
|
|
218
|
-
await
|
|
344
|
+
const source = await readFile(path.join(rootDir, "build", "adoc", "books", `${book.bookId}.adoc`), "utf8");
|
|
345
|
+
await writeFile(htmlFile, addBookControlsToBookHtml(html, href, homeLink, source), "utf8");
|
|
219
346
|
}
|
|
220
347
|
}
|
|
221
|
-
async function writeRootIndex(rootDir) {
|
|
348
|
+
async function writeRootIndex(rootDir, rootIndex) {
|
|
222
349
|
const outputDir = path.join(rootDir, "build", "html");
|
|
223
350
|
await mkdir(outputDir, { recursive: true });
|
|
351
|
+
const redirectTo = rootIndex.redirectTo;
|
|
224
352
|
await writeFile(path.join(outputDir, "index.html"), `<!doctype html>
|
|
225
353
|
<html lang="en">
|
|
226
354
|
<head>
|
|
227
355
|
<meta charset="utf-8">
|
|
228
|
-
<meta http-equiv="refresh" content="0; url
|
|
229
|
-
<title
|
|
356
|
+
<meta http-equiv="refresh" content="0; url=${escapeHtmlAttribute(redirectTo)}">
|
|
357
|
+
<title>${escapeHtmlAttribute(rootIndex.title)}</title>
|
|
230
358
|
</head>
|
|
231
359
|
<body>
|
|
232
|
-
<p><a href="
|
|
360
|
+
<p><a href="${escapeHtmlAttribute(redirectTo)}">${escapeHtmlAttribute(redirectTo)}</a></p>
|
|
233
361
|
</body>
|
|
234
362
|
</html>
|
|
235
363
|
`, "utf8");
|
|
@@ -351,14 +479,15 @@ export async function buildWorkspace(rootDir = process.cwd()) {
|
|
|
351
479
|
const books = await discoverBooks(rootDir);
|
|
352
480
|
if (books.length === 0)
|
|
353
481
|
throw new Error(`missing book.adoc entries in ${path.join(rootDir, "books")}`);
|
|
482
|
+
const config = await loadRuntimeConfig(rootDir);
|
|
354
483
|
const useKroki = await workspaceUsesDiagrams(rootDir, books);
|
|
355
484
|
const fetchDiagrams = shouldFetchDiagrams();
|
|
356
485
|
const asciidoctor = createAsciidoctor(useKroki);
|
|
357
486
|
await buildReducedAdoc(rootDir, books, asciidoctor);
|
|
358
487
|
await buildHtml(rootDir, books, asciidoctor, useKroki, fetchDiagrams);
|
|
359
488
|
await copyAssets(rootDir, books);
|
|
360
|
-
await addHomeLinks(rootDir, books);
|
|
361
|
-
await writeRootIndex(rootDir);
|
|
489
|
+
await addHomeLinks(rootDir, books, config.homeLink);
|
|
490
|
+
await writeRootIndex(rootDir, config.rootIndex);
|
|
362
491
|
await assertNoIssues("HTML local resource check", await missingLocalResources(rootDir));
|
|
363
492
|
await assertNoIssues("workspace contract check", await workspaceContractIssues(rootDir, books));
|
|
364
493
|
}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
export declare const defaultWorkspaceTemplate = "default-workspace";
|
|
2
|
+
export declare const templatePackageNamePlaceholder = "{{name}}";
|
|
3
|
+
export declare const fixedTemplateOutputPaths: readonly ["README.md", "catalog.adoc", "package.json", ".gitignore", "tools/adoc-books.mjs", "books", "shared"];
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-asciidoc-multi-book-workspace",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.7",
|
|
4
4
|
"description": "Create a complete AsciiDoc multi-book workspace.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"author": {
|
|
@@ -17,6 +17,13 @@
|
|
|
17
17
|
},
|
|
18
18
|
"homepage": "https://michengliang.github.io/asciidoc-multi-book-workspace/",
|
|
19
19
|
"type": "module",
|
|
20
|
+
"exports": {
|
|
21
|
+
".": {
|
|
22
|
+
"types": "./dist/index.d.ts",
|
|
23
|
+
"import": "./dist/index.js"
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
"types": "./dist/index.d.ts",
|
|
20
27
|
"keywords": [
|
|
21
28
|
"asciidoc",
|
|
22
29
|
"asciidoctor",
|
|
@@ -30,7 +37,9 @@
|
|
|
30
37
|
},
|
|
31
38
|
"files": [
|
|
32
39
|
"dist/build-template-preview.js",
|
|
40
|
+
"dist/*.d.ts",
|
|
33
41
|
"dist/create.js",
|
|
42
|
+
"dist/index.js",
|
|
34
43
|
"dist/init-workspace.js",
|
|
35
44
|
"dist/runtime/adoc-books.mjs",
|
|
36
45
|
"dist/template-manifest.js",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# My Books
|
|
2
2
|
|
|
3
|
-
This is an AsciiDoc multi-book workspace. It starts with
|
|
3
|
+
This is an AsciiDoc multi-book workspace. It starts with sample books that show common ways to organize independent books, multipart books, technical books, reference material, split volumes, and structured writing conventions.
|
|
4
4
|
|
|
5
5
|
## Install
|
|
6
6
|
|
|
@@ -4,8 +4,11 @@
|
|
|
4
4
|
|===
|
|
5
5
|
|写法 |含义
|
|
6
6
|
|
|
7
|
-
|`=
|
|
8
|
-
|Document title
|
|
7
|
+
|`= 书名`
|
|
8
|
+
|Document title(文档标题)。在 book 文档类型中作为整本书标题。
|
|
9
|
+
|
|
10
|
+
|`= 部标题`
|
|
11
|
+
|Document title 之后的 Level 0 Section。在 book 文档类型中可作为 Part(部)。
|
|
9
12
|
|
|
10
13
|
|`== 章`
|
|
11
14
|
|Level 1 Section(一级章节)。在 book 文档类型中通常作为 Chapter(章)。
|
|
@@ -22,3 +25,5 @@
|
|
|
22
25
|
|`====== 最底层级`
|
|
23
26
|
|Level 5 Section(五级章节)。AsciiDoc 支持的最深层级。
|
|
24
27
|
|===
|
|
28
|
+
|
|
29
|
+
`[appendix]`、`[glossary]`、`[bibliography]` 和 `[index]` 是 section style。它们改变紧随其后 section 的语义;标题层级仍由 `=` 数量决定。
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
= 参考资料
|
|
2
2
|
|
|
3
|
+
每条参考资料可使用 bibliography anchor 作为稳定引用目标。
|
|
4
|
+
|
|
3
5
|
* [[[asciidoctor-section-styles]]] Asciidoctor Docs, Section Styles for Articles and Books, https://docs.asciidoctor.org/asciidoc/latest/sections/styles/
|
|
4
6
|
* [[[asciidoctor-parts]]] Asciidoctor Docs, Book Parts, https://docs.asciidoctor.org/asciidoc/latest/sections/parts/
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
= 术语表
|
|
2
2
|
|
|
3
|
+
术语表通常使用定义列表记录术语和解释。
|
|
4
|
+
|
|
3
5
|
book:: 具有独立 `book.adoc`、章节顺序和构建产物的书籍单位。
|
|
4
6
|
part:: 同一本 book 内部的 level 0 大分部。
|
|
5
7
|
chapter:: book 中的主要正文单位,通常使用 `==` 标题。
|
|
@@ -7,4 +9,4 @@ section:: chapter 内部的层级标题。
|
|
|
7
9
|
appendix:: 放置补充材料的后置章节。
|
|
8
10
|
glossary:: 使用定义列表解释术语的后置章节。
|
|
9
11
|
bibliography:: 放置参考资料的后置章节。
|
|
10
|
-
index::
|
|
12
|
+
index:: 放置索引目录种子或索引说明的后置章节;自动索引目录依赖转换器支持。
|
|
@@ -1,9 +1,37 @@
|
|
|
1
1
|
= 索引
|
|
2
2
|
|
|
3
|
-
索引 section
|
|
3
|
+
索引 section 位于书籍后置区域。正文中的索引词宏是索引词来源。
|
|
4
|
+
|
|
5
|
+
AsciiDoc 区分正文可见索引词和正文隐藏索引词:
|
|
6
|
+
|
|
7
|
+
[cols="1,2", options="header"]
|
|
8
|
+
|===
|
|
9
|
+
|写法 |含义
|
|
10
|
+
|
|
11
|
+
|`indexterm2:[<primary>]`
|
|
12
|
+
|正文可见,同时作为一级索引项。
|
|
13
|
+
|
|
14
|
+
|`indexterm:[<primary>]`
|
|
15
|
+
|正文不可见,作为一级索引项。
|
|
16
|
+
|
|
17
|
+
|`indexterm:[<primary>, <secondary>]`
|
|
18
|
+
|正文不可见,作为二级索引项。
|
|
19
|
+
|
|
20
|
+
|`indexterm:[<primary>, <secondary>, <tertiary>]`
|
|
21
|
+
|正文不可见,作为三级索引项。
|
|
22
|
+
|===
|
|
23
|
+
|
|
24
|
+
正文中已经出现该词时,优先使用正文可见索引词。正文没有出现该词,但当前位置需要进入索引时,才使用正文隐藏索引词。
|
|
25
|
+
|
|
26
|
+
隐藏索引词应贴近它标记的段落内容。本书把隐藏索引词放在相关句子末尾,避免形成独立空段落。
|
|
27
|
+
|
|
28
|
+
Asciidoctor 的内置 HTML5 转换器不会自动生成索引目录。`[index]` section 是 PDF 和 DocBook 工具链自动填充索引目录的种子位置;在本 HTML 样本中,它展示后置索引章节的位置和索引词写法。
|
|
29
|
+
|
|
30
|
+
本书正文中的索引词示例:
|
|
4
31
|
|
|
5
32
|
[source,asciidoc]
|
|
6
33
|
----
|
|
7
|
-
|
|
8
|
-
|
|
34
|
+
indexterm2:[section]
|
|
35
|
+
indexterm:[section, hierarchy]
|
|
36
|
+
indexterm:[heading, discrete]
|
|
9
37
|
----
|
package/templates/default-workspace/books/00-book-anatomy/parts/02-body-structure/01-body-map.adoc
CHANGED
|
@@ -1,13 +1,17 @@
|
|
|
1
1
|
[#body-map]
|
|
2
2
|
== 正文结构地图
|
|
3
3
|
|
|
4
|
-
part 是 book doctype
|
|
4
|
+
part 是 book doctype 中 document title 之后的 level 0 section。level 1 section 通常形成 chapter;multipart book 中 chapter 位于 part 下,普通 book 中 chapter 可以直接位于 book 下。
|
|
5
|
+
|
|
6
|
+
本模板把每个 part 的源文件放在 `parts/<part-id>/` 下。这个目录约定服务维护边界;part 本身由 `book.adoc` 中的 level 0 section 声明。
|
|
7
|
+
|
|
8
|
+
本书启用 `:sectnums:`。part 标题不占用 chapter 编号;part 下的 level 1 section 按 `book.adoc` 展开后的顺序形成连续 chapter 编号。
|
|
5
9
|
|
|
6
10
|
=== 小节层级
|
|
7
11
|
|
|
8
|
-
|
|
12
|
+
indexterm2:[section] 是 chapter 内部的层级单位。indexterm:[section, hierarchy]
|
|
9
13
|
|
|
10
14
|
[discrete]
|
|
11
15
|
=== 离散标题
|
|
12
16
|
|
|
13
|
-
|
|
17
|
+
离散标题显示为标题样式,但不创建 section,不参与章节编号,也不进入目录。indexterm:[heading, discrete]
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
[#inline-structure-map]
|
|
2
|
+
== 内联结构标记
|
|
3
|
+
|
|
4
|
+
内联结构标记用于给正文中的术语、路径、引用目标和索引入口提供稳定身份。它不改变 book 的章节层级,但会提高正文片段的可维护性和可检索性。
|
|
5
|
+
|
|
6
|
+
[cols="1,2", options="header"]
|
|
7
|
+
|===
|
|
8
|
+
|写法 |结构作用
|
|
9
|
+
|
|
10
|
+
|`[#stable-anchor]`
|
|
11
|
+
|声明稳定引用目标。
|
|
12
|
+
|
|
13
|
+
|`xref:#body-map[正文结构地图]`
|
|
14
|
+
|引用同一文档内的稳定目标。
|
|
15
|
+
|
|
16
|
+
|`indexterm2:[term]`
|
|
17
|
+
|把正文中已经出现的词作为可见索引词。
|
|
18
|
+
|
|
19
|
+
|`indexterm:[term, detail]`
|
|
20
|
+
|正文没有出现该词时,补充隐藏索引入口。
|
|
21
|
+
|
|
22
|
+
|`[.term]#inline role#`
|
|
23
|
+
|给术语片段提供语义身份。
|
|
24
|
+
|
|
25
|
+
|`[.path]` + monospace path
|
|
26
|
+
|给路径文本提供语义身份。
|
|
27
|
+
|
|
28
|
+
|`{series-name}`
|
|
29
|
+
|引用共享属性,减少多处重复文本。
|
|
30
|
+
|===
|
|
31
|
+
|
|
32
|
+
语义 inline role 提供结构身份;具体视觉效果取决于输出样式。本书使用 [.term]#inline role# 标记术语片段,使用 [.path]`parts/02-body-structure/` 标记路径片段。
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
= 附录 A:结构化写法速查
|
|
2
|
+
|
|
3
|
+
[cols="1,2", options="header"]
|
|
4
|
+
|===
|
|
5
|
+
|写法 |含义
|
|
6
|
+
|
|
7
|
+
|`= 书名`
|
|
8
|
+
|Document title(文档标题)。在 book 文档类型中作为整本书标题。
|
|
9
|
+
|
|
10
|
+
|`= 部标题`
|
|
11
|
+
|Document title 之后的 Level 0 Section。在 book 文档类型中可作为 Part(部)。
|
|
12
|
+
|
|
13
|
+
|`== 章 / 标题`
|
|
14
|
+
|Level 1 Section(一级章节)。创建书稿阅读结构,在 book 文档类型中通常作为 Chapter(章)。
|
|
15
|
+
|
|
16
|
+
|`=== 节`
|
|
17
|
+
|Level 2 Section(二级章节 / 节)。
|
|
18
|
+
|
|
19
|
+
|`==== 小节`
|
|
20
|
+
|Level 3 Section(三级章节 / 小节)。
|
|
21
|
+
|
|
22
|
+
|`===== 次小节`
|
|
23
|
+
|Level 4 Section(四级章节)。
|
|
24
|
+
|
|
25
|
+
|`====== 最底层级`
|
|
26
|
+
|Level 5 Section(五级章节)。AsciiDoc 支持的最深层级。
|
|
27
|
+
|
|
28
|
+
|`parts/100-topic/`
|
|
29
|
+
|part 目录的源文件编排号。
|
|
30
|
+
|
|
31
|
+
|`010-opening.adoc`
|
|
32
|
+
|chapter 文件的源文件编排号。
|
|
33
|
+
|
|
34
|
+
|`[#stable-id]`
|
|
35
|
+
|为重要标题声明稳定 ID。
|
|
36
|
+
|
|
37
|
+
|`[#stable-id.concept]`
|
|
38
|
+
|声明稳定 ID,并用 role 标明标题身份。
|
|
39
|
+
|
|
40
|
+
|`[#example.example, owner=writing-team]`
|
|
41
|
+
|role 声明标题身份;named attributes 保留附加字段。
|
|
42
|
+
|
|
43
|
+
|`xref:stable-id[显示文本]`
|
|
44
|
+
|显示为链接,投影为 references。
|
|
45
|
+
|
|
46
|
+
|`xref:stable-id[显示文本, rel=depends-on]`
|
|
47
|
+
|显示为链接,同时声明 depends-on 关系。
|
|
48
|
+
|
|
49
|
+
|`indexterm2:[role]`
|
|
50
|
+
|正文可见索引词。
|
|
51
|
+
|
|
52
|
+
|`indexterm:[relation predicate]`
|
|
53
|
+
|正文隐藏索引词。
|
|
54
|
+
|===
|
|
55
|
+
|
|
56
|
+
role 描述标题身份。rel 描述 xref 边上的关系谓词。named attributes 是附加字段。
|
|
57
|
+
|
|
58
|
+
`[appendix]`、`[glossary]`、`[bibliography]` 和 `[index]` 是 section style。它们改变紧随其后 section 的语义;标题层级仍由 `=` 数量决定。
|
|
59
|
+
|
|
60
|
+
对于跨文件的交叉引用,为了避免重复编写相对路径,你可以在文档的头部(Header)定义一个文档属性(Document Attribute)来存储这个基础路径。
|
|
61
|
+
|
|
62
|
+
你可以在主文档的开头定义一个变量(比如 `:book-b-dir:`),后续引用时通过 `{book-b-dir}` 来调用它。
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
= 参考坐标
|
|
2
|
+
|
|
3
|
+
以下资料提供 AsciiDoc 标题、交叉引用和元素属性的参考坐标。
|
|
4
|
+
|
|
5
|
+
* [[[asciidoctor-xref]]] Asciidoctor Docs, Cross References, https://docs.asciidoctor.org/asciidoc/latest/macros/xref/
|
|
6
|
+
* [[[asciidoctor-attributes]]] Asciidoctor Docs, Element Attributes, https://docs.asciidoctor.org/asciidoc/latest/attributes/element-attributes/
|
|
7
|
+
* [[[asciidoctor-sections]]] Asciidoctor Docs, Sections, https://docs.asciidoctor.org/asciidoc/latest/sections/
|
package/templates/default-workspace/books/07-structured-writing-conventions/backmatter/glossary.adoc
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
= 术语表
|
|
2
|
+
|
|
3
|
+
本术语表记录结构化书写约定中的核心术语。
|
|
4
|
+
|
|
5
|
+
heading:: 使用等号标题创建的书稿结构单位。
|
|
6
|
+
stable ID:: 作者声明的稳定引用地址,例如 `#stable-heading`。
|
|
7
|
+
source-order notation:: 写在源文件路径表面的排序符号。
|
|
8
|
+
role:: 标题身份标记,例如 `.concept` 或 `.rule`。
|
|
9
|
+
ordinary reference:: 普通 xref。投影时使用默认谓词 `aat:references`。
|
|
10
|
+
relation predicate:: xref `rel` 字段选择的边谓词。
|
|
11
|
+
source heading:: xref 所在的标题。
|
|
12
|
+
target heading:: xref selector 指向的标题。
|
|
13
|
+
surface field:: named attributes 携带的源文档表面字段。
|
|
14
|
+
index term:: 服务书后索引和读者检索的索引入口。
|
package/templates/default-workspace/books/07-structured-writing-conventions/backmatter/index.adoc
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
= 索引
|
|
2
|
+
|
|
3
|
+
索引 section 位于书籍后置区域。正文中的索引词宏是索引词来源。
|
|
4
|
+
|
|
5
|
+
AsciiDoc 区分正文可见索引词和正文隐藏索引词:
|
|
6
|
+
|
|
7
|
+
[cols="1,2", options="header"]
|
|
8
|
+
|===
|
|
9
|
+
|写法 |含义
|
|
10
|
+
|
|
11
|
+
|`indexterm2:[<primary>]`
|
|
12
|
+
|正文可见,同时作为一级索引项。
|
|
13
|
+
|
|
14
|
+
|`indexterm:[<primary>]`
|
|
15
|
+
|正文不可见,作为一级索引项。
|
|
16
|
+
|
|
17
|
+
|`indexterm:[<primary>, <secondary>]`
|
|
18
|
+
|正文不可见,作为二级索引项。
|
|
19
|
+
|
|
20
|
+
|`indexterm:[<primary>, <secondary>, <tertiary>]`
|
|
21
|
+
|正文不可见,作为三级索引项。
|
|
22
|
+
|===
|
|
23
|
+
|
|
24
|
+
正文中已经出现该词时,优先使用正文可见索引词。需要补充未出现在正文里的索引入口时,使用正文隐藏索引词。
|
|
25
|
+
|
|
26
|
+
隐藏索引词应贴近它标记的段落内容。本书把隐藏索引词放在相关句子末尾。
|
|
27
|
+
|
|
28
|
+
Asciidoctor 的内置 HTML5 转换器不会自动生成索引目录。`[index]` section 是 PDF 和 DocBook 工具链自动填充索引目录的种子位置;在本 HTML 样本中,它展示后置索引章节的位置和索引词写法。
|
|
29
|
+
|
|
30
|
+
本书正文中的索引词示例:
|
|
31
|
+
|
|
32
|
+
[source,asciidoc]
|
|
33
|
+
----
|
|
34
|
+
indexterm2:[role]
|
|
35
|
+
indexterm:[relation predicate]
|
|
36
|
+
indexterm:[源文件编排号]
|
|
37
|
+
----
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
= 结构化书写约定标本
|
|
2
|
+
作者 <author@example.com>
|
|
3
|
+
v0.1, 2026-05
|
|
4
|
+
:doctype: book
|
|
5
|
+
:toc: left
|
|
6
|
+
:toclevels: 3
|
|
7
|
+
:sectnums:
|
|
8
|
+
:partnums:
|
|
9
|
+
:part-signifier: Part
|
|
10
|
+
:icons: font
|
|
11
|
+
:experimental:
|
|
12
|
+
:idprefix:
|
|
13
|
+
:idseparator: -
|
|
14
|
+
|
|
15
|
+
include::../../shared/attributes.adoc[]
|
|
16
|
+
|
|
17
|
+
[abstract]
|
|
18
|
+
include::frontmatter/abstract.adoc[]
|
|
19
|
+
|
|
20
|
+
[colophon]
|
|
21
|
+
include::frontmatter/colophon.adoc[]
|
|
22
|
+
|
|
23
|
+
[dedication]
|
|
24
|
+
include::frontmatter/dedication.adoc[]
|
|
25
|
+
|
|
26
|
+
[preface]
|
|
27
|
+
include::frontmatter/preface.adoc[]
|
|
28
|
+
|
|
29
|
+
[acknowledgments]
|
|
30
|
+
include::frontmatter/acknowledgments.adoc[]
|
|
31
|
+
|
|
32
|
+
= 从源文档看结构
|
|
33
|
+
|
|
34
|
+
[partintro]
|
|
35
|
+
include::parts/100-source-surface/_partintro.adoc[]
|
|
36
|
+
|
|
37
|
+
include::parts/100-source-surface/010-source-and-projection.adoc[]
|
|
38
|
+
|
|
39
|
+
include::parts/100-source-surface/020-default-semantics.adoc[]
|
|
40
|
+
|
|
41
|
+
include::parts/100-source-surface/030-source-order-notation.adoc[]
|
|
42
|
+
|
|
43
|
+
= 给标题和引用加意图
|
|
44
|
+
|
|
45
|
+
[partintro]
|
|
46
|
+
include::parts/200-identity-and-relation/_partintro.adoc[]
|
|
47
|
+
|
|
48
|
+
include::parts/200-identity-and-relation/010-role-identity.adoc[]
|
|
49
|
+
|
|
50
|
+
include::parts/200-identity-and-relation/020-relation-predicate.adoc[]
|
|
51
|
+
|
|
52
|
+
= 字段、索引与术语
|
|
53
|
+
|
|
54
|
+
[partintro]
|
|
55
|
+
include::parts/300-fields-and-lookup/_partintro.adoc[]
|
|
56
|
+
|
|
57
|
+
include::parts/300-fields-and-lookup/010-surface-fields.adoc[]
|
|
58
|
+
|
|
59
|
+
include::parts/300-fields-and-lookup/020-index-and-glossary.adoc[]
|
|
60
|
+
|
|
61
|
+
[appendix]
|
|
62
|
+
include::backmatter/appendix-a.adoc[]
|
|
63
|
+
|
|
64
|
+
[glossary]
|
|
65
|
+
include::backmatter/glossary.adoc[]
|
|
66
|
+
|
|
67
|
+
[bibliography]
|
|
68
|
+
include::backmatter/bibliography.adoc[]
|
|
69
|
+
|
|
70
|
+
[index]
|
|
71
|
+
include::backmatter/index.adoc[]
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
[#source-and-projection]
|
|
2
|
+
== 源文本与投影
|
|
3
|
+
|
|
4
|
+
本章用一段示例展示结构化书写约定。Turtle 片段列出关键投影事实;完整投影还会保留 raw、路径、行号和边证据。
|
|
5
|
+
希望你能通过本章节的演示来理解你写下的文字能够给未来的你提供稳定的查询与导航结构。
|
|
6
|
+
|
|
7
|
+
[source,asciidoc]
|
|
8
|
+
----
|
|
9
|
+
= 结构化写作样例
|
|
10
|
+
|
|
11
|
+
[#stable-heading.concept]
|
|
12
|
+
== 稳定标题
|
|
13
|
+
|
|
14
|
+
稳定标题提供可引用的阅读单位。
|
|
15
|
+
|
|
16
|
+
[#xref-rule.rule]
|
|
17
|
+
== 引用规则
|
|
18
|
+
|
|
19
|
+
引用规则参见 xref:stable-heading[稳定标题]。
|
|
20
|
+
引用规则依赖 xref:stable-heading[稳定标题, rel=depends-on, weight=strong]。
|
|
21
|
+
----
|
|
22
|
+
|
|
23
|
+
源文档把 `稳定标题` 写成可引用的阅读单位,把 `引用规则` 写成规则说明,并在正文里写出参见和依赖两种引用。
|
|
24
|
+
|
|
25
|
+
[source,turtle]
|
|
26
|
+
----
|
|
27
|
+
:stable-heading a aat:Heading ;
|
|
28
|
+
aat:headline "稳定标题" ;
|
|
29
|
+
aat:addressLabel "stable-heading" ;
|
|
30
|
+
aat:role "concept" .
|
|
31
|
+
|
|
32
|
+
:xref-rule a aat:Heading ;
|
|
33
|
+
aat:headline "引用规则" ;
|
|
34
|
+
aat:addressLabel "xref-rule" ;
|
|
35
|
+
aat:role "rule" ;
|
|
36
|
+
aat:references :stable-heading ;
|
|
37
|
+
rel:depends-on :stable-heading .
|
|
38
|
+
|
|
39
|
+
:xref-edge-depends-on a aat:XrefEdge ;
|
|
40
|
+
aat:rel "depends-on" ;
|
|
41
|
+
aat:weight "strong" .
|
|
42
|
+
----
|
|
43
|
+
|
|
44
|
+
读者看源文档,能直接看到 [.concept]#稳定标题# 是被引用的阅读单位, [.rule]#引用规则# 说明引用写法。下游投影工具链读取同一份源文档,得到 `aat:Heading`、`aat:addressLabel`、`aat:role`、`aat:references` 和 `rel:depends-on`。
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
[#heading-and-xref]
|
|
2
|
+
== 标题与引用
|
|
3
|
+
|
|
4
|
+
等号行是标题。标题前一行的 attrlist 承载地址和 role。
|
|
5
|
+
|
|
6
|
+
[source,asciidoc]
|
|
7
|
+
----
|
|
8
|
+
[#stable-heading.concept]
|
|
9
|
+
== 稳定标题
|
|
10
|
+
----
|
|
11
|
+
|
|
12
|
+
`#stable-heading` 给标题一个稳定地址;`.concept` 标明标题身份;`稳定标题` 是读者看到的标题文本。
|
|
13
|
+
|
|
14
|
+
[source,asciidoc]
|
|
15
|
+
----
|
|
16
|
+
引用规则参见 xref:stable-heading[稳定标题]。
|
|
17
|
+
----
|
|
18
|
+
|
|
19
|
+
这条 xref 表示参见目标标题。投影时,这条引用使用默认谓词 `aat:references`。
|
|
20
|
+
|
|
21
|
+
[source,asciidoc]
|
|
22
|
+
----
|
|
23
|
+
引用规则依赖 xref:stable-heading[稳定标题, rel=depends-on]。
|
|
24
|
+
----
|
|
25
|
+
|
|
26
|
+
写入 `rel=depends-on` 时,作者声明当前标题到目标标题的依赖关系。投影时,这条关系使用 `rel:depends-on`。
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
[#source-order-notation]
|
|
2
|
+
== 源文件编排号
|
|
3
|
+
|
|
4
|
+
源文件编排号写在 part 目录名和 chapter 文件名前部。indexterm:[源文件编排号]
|
|
5
|
+
|
|
6
|
+
part 目录使用 `100-`、`200-`、`300-`。chapter 文件在所属 part 内使用 `010-`、`020-`、`030-`。
|
|
7
|
+
|
|
8
|
+
中间插入新文件时,使用相邻编号之间的空位。
|
|
9
|
+
|
|
10
|
+
[source,text]
|
|
11
|
+
----
|
|
12
|
+
parts/100-source-surface/
|
|
13
|
+
parts/150-new-topic/
|
|
14
|
+
parts/200-identity-and-relation/
|
|
15
|
+
|
|
16
|
+
010-opening.adoc
|
|
17
|
+
015-new-context.adoc
|
|
18
|
+
020-main-flow.adoc
|
|
19
|
+
----
|
|
20
|
+
|
|
21
|
+
标题文本保留语义名称。长期引用的标题使用显式 ID。
|
|
22
|
+
|
|
23
|
+
编排号帮助维护者观察源文件顺序;显式 ID 帮助读者和工具链稳定引用标题。
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
本部从一段源文档出发,展示读者看到的写作意图和投影得到的结构事实。
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
[#role-identity]
|
|
2
|
+
== role 身份
|
|
3
|
+
|
|
4
|
+
`[#xref-rule.rule]` 里的 `.rule` 是 indexterm2:[role]。它把这个标题标成规则说明。
|
|
5
|
+
|
|
6
|
+
role 写在标题 attrlist 的点号 token 位置。
|
|
7
|
+
|
|
8
|
+
[source,asciidoc]
|
|
9
|
+
----
|
|
10
|
+
[#stable-heading.concept]
|
|
11
|
+
== 稳定标题
|
|
12
|
+
|
|
13
|
+
[#xref-rule.rule]
|
|
14
|
+
== 引用规则
|
|
15
|
+
----
|
|
16
|
+
|
|
17
|
+
`#stable-heading` 和 `#xref-rule` 是稳定 ID。`.concept` 和 `.rule` 标明标题身份。
|
|
18
|
+
|
|
19
|
+
[cols="1,2", options="header"]
|
|
20
|
+
|===
|
|
21
|
+
|写法 |读者看到的身份
|
|
22
|
+
|
|
23
|
+
|`[.concept]`
|
|
24
|
+
|标记概念说明。
|
|
25
|
+
|
|
26
|
+
|`[.rule]`
|
|
27
|
+
|标记规则说明。
|
|
28
|
+
|
|
29
|
+
|`[.example]`
|
|
30
|
+
|标记示例。
|
|
31
|
+
|===
|
|
32
|
+
|
|
33
|
+
role 的职责,是在全书范围内保持身份含义的稳定。
|
|
34
|
+
|
|
35
|
+
一旦一个 role 被定义——例如 `.rule` 代表规则说明——它在全书任何地方都只能代表这个身份,不能产生歧义。一本书需要多少种 role,取决于它所要描述的领域固有的本质复杂度。无论三种还是十种,每一种都必须是确定的。
|
|
36
|
+
|
|
37
|
+
读者和工具链依赖这种稳定理解来导航文本和提取结构。
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
[#relation-predicate]
|
|
2
|
+
== rel 关系谓词
|
|
3
|
+
|
|
4
|
+
indexterm:[relation predicate] `rel` 是 xref 边上的关系谓词。xref 写在哪个标题下面,哪个标题就是关系起点;xref 指向哪个标题,哪个标题就是关系终点。本书把这两个位置称为 source heading 和 target heading。
|
|
5
|
+
|
|
6
|
+
[source,asciidoc]
|
|
7
|
+
----
|
|
8
|
+
引用规则参见 xref:stable-heading[稳定标题]。
|
|
9
|
+
引用规则依赖 xref:stable-heading[稳定标题, rel=depends-on]。
|
|
10
|
+
----
|
|
11
|
+
|
|
12
|
+
第一行表示参见 `稳定标题`,投影为 `aat:references`。第二行写入 `rel=depends-on`,声明 `引用规则` 到 `稳定标题` 的依赖关系,投影为 `rel:depends-on`。
|
|
13
|
+
|
|
14
|
+
`rel` 会被读者和工具当作关系谓词。同一本书使用 rel 时,应保持谓词含义稳定。
|
|
15
|
+
|
|
16
|
+
[horizontal]
|
|
17
|
+
depends-on:: 当前标题的判断、规则或操作以目标标题为依据。阅读顺序和先读建议使用普通 xref 表达。
|
|
18
|
+
illustrates:: 当前标题提供目标标题的示例。
|
|
19
|
+
defines:: 当前标题给出目标标题所代表对象的定义。
|
|
20
|
+
constrains:: 当前标题对目标标题的合法写法或范围施加约束。
|
|
21
|
+
|
|
22
|
+
关系谓词描述标题之间的边。标题自身的身份使用 role 表达。
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
本部展示标题身份和引用关系。role 标明标题身份;rel 标明引用关系。 你应该在自己书籍里增加各类词表约定的章节。
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
[#surface-fields]
|
|
2
|
+
== 附加字段
|
|
3
|
+
|
|
4
|
+
named attributes 是写在源文档表面的字段。
|
|
5
|
+
|
|
6
|
+
[source,asciidoc]
|
|
7
|
+
----
|
|
8
|
+
[#example.example, owner=writing-team]
|
|
9
|
+
== 示例
|
|
10
|
+
|
|
11
|
+
示例说明 xref:stable-heading[稳定标题, rel=illustrates, weight=strong]。
|
|
12
|
+
----
|
|
13
|
+
|
|
14
|
+
`.example` 是 role。`owner=writing-team` 是标题附加字段。`weight=strong` 是 xref 边证据上的附加字段。
|
|
15
|
+
|
|
16
|
+
`owner=writing-team` 写在标题 attrlist 中,投影时成为标题字段。`weight=strong` 写在 xref 中,投影时成为边证据字段。
|
|
17
|
+
|
|
18
|
+
字段名和字段值来自本书自己的约定。同一本书使用附加字段时,应保持字段写法和字段含义稳定。
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
[#index-and-glossary]
|
|
2
|
+
== 索引词与术语表
|
|
3
|
+
|
|
4
|
+
索引词帮助读者在书后找到词。术语表解释本书采用的词。role 标明标题身份,rel 标明引用关系。
|
|
5
|
+
|
|
6
|
+
正文里已经自然出现该词时,使用可见索引词标记。需要补充未出现在正文里的索引入口时,使用隐藏索引词。
|
|
7
|
+
|
|
8
|
+
[source,asciidoc]
|
|
9
|
+
----
|
|
10
|
+
indexterm2:[role]
|
|
11
|
+
indexterm:[relation predicate]
|
|
12
|
+
----
|
|
13
|
+
|
|
14
|
+
稳定术语帮助作者、读者和维护者使用同一组词理解源文档。
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
本部展示字段、索引词和术语表。字段随源文档保留;索引词和术语表帮助读者找词、解词。
|
|
@@ -43,6 +43,10 @@ v0.1, 2026-05
|
|
|
43
43
|
|组织可独立发布的下册
|
|
44
44
|
|xref:books/06-lower-volume/book.adoc[06 下册]
|
|
45
45
|
|它用文本示例说明跨卷引用写法,但不真实依赖上册。
|
|
46
|
+
|
|
47
|
+
|让源书稿保持可读,同时保留可被工具链读取的结构关系
|
|
48
|
+
|xref:books/07-structured-writing-conventions/book.adoc[07 结构化书写约定标本]
|
|
49
|
+
|它展示标题、稳定 ID、role、xref、rel 和附加字段如何形成结构化书稿表面。
|
|
46
50
|
|===
|
|
47
51
|
|
|
48
52
|
== 样本书
|
|
@@ -54,6 +58,7 @@ v0.1, 2026-05
|
|
|
54
58
|
* xref:books/04-reference-manual/book.adoc[04 参考手册]:结构选择、路径规则和引用模式。
|
|
55
59
|
* xref:books/05-upper-volume/book.adoc[05 上册]:独立分卷的上册。
|
|
56
60
|
* xref:books/06-lower-volume/book.adoc[06 下册]:独立分卷的下册,并用示例说明跨卷引用写法。
|
|
61
|
+
* xref:books/07-structured-writing-conventions/book.adoc[07 结构化书写约定标本]:标题、稳定 ID、role、xref、rel 和附加字段的结构化写法。
|
|
57
62
|
|
|
58
63
|
== 工作区地图
|
|
59
64
|
|
|
@@ -66,3 +71,4 @@ image::shared/images/workspace-map.svg[多书工作区结构]
|
|
|
66
71
|
* 下册需要说明跨卷引用写法但不制造默认依赖:看 xref:books/06-lower-volume/book.adoc[06 下册]。
|
|
67
72
|
* 新增一本普通书:从 xref:books/01-starter-book/book.adoc[01 日常独立单书] 开始。
|
|
68
73
|
* 查路径、引用和增长规则:看 xref:books/04-reference-manual/book.adoc[04 参考手册]。
|
|
74
|
+
* 写需要被读者和工具同时理解的结构化源文本:看 xref:books/07-structured-writing-conventions/book.adoc[07 结构化书写约定标本]。
|