@openuji/render-respec 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/README.md +100 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +90 -0
- package/dist/cli.js.map +1 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +131 -0
- package/dist/index.js.map +1 -0
- package/dist/model.d.ts +214 -0
- package/dist/model.d.ts.map +1 -0
- package/dist/model.js +81 -0
- package/dist/model.js.map +1 -0
- package/dist/render/diagnostics.d.ts +19 -0
- package/dist/render/diagnostics.d.ts.map +1 -0
- package/dist/render/diagnostics.js +63 -0
- package/dist/render/diagnostics.js.map +1 -0
- package/dist/render/html.d.ts +8 -0
- package/dist/render/html.d.ts.map +1 -0
- package/dist/render/html.js +174 -0
- package/dist/render/html.js.map +1 -0
- package/dist/render/toc.d.ts +16 -0
- package/dist/render/toc.d.ts.map +1 -0
- package/dist/render/toc.js +60 -0
- package/dist/render/toc.js.map +1 -0
- package/dist/templates/respec.html +355 -0
- package/package.json +57 -0
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { LintResult } from '@openuji/speculator-lint';
|
|
2
|
+
export interface DiagnosticsByFile {
|
|
3
|
+
[file: string]: Array<{
|
|
4
|
+
code: string;
|
|
5
|
+
severity: 'error' | 'warning' | 'info';
|
|
6
|
+
message: string;
|
|
7
|
+
line?: number;
|
|
8
|
+
column?: number;
|
|
9
|
+
}>;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Group diagnostics by file
|
|
13
|
+
*/
|
|
14
|
+
export declare function groupDiagnosticsByFile(lintResult: LintResult): DiagnosticsByFile;
|
|
15
|
+
/**
|
|
16
|
+
* Render diagnostics as HTML
|
|
17
|
+
*/
|
|
18
|
+
export declare function renderDiagnosticsHtml(lintResult: LintResult): string;
|
|
19
|
+
//# sourceMappingURL=diagnostics.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"diagnostics.d.ts","sourceRoot":"","sources":["../../src/render/diagnostics.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAE3D,MAAM,WAAW,iBAAiB;IAC9B,CAAC,IAAI,EAAE,MAAM,GAAG,KAAK,CAAC;QAClB,IAAI,EAAE,MAAM,CAAC;QACb,QAAQ,EAAE,OAAO,GAAG,SAAS,GAAG,MAAM,CAAC;QACvC,OAAO,EAAE,MAAM,CAAC;QAChB,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,MAAM,CAAC,EAAE,MAAM,CAAC;KACnB,CAAC,CAAC;CACN;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CAAC,UAAU,EAAE,UAAU,GAAG,iBAAiB,CAkBhF;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,UAAU,EAAE,UAAU,GAAG,MAAM,CA2CpE"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Group diagnostics by file
|
|
3
|
+
*/
|
|
4
|
+
export function groupDiagnosticsByFile(lintResult) {
|
|
5
|
+
const grouped = {};
|
|
6
|
+
for (const diagnostic of lintResult.diagnostics) {
|
|
7
|
+
const file = diagnostic.file || 'unknown';
|
|
8
|
+
if (!grouped[file]) {
|
|
9
|
+
grouped[file] = [];
|
|
10
|
+
}
|
|
11
|
+
grouped[file].push({
|
|
12
|
+
code: diagnostic.code,
|
|
13
|
+
severity: diagnostic.severity,
|
|
14
|
+
message: diagnostic.message,
|
|
15
|
+
line: diagnostic.sourcePos?.line,
|
|
16
|
+
column: diagnostic.sourcePos?.column,
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
return grouped;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Render diagnostics as HTML
|
|
23
|
+
*/
|
|
24
|
+
export function renderDiagnosticsHtml(lintResult) {
|
|
25
|
+
const grouped = groupDiagnosticsByFile(lintResult);
|
|
26
|
+
const files = Object.keys(grouped);
|
|
27
|
+
if (files.length === 0) {
|
|
28
|
+
return '<div class="diagnostics-panel"><p>✅ No issues found</p></div>';
|
|
29
|
+
}
|
|
30
|
+
const sections = files.map(file => {
|
|
31
|
+
const diagnostics = grouped[file];
|
|
32
|
+
const items = diagnostics.map(d => {
|
|
33
|
+
const severityClass = `diagnostic-${d.severity}`;
|
|
34
|
+
const location = d.line ? ` (line ${d.line}${d.column ? `:${d.column}` : ''})` : '';
|
|
35
|
+
return `
|
|
36
|
+
<li class="${severityClass}">
|
|
37
|
+
<strong>${d.code}</strong>: ${d.message}${location}
|
|
38
|
+
</li>
|
|
39
|
+
`;
|
|
40
|
+
}).join('');
|
|
41
|
+
return `
|
|
42
|
+
<div class="diagnostic-file">
|
|
43
|
+
<h4>${file}</h4>
|
|
44
|
+
<ul class="diagnostic-list">
|
|
45
|
+
${items}
|
|
46
|
+
</ul>
|
|
47
|
+
</div>
|
|
48
|
+
`;
|
|
49
|
+
}).join('');
|
|
50
|
+
const errorCount = lintResult.diagnostics.filter(d => d.severity === 'error').length;
|
|
51
|
+
const warningCount = lintResult.diagnostics.filter(d => d.severity === 'warning').length;
|
|
52
|
+
return `
|
|
53
|
+
<div class="diagnostics-panel">
|
|
54
|
+
<h3>📋 Diagnostics</h3>
|
|
55
|
+
<p class="diagnostic-summary">
|
|
56
|
+
${errorCount} error${errorCount !== 1 ? 's' : ''},
|
|
57
|
+
${warningCount} warning${warningCount !== 1 ? 's' : ''}
|
|
58
|
+
</p>
|
|
59
|
+
${sections}
|
|
60
|
+
</div>
|
|
61
|
+
`;
|
|
62
|
+
}
|
|
63
|
+
//# sourceMappingURL=diagnostics.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"diagnostics.js","sourceRoot":"","sources":["../../src/render/diagnostics.ts"],"names":[],"mappings":"AAYA;;GAEG;AACH,MAAM,UAAU,sBAAsB,CAAC,UAAsB;IACzD,MAAM,OAAO,GAAsB,EAAE,CAAC;IAEtC,KAAK,MAAM,UAAU,IAAI,UAAU,CAAC,WAAW,EAAE,CAAC;QAC9C,MAAM,IAAI,GAAG,UAAU,CAAC,IAAI,IAAI,SAAS,CAAC;QAC1C,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;YACjB,OAAO,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC;QACvB,CAAC;QACD,OAAO,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC;YACf,IAAI,EAAE,UAAU,CAAC,IAAI;YACrB,QAAQ,EAAE,UAAU,CAAC,QAAQ;YAC7B,OAAO,EAAE,UAAU,CAAC,OAAO;YAC3B,IAAI,EAAE,UAAU,CAAC,SAAS,EAAE,IAAI;YAChC,MAAM,EAAE,UAAU,CAAC,SAAS,EAAE,MAAM;SACvC,CAAC,CAAC;IACP,CAAC;IAED,OAAO,OAAO,CAAC;AACnB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,qBAAqB,CAAC,UAAsB;IACxD,MAAM,OAAO,GAAG,sBAAsB,CAAC,UAAU,CAAC,CAAC;IACnD,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAEnC,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACrB,OAAO,+DAA+D,CAAC;IAC3E,CAAC;IAED,MAAM,QAAQ,GAAG,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE;QAC9B,MAAM,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;QAClC,MAAM,KAAK,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE;YAC9B,MAAM,aAAa,GAAG,cAAc,CAAC,CAAC,QAAQ,EAAE,CAAC;YACjD,MAAM,QAAQ,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;YACpF,OAAO;6BACU,aAAa;8BACZ,CAAC,CAAC,IAAI,cAAc,CAAC,CAAC,OAAO,GAAG,QAAQ;;aAEzD,CAAC;QACN,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QAEZ,OAAO;;sBAEO,IAAI;;sBAEJ,KAAK;;;SAGlB,CAAC;IACN,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAEZ,MAAM,UAAU,GAAG,UAAU,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC,MAAM,CAAC;IACrF,MAAM,YAAY,GAAG,UAAU,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,MAAM,CAAC;IAEzF,OAAO;;;;kBAIO,UAAU,SAAS,UAAU,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE;kBAC9C,YAAY,WAAW,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE;;cAExD,QAAQ;;KAEjB,CAAC;AACN,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { Workspace } from '@openuji/speculator';
|
|
2
|
+
import type { LintResult } from '@openuji/speculator-lint';
|
|
3
|
+
import type { ReSpecConfig } from '../model.js';
|
|
4
|
+
/**
|
|
5
|
+
* Generate complete ReSpec HTML document
|
|
6
|
+
*/
|
|
7
|
+
export declare function generateHTML(workspace: Workspace, config: ReSpecConfig, lintResult: LintResult): Promise<string>;
|
|
8
|
+
//# sourceMappingURL=html.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"html.d.ts","sourceRoot":"","sources":["../../src/render/html.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAY,MAAM,qBAAqB,CAAC;AAC/D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAC3D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAOhD;;GAEG;AACH,wBAAsB,YAAY,CAC9B,SAAS,EAAE,SAAS,EACpB,MAAM,EAAE,YAAY,EACpB,UAAU,EAAE,UAAU,GACvB,OAAO,CAAC,MAAM,CAAC,CA6DjB"}
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
import nunjucks from 'nunjucks';
|
|
2
|
+
import { dirname, join } from 'path';
|
|
3
|
+
import { fileURLToPath } from 'url';
|
|
4
|
+
import { generateToc, renderTocHtml } from './toc.js';
|
|
5
|
+
import { renderDiagnosticsHtml } from './diagnostics.js';
|
|
6
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
7
|
+
const __dirname = dirname(__filename);
|
|
8
|
+
/**
|
|
9
|
+
* Generate complete ReSpec HTML document
|
|
10
|
+
*/
|
|
11
|
+
export async function generateHTML(workspace, config, lintResult) {
|
|
12
|
+
// Get the entry document (first document in workspace)
|
|
13
|
+
const document = workspace.documents[0];
|
|
14
|
+
if (!document) {
|
|
15
|
+
throw new Error('No document found in workspace');
|
|
16
|
+
}
|
|
17
|
+
// Generate TOC
|
|
18
|
+
const tocEntries = generateToc(document, config.maxTocLevel);
|
|
19
|
+
const tocHtml = renderTocHtml(tocEntries);
|
|
20
|
+
// Render main content from AST
|
|
21
|
+
const contentHtml = renderDocumentContent(document);
|
|
22
|
+
// Render diagnostics
|
|
23
|
+
const diagnosticsHtml = renderDiagnosticsHtml(lintResult);
|
|
24
|
+
// Prepare template data
|
|
25
|
+
const templateData = {
|
|
26
|
+
// Document metadata
|
|
27
|
+
title: document.metadata?.title || 'Specification',
|
|
28
|
+
subtitle: config.subtitle,
|
|
29
|
+
// Status and dates
|
|
30
|
+
specStatus: config.specStatus,
|
|
31
|
+
publishDate: config.publishDate || new Date().toISOString().split('T')[0],
|
|
32
|
+
previousPublishDate: config.previousPublishDate,
|
|
33
|
+
// People
|
|
34
|
+
editors: config.editors || [],
|
|
35
|
+
authors: config.authors || [],
|
|
36
|
+
// Organization
|
|
37
|
+
group: config.group,
|
|
38
|
+
wg: config.wg,
|
|
39
|
+
wgURI: config.wgURI,
|
|
40
|
+
// Content
|
|
41
|
+
abstract: extractAbstract(document),
|
|
42
|
+
toc: tocHtml,
|
|
43
|
+
content: contentHtml,
|
|
44
|
+
diagnostics: diagnosticsHtml,
|
|
45
|
+
// GitHub
|
|
46
|
+
github: config.github,
|
|
47
|
+
// Copyright
|
|
48
|
+
copyrightStart: config.copyrightStart || new Date().getFullYear().toString(),
|
|
49
|
+
// Logos
|
|
50
|
+
logos: config.logos || [],
|
|
51
|
+
};
|
|
52
|
+
// Configure Nunjucks
|
|
53
|
+
const templatesDir = join(__dirname, '..', 'templates');
|
|
54
|
+
nunjucks.configure(templatesDir, { autoescape: false });
|
|
55
|
+
// Render template
|
|
56
|
+
const html = nunjucks.render('respec.html', templateData);
|
|
57
|
+
return html;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Extract abstract section from document
|
|
61
|
+
*/
|
|
62
|
+
function extractAbstract(document) {
|
|
63
|
+
if (!document.children)
|
|
64
|
+
return 'No abstract provided.';
|
|
65
|
+
for (const child of document.children) {
|
|
66
|
+
if (child.type === 'section') {
|
|
67
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
68
|
+
const section = child;
|
|
69
|
+
if (section.id === 'abstract' || section.data?.respecClass === 'abstract') {
|
|
70
|
+
return renderNode(section);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
return 'No abstract provided.';
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Render document content as HTML
|
|
78
|
+
*/
|
|
79
|
+
function renderDocumentContent(document) {
|
|
80
|
+
if (!document.children)
|
|
81
|
+
return '';
|
|
82
|
+
return document.children
|
|
83
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
84
|
+
.filter((child) => child.id !== 'abstract') // Skip abstract, it's rendered separately
|
|
85
|
+
.map(child => renderNode(child))
|
|
86
|
+
.join('\n');
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Recursively render an AST node to HTML
|
|
90
|
+
*/
|
|
91
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
92
|
+
function renderNode(node) {
|
|
93
|
+
if (!node || typeof node !== 'object')
|
|
94
|
+
return '';
|
|
95
|
+
switch (node.type) {
|
|
96
|
+
case 'section':
|
|
97
|
+
return renderSection(node);
|
|
98
|
+
case 'paragraph':
|
|
99
|
+
return renderParagraph(node);
|
|
100
|
+
case 'heading':
|
|
101
|
+
return renderHeading(node);
|
|
102
|
+
case 'text':
|
|
103
|
+
return escapeHtml(node.value || '');
|
|
104
|
+
case 'definition':
|
|
105
|
+
return renderDefinition(node);
|
|
106
|
+
case 'reference':
|
|
107
|
+
return renderReference(node);
|
|
108
|
+
case 'code':
|
|
109
|
+
return `<code>${escapeHtml(node.value || '')}</code>`;
|
|
110
|
+
case 'emphasis':
|
|
111
|
+
return `<em>${renderChildren(node)}</em>`;
|
|
112
|
+
case 'strong':
|
|
113
|
+
return `<strong>${renderChildren(node)}</strong>`;
|
|
114
|
+
case 'link':
|
|
115
|
+
return `<a href="${escapeHtml(node.href || '#')}">${renderChildren(node)}</a>`;
|
|
116
|
+
case 'list':
|
|
117
|
+
return renderList(node);
|
|
118
|
+
case 'listItem':
|
|
119
|
+
return `<li>${renderChildren(node)}</li>`;
|
|
120
|
+
default:
|
|
121
|
+
return renderChildren(node);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
125
|
+
function renderSection(node) {
|
|
126
|
+
const id = node.id ? ` id="${escapeHtml(node.id)}"` : '';
|
|
127
|
+
const className = node.data?.respecClass ? ` class="${escapeHtml(node.data.respecClass)}"` : '';
|
|
128
|
+
const title = node.title ? `<h${node.level || 2}>${escapeHtml(node.title)}</h${node.level || 2}>` : '';
|
|
129
|
+
const content = renderChildren(node);
|
|
130
|
+
return `<section${id}${className}>\n${title}\n${content}\n</section>`;
|
|
131
|
+
}
|
|
132
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
133
|
+
function renderParagraph(node) {
|
|
134
|
+
return `<p>${renderChildren(node)}</p>`;
|
|
135
|
+
}
|
|
136
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
137
|
+
function renderHeading(node) {
|
|
138
|
+
const level = node.level || 2;
|
|
139
|
+
return `<h${level}>${renderChildren(node)}</h${level}>`;
|
|
140
|
+
}
|
|
141
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
142
|
+
function renderDefinition(node) {
|
|
143
|
+
const term = node.term || renderChildren(node);
|
|
144
|
+
const id = node.id ? ` id="${escapeHtml(node.id)}"` : '';
|
|
145
|
+
return `<dfn${id}>${escapeHtml(term)}</dfn>`;
|
|
146
|
+
}
|
|
147
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
148
|
+
function renderReference(node) {
|
|
149
|
+
const targetTerm = node.targetTerm || renderChildren(node);
|
|
150
|
+
const href = node.resolved?.id ? `#${escapeHtml(node.resolved.id)}` : '#';
|
|
151
|
+
return `<a href="${href}" class="internalDFN">${escapeHtml(targetTerm)}</a>`;
|
|
152
|
+
}
|
|
153
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
154
|
+
function renderList(node) {
|
|
155
|
+
const tag = node.ordered ? 'ol' : 'ul';
|
|
156
|
+
const content = renderChildren(node);
|
|
157
|
+
return `<${tag}>${content}</${tag}>`;
|
|
158
|
+
}
|
|
159
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
160
|
+
function renderChildren(node) {
|
|
161
|
+
if (!node.children || !Array.isArray(node.children))
|
|
162
|
+
return '';
|
|
163
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
164
|
+
return node.children.map((child) => renderNode(child)).join('');
|
|
165
|
+
}
|
|
166
|
+
function escapeHtml(text) {
|
|
167
|
+
return text
|
|
168
|
+
.replace(/&/g, '&')
|
|
169
|
+
.replace(/</g, '<')
|
|
170
|
+
.replace(/>/g, '>')
|
|
171
|
+
.replace(/"/g, '"')
|
|
172
|
+
.replace(/'/g, ''');
|
|
173
|
+
}
|
|
174
|
+
//# sourceMappingURL=html.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"html.js","sourceRoot":"","sources":["../../src/render/html.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,MAAM,UAAU,CAAC;AAChC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AACrC,OAAO,EAAE,aAAa,EAAE,MAAM,KAAK,CAAC;AAIpC,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACtD,OAAO,EAAE,qBAAqB,EAAE,MAAM,kBAAkB,CAAC;AAEzD,MAAM,UAAU,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAClD,MAAM,SAAS,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;AAEtC;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAC9B,SAAoB,EACpB,MAAoB,EACpB,UAAsB;IAEtB,uDAAuD;IACvD,MAAM,QAAQ,GAAG,SAAS,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;IACxC,IAAI,CAAC,QAAQ,EAAE,CAAC;QACZ,MAAM,IAAI,KAAK,CAAC,gCAAgC,CAAC,CAAC;IACtD,CAAC;IAED,eAAe;IACf,MAAM,UAAU,GAAG,WAAW,CAAC,QAAQ,EAAE,MAAM,CAAC,WAAW,CAAC,CAAC;IAC7D,MAAM,OAAO,GAAG,aAAa,CAAC,UAAU,CAAC,CAAC;IAE1C,+BAA+B;IAC/B,MAAM,WAAW,GAAG,qBAAqB,CAAC,QAAQ,CAAC,CAAC;IAEpD,qBAAqB;IACrB,MAAM,eAAe,GAAG,qBAAqB,CAAC,UAAU,CAAC,CAAC;IAE1D,wBAAwB;IACxB,MAAM,YAAY,GAAG;QACjB,oBAAoB;QACpB,KAAK,EAAE,QAAQ,CAAC,QAAQ,EAAE,KAAK,IAAI,eAAe;QAClD,QAAQ,EAAE,MAAM,CAAC,QAAQ;QAEzB,mBAAmB;QACnB,UAAU,EAAE,MAAM,CAAC,UAAU;QAC7B,WAAW,EAAE,MAAM,CAAC,WAAW,IAAI,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;QACzE,mBAAmB,EAAE,MAAM,CAAC,mBAAmB;QAE/C,SAAS;QACT,OAAO,EAAE,MAAM,CAAC,OAAO,IAAI,EAAE;QAC7B,OAAO,EAAE,MAAM,CAAC,OAAO,IAAI,EAAE;QAE7B,eAAe;QACf,KAAK,EAAE,MAAM,CAAC,KAAK;QACnB,EAAE,EAAE,MAAM,CAAC,EAAE;QACb,KAAK,EAAE,MAAM,CAAC,KAAK;QAEnB,UAAU;QACV,QAAQ,EAAE,eAAe,CAAC,QAAQ,CAAC;QACnC,GAAG,EAAE,OAAO;QACZ,OAAO,EAAE,WAAW;QACpB,WAAW,EAAE,eAAe;QAE5B,SAAS;QACT,MAAM,EAAE,MAAM,CAAC,MAAM;QAErB,YAAY;QACZ,cAAc,EAAE,MAAM,CAAC,cAAc,IAAI,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,QAAQ,EAAE;QAE5E,QAAQ;QACR,KAAK,EAAE,MAAM,CAAC,KAAK,IAAI,EAAE;KAC5B,CAAC;IAEF,qBAAqB;IACrB,MAAM,YAAY,GAAG,IAAI,CAAC,SAAS,EAAE,IAAI,EAAE,WAAW,CAAC,CAAC;IACxD,QAAQ,CAAC,SAAS,CAAC,YAAY,EAAE,EAAE,UAAU,EAAE,KAAK,EAAE,CAAC,CAAC;IAExD,kBAAkB;IAClB,MAAM,IAAI,GAAG,QAAQ,CAAC,MAAM,CAAC,aAAa,EAAE,YAAY,CAAC,CAAC;IAE1D,OAAO,IAAI,CAAC;AAChB,CAAC;AAED;;GAEG;AACH,SAAS,eAAe,CAAC,QAAkB;IACvC,IAAI,CAAC,QAAQ,CAAC,QAAQ;QAAE,OAAO,uBAAuB,CAAC;IAEvD,KAAK,MAAM,KAAK,IAAI,QAAQ,CAAC,QAAQ,EAAE,CAAC;QACpC,IAAI,KAAK,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;YAC3B,8DAA8D;YAC9D,MAAM,OAAO,GAAG,KAAY,CAAC;YAC7B,IAAI,OAAO,CAAC,EAAE,KAAK,UAAU,IAAI,OAAO,CAAC,IAAI,EAAE,WAAW,KAAK,UAAU,EAAE,CAAC;gBACxE,OAAO,UAAU,CAAC,OAAO,CAAC,CAAC;YAC/B,CAAC;QACL,CAAC;IACL,CAAC;IAED,OAAO,uBAAuB,CAAC;AACnC,CAAC;AAED;;GAEG;AACH,SAAS,qBAAqB,CAAC,QAAkB;IAC7C,IAAI,CAAC,QAAQ,CAAC,QAAQ;QAAE,OAAO,EAAE,CAAC;IAElC,OAAO,QAAQ,CAAC,QAAQ;QACpB,8DAA8D;SAC7D,MAAM,CAAC,CAAC,KAAU,EAAE,EAAE,CAAC,KAAK,CAAC,EAAE,KAAK,UAAU,CAAC,CAAC,0CAA0C;SAC1F,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;SAC/B,IAAI,CAAC,IAAI,CAAC,CAAC;AACpB,CAAC;AAED;;GAEG;AACH,8DAA8D;AAC9D,SAAS,UAAU,CAAC,IAAS;IACzB,IAAI,CAAC,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ;QAAE,OAAO,EAAE,CAAC;IAEjD,QAAQ,IAAI,CAAC,IAAI,EAAE,CAAC;QAChB,KAAK,SAAS;YACV,OAAO,aAAa,CAAC,IAAI,CAAC,CAAC;QAC/B,KAAK,WAAW;YACZ,OAAO,eAAe,CAAC,IAAI,CAAC,CAAC;QACjC,KAAK,SAAS;YACV,OAAO,aAAa,CAAC,IAAI,CAAC,CAAC;QAC/B,KAAK,MAAM;YACP,OAAO,UAAU,CAAC,IAAI,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC;QACxC,KAAK,YAAY;YACb,OAAO,gBAAgB,CAAC,IAAI,CAAC,CAAC;QAClC,KAAK,WAAW;YACZ,OAAO,eAAe,CAAC,IAAI,CAAC,CAAC;QACjC,KAAK,MAAM;YACP,OAAO,SAAS,UAAU,CAAC,IAAI,CAAC,KAAK,IAAI,EAAE,CAAC,SAAS,CAAC;QAC1D,KAAK,UAAU;YACX,OAAO,OAAO,cAAc,CAAC,IAAI,CAAC,OAAO,CAAC;QAC9C,KAAK,QAAQ;YACT,OAAO,WAAW,cAAc,CAAC,IAAI,CAAC,WAAW,CAAC;QACtD,KAAK,MAAM;YACP,OAAO,YAAY,UAAU,CAAC,IAAI,CAAC,IAAI,IAAI,GAAG,CAAC,KAAK,cAAc,CAAC,IAAI,CAAC,MAAM,CAAC;QACnF,KAAK,MAAM;YACP,OAAO,UAAU,CAAC,IAAI,CAAC,CAAC;QAC5B,KAAK,UAAU;YACX,OAAO,OAAO,cAAc,CAAC,IAAI,CAAC,OAAO,CAAC;QAC9C;YACI,OAAO,cAAc,CAAC,IAAI,CAAC,CAAC;IACpC,CAAC;AACL,CAAC;AAED,8DAA8D;AAC9D,SAAS,aAAa,CAAC,IAAS;IAC5B,MAAM,EAAE,GAAG,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;IACzD,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,EAAE,WAAW,CAAC,CAAC,CAAC,WAAW,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;IAChG,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,KAAK,IAAI,CAAC,IAAI,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,IAAI,CAAC,KAAK,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;IACvG,MAAM,OAAO,GAAG,cAAc,CAAC,IAAI,CAAC,CAAC;IAErC,OAAO,WAAW,EAAE,GAAG,SAAS,MAAM,KAAK,KAAK,OAAO,cAAc,CAAC;AAC1E,CAAC;AAED,8DAA8D;AAC9D,SAAS,eAAe,CAAC,IAAS;IAC9B,OAAO,MAAM,cAAc,CAAC,IAAI,CAAC,MAAM,CAAC;AAC5C,CAAC;AAED,8DAA8D;AAC9D,SAAS,aAAa,CAAC,IAAS;IAC5B,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,IAAI,CAAC,CAAC;IAC9B,OAAO,KAAK,KAAK,IAAI,cAAc,CAAC,IAAI,CAAC,MAAM,KAAK,GAAG,CAAC;AAC5D,CAAC;AAED,8DAA8D;AAC9D,SAAS,gBAAgB,CAAC,IAAS;IAC/B,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,IAAI,cAAc,CAAC,IAAI,CAAC,CAAC;IAC/C,MAAM,EAAE,GAAG,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;IACzD,OAAO,OAAO,EAAE,IAAI,UAAU,CAAC,IAAI,CAAC,QAAQ,CAAC;AACjD,CAAC;AAED,8DAA8D;AAC9D,SAAS,eAAe,CAAC,IAAS;IAC9B,MAAM,UAAU,GAAG,IAAI,CAAC,UAAU,IAAI,cAAc,CAAC,IAAI,CAAC,CAAC;IAC3D,MAAM,IAAI,GAAG,IAAI,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,UAAU,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC;IAC1E,OAAO,YAAY,IAAI,yBAAyB,UAAU,CAAC,UAAU,CAAC,MAAM,CAAC;AACjF,CAAC;AAED,8DAA8D;AAC9D,SAAS,UAAU,CAAC,IAAS;IACzB,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;IACvC,MAAM,OAAO,GAAG,cAAc,CAAC,IAAI,CAAC,CAAC;IACrC,OAAO,IAAI,GAAG,IAAI,OAAO,KAAK,GAAG,GAAG,CAAC;AACzC,CAAC;AAED,8DAA8D;AAC9D,SAAS,cAAc,CAAC,IAAS;IAC7B,IAAI,CAAC,IAAI,CAAC,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC;QAAE,OAAO,EAAE,CAAC;IAC/D,8DAA8D;IAC9D,OAAO,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,KAAU,EAAE,EAAE,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;AACzE,CAAC;AAED,SAAS,UAAU,CAAC,IAAY;IAC5B,OAAO,IAAI;SACN,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC;SACtB,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC;SACrB,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC;SACrB,OAAO,CAAC,IAAI,EAAE,QAAQ,CAAC;SACvB,OAAO,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;AACjC,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { Document } from '@openuji/speculator';
|
|
2
|
+
export interface TocEntry {
|
|
3
|
+
id: string;
|
|
4
|
+
title: string;
|
|
5
|
+
level: number;
|
|
6
|
+
children: TocEntry[];
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Generate Table of Contents from document sections
|
|
10
|
+
*/
|
|
11
|
+
export declare function generateToc(document: Document, maxLevel?: number): TocEntry[];
|
|
12
|
+
/**
|
|
13
|
+
* Render TOC as HTML
|
|
14
|
+
*/
|
|
15
|
+
export declare function renderTocHtml(entries: TocEntry[], level?: number): string;
|
|
16
|
+
//# sourceMappingURL=toc.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"toc.d.ts","sourceRoot":"","sources":["../../src/render/toc.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAEpD,MAAM,WAAW,QAAQ;IACrB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,QAAQ,EAAE,CAAC;CACxB;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,QAAQ,EAAE,QAAQ,EAAE,QAAQ,GAAE,MAAU,GAAG,QAAQ,EAAE,CAyChF;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,QAAQ,EAAE,EAAE,KAAK,GAAE,MAAU,GAAG,MAAM,CAgB5E"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generate Table of Contents from document sections
|
|
3
|
+
*/
|
|
4
|
+
export function generateToc(document, maxLevel = 3) {
|
|
5
|
+
const toc = [];
|
|
6
|
+
const stack = [];
|
|
7
|
+
// Walk through document children (sections)
|
|
8
|
+
if (document.children) {
|
|
9
|
+
for (const child of document.children) {
|
|
10
|
+
if (child.type === 'section') {
|
|
11
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
12
|
+
const section = child;
|
|
13
|
+
const level = section.level || 1;
|
|
14
|
+
// Only include up to maxLevel
|
|
15
|
+
if (level > maxLevel)
|
|
16
|
+
continue;
|
|
17
|
+
const entry = {
|
|
18
|
+
id: section.id || `section-${toc.length}`,
|
|
19
|
+
title: section.title || 'Untitled Section',
|
|
20
|
+
level,
|
|
21
|
+
children: [],
|
|
22
|
+
};
|
|
23
|
+
// Determine where to place this entry
|
|
24
|
+
while (stack.length > 0 && stack[stack.length - 1].level >= level) {
|
|
25
|
+
stack.pop();
|
|
26
|
+
}
|
|
27
|
+
if (stack.length === 0) {
|
|
28
|
+
// Top-level entry
|
|
29
|
+
toc.push(entry);
|
|
30
|
+
}
|
|
31
|
+
else {
|
|
32
|
+
// Nested entry
|
|
33
|
+
stack[stack.length - 1].entry.children.push(entry);
|
|
34
|
+
}
|
|
35
|
+
stack.push({ entry, level });
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
return toc;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Render TOC as HTML
|
|
43
|
+
*/
|
|
44
|
+
export function renderTocHtml(entries, level = 1) {
|
|
45
|
+
if (entries.length === 0)
|
|
46
|
+
return '';
|
|
47
|
+
const items = entries.map(entry => {
|
|
48
|
+
const children = renderTocHtml(entry.children, level + 1);
|
|
49
|
+
return `
|
|
50
|
+
<li class="tocline">
|
|
51
|
+
<a href="#${entry.id}" class="tocxref">
|
|
52
|
+
<span class="secno"></span> ${entry.title}
|
|
53
|
+
</a>
|
|
54
|
+
${children ? `<ol class="toc">${children}</ol>` : ''}
|
|
55
|
+
</li>
|
|
56
|
+
`;
|
|
57
|
+
}).join('');
|
|
58
|
+
return items;
|
|
59
|
+
}
|
|
60
|
+
//# sourceMappingURL=toc.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"toc.js","sourceRoot":"","sources":["../../src/render/toc.ts"],"names":[],"mappings":"AASA;;GAEG;AACH,MAAM,UAAU,WAAW,CAAC,QAAkB,EAAE,WAAmB,CAAC;IAChE,MAAM,GAAG,GAAe,EAAE,CAAC;IAC3B,MAAM,KAAK,GAA8C,EAAE,CAAC;IAE5D,4CAA4C;IAC5C,IAAI,QAAQ,CAAC,QAAQ,EAAE,CAAC;QACpB,KAAK,MAAM,KAAK,IAAI,QAAQ,CAAC,QAAQ,EAAE,CAAC;YACpC,IAAI,KAAK,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;gBAC3B,8DAA8D;gBAC9D,MAAM,OAAO,GAAG,KAAY,CAAC;gBAC7B,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,IAAI,CAAC,CAAC;gBAEjC,8BAA8B;gBAC9B,IAAI,KAAK,GAAG,QAAQ;oBAAE,SAAS;gBAE/B,MAAM,KAAK,GAAa;oBACpB,EAAE,EAAE,OAAO,CAAC,EAAE,IAAI,WAAW,GAAG,CAAC,MAAM,EAAE;oBACzC,KAAK,EAAE,OAAO,CAAC,KAAK,IAAI,kBAAkB;oBAC1C,KAAK;oBACL,QAAQ,EAAE,EAAE;iBACf,CAAC;gBAEF,sCAAsC;gBACtC,OAAO,KAAK,CAAC,MAAM,GAAG,CAAC,IAAI,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,KAAK,IAAI,KAAK,EAAE,CAAC;oBAChE,KAAK,CAAC,GAAG,EAAE,CAAC;gBAChB,CAAC;gBAED,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;oBACrB,kBAAkB;oBAClB,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;gBACpB,CAAC;qBAAM,CAAC;oBACJ,eAAe;oBACf,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;gBACvD,CAAC;gBAED,KAAK,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC;YACjC,CAAC;QACL,CAAC;IACL,CAAC;IAED,OAAO,GAAG,CAAC;AACf,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,aAAa,CAAC,OAAmB,EAAE,QAAgB,CAAC;IAChE,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IAEpC,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE;QAC9B,MAAM,QAAQ,GAAG,aAAa,CAAC,KAAK,CAAC,QAAQ,EAAE,KAAK,GAAG,CAAC,CAAC,CAAC;QAC1D,OAAO;;4BAEa,KAAK,CAAC,EAAE;kDACc,KAAK,CAAC,KAAK;;kBAE3C,QAAQ,CAAC,CAAC,CAAC,mBAAmB,QAAQ,OAAO,CAAC,CAAC,CAAC,EAAE;;SAE3D,CAAC;IACN,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAEZ,OAAO,KAAK,CAAC;AACjB,CAAC"}
|