@oml/cli 0.12.0 → 0.14.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 +29 -21
- package/out/{auth.d.ts → auth/auth.d.ts} +7 -0
- package/out/{auth.js → auth/auth.js} +42 -3
- package/out/auth/auth.js.map +1 -0
- package/out/{platform-constants.js → auth/constants.js} +1 -1
- package/out/auth/constants.js.map +1 -0
- package/out/{platform.d.ts → auth/platform.d.ts} +5 -7
- package/out/{platform.js → auth/platform.js} +39 -17
- package/out/auth/platform.js.map +1 -0
- package/out/cli.d.ts +6 -0
- package/out/cli.js +214 -59
- package/out/cli.js.map +1 -1
- package/out/commands/export.d.ts +8 -0
- package/out/commands/export.js +27 -0
- package/out/commands/export.js.map +1 -0
- package/out/commands/lint.d.ts +22 -2
- package/out/commands/lint.js +64 -18
- package/out/commands/lint.js.map +1 -1
- package/out/commands/reason.d.ts +2 -9
- package/out/commands/reason.js +52 -48
- package/out/commands/reason.js.map +1 -1
- package/out/commands/render.d.ts +1 -9
- package/out/commands/render.js +15 -726
- package/out/commands/render.js.map +1 -1
- package/out/commands/server/actions.d.ts +22 -0
- package/out/commands/server/actions.js +394 -0
- package/out/commands/server/actions.js.map +1 -0
- package/out/commands/server/require.d.ts +1 -0
- package/out/commands/server/require.js +89 -0
- package/out/commands/server/require.js.map +1 -0
- package/out/commands/server/rest.d.ts +2 -0
- package/out/commands/server/rest.js +117 -0
- package/out/commands/server/rest.js.map +1 -0
- package/out/commands/validate.d.ts +3 -3
- package/out/commands/validate.js +35 -171
- package/out/commands/validate.js.map +1 -1
- package/package.json +5 -7
- package/src/{auth.ts → auth/auth.ts} +54 -3
- package/src/{platform.ts → auth/platform.ts} +41 -17
- package/src/cli.ts +249 -59
- package/src/commands/export.ts +54 -0
- package/src/commands/lint.ts +88 -18
- package/src/commands/reason.ts +69 -56
- package/src/commands/render.ts +23 -995
- package/src/commands/server/actions.ts +480 -0
- package/src/commands/server/require.ts +99 -0
- package/src/commands/server/rest.ts +135 -0
- package/src/commands/validate.ts +46 -207
- package/out/auth.js.map +0 -1
- package/out/backend/backend-types.d.ts +0 -21
- package/out/backend/backend-types.js +0 -3
- package/out/backend/backend-types.js.map +0 -1
- package/out/backend/create-backend.d.ts +0 -2
- package/out/backend/create-backend.js +0 -6
- package/out/backend/create-backend.js.map +0 -1
- package/out/backend/direct-backend.d.ts +0 -20
- package/out/backend/direct-backend.js +0 -150
- package/out/backend/direct-backend.js.map +0 -1
- package/out/backend/reasoned-output.d.ts +0 -38
- package/out/backend/reasoned-output.js +0 -568
- package/out/backend/reasoned-output.js.map +0 -1
- package/out/commands/closure.d.ts +0 -33
- package/out/commands/closure.js +0 -537
- package/out/commands/closure.js.map +0 -1
- package/out/commands/compile.d.ts +0 -11
- package/out/commands/compile.js +0 -63
- package/out/commands/compile.js.map +0 -1
- package/out/platform-constants.js.map +0 -1
- package/out/platform.js.map +0 -1
- package/src/backend/backend-types.ts +0 -27
- package/src/backend/create-backend.ts +0 -8
- package/src/backend/direct-backend.ts +0 -169
- package/src/backend/reasoned-output.ts +0 -697
- package/src/commands/closure.ts +0 -624
- package/src/commands/compile.ts +0 -88
- /package/out/{platform-constants.d.ts → auth/constants.d.ts} +0 -0
- /package/src/{platform-constants.ts → auth/constants.ts} +0 -0
package/out/commands/render.js
CHANGED
|
@@ -1,735 +1,24 @@
|
|
|
1
1
|
// Copyright (c) 2026 Modelware. All rights reserved.
|
|
2
2
|
import chalk from 'chalk';
|
|
3
|
-
import * as url from 'node:url';
|
|
4
|
-
import * as fs from 'node:fs/promises';
|
|
5
3
|
import * as path from 'node:path';
|
|
6
|
-
import { createRequire } from 'node:module';
|
|
7
|
-
import { createHash } from 'node:crypto';
|
|
8
|
-
import { MarkdownHandlerRegistry, MarkdownPreviewRuntime, extractLeadingFrontMatter, stripLeadingFrontMatter } from '@oml/markdown';
|
|
9
|
-
import { runWithIriLabelSnapshot } from '@oml/markdown/renderers';
|
|
10
|
-
import { STATIC_MARKDOWN_RUNTIME_BUNDLE_FILE, STATIC_MARKDOWN_RUNTIME_CSS } from '@oml/markdown/static';
|
|
11
|
-
import { normalizeFormatExtension } from '../backend/reasoned-output.js';
|
|
12
|
-
import { createBackend } from '../backend/create-backend.js';
|
|
13
4
|
import { failCli } from '../cli-error.js';
|
|
14
5
|
import { formatDuration } from '../util.js';
|
|
15
|
-
import {
|
|
16
|
-
import {
|
|
17
|
-
const markdownRuntime = new MarkdownPreviewRuntime(new MarkdownHandlerRegistry());
|
|
18
|
-
const SUPPORTED_MD_BLOCK_KINDS = new Set([
|
|
19
|
-
'table',
|
|
20
|
-
'tree',
|
|
21
|
-
'graph',
|
|
22
|
-
'chart',
|
|
23
|
-
'diagram',
|
|
24
|
-
'list',
|
|
25
|
-
'text',
|
|
26
|
-
'matrix',
|
|
27
|
-
'table-editor'
|
|
28
|
-
]);
|
|
29
|
-
const LINK_ATTRIBUTE_KEYS = new Set(['href', 'src', 'xlinkHref', 'xlink:href']);
|
|
6
|
+
import { restPost } from './server/rest.js';
|
|
7
|
+
import { lintAction } from './lint.js';
|
|
30
8
|
export const renderAction = async (opts) => {
|
|
31
|
-
|
|
32
|
-
const
|
|
33
|
-
const
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
checkOnly: false,
|
|
43
|
-
uniqueNamesAssumption: opts.uniqueNamesAssumption,
|
|
44
|
-
explanations: opts.explanations,
|
|
45
|
-
profile: opts.profile,
|
|
46
|
-
};
|
|
47
|
-
await reasonAction(reasonOpts);
|
|
48
|
-
}
|
|
49
|
-
const backend = createBackend({
|
|
50
|
-
owlOutputRoot,
|
|
51
|
-
rdfFormat,
|
|
52
|
-
});
|
|
53
|
-
try {
|
|
54
|
-
const renderStartedAt = Date.now();
|
|
55
|
-
const markdownRoot = path.resolve(workspaceRoot, opts.md);
|
|
56
|
-
const output = path.resolve(opts.web);
|
|
57
|
-
const workspaceStat = await fs.stat(workspaceRoot).catch(() => undefined);
|
|
58
|
-
if (!workspaceStat || !workspaceStat.isDirectory()) {
|
|
59
|
-
failCli(chalk.red(`Workspace folder does not exist: ${workspaceRoot}`));
|
|
60
|
-
}
|
|
61
|
-
const markdownStat = await fs.stat(markdownRoot).catch(() => undefined);
|
|
62
|
-
if (!markdownStat || !markdownStat.isDirectory()) {
|
|
63
|
-
failCli(chalk.red(`Markdown folder does not exist: ${markdownRoot}`));
|
|
64
|
-
}
|
|
65
|
-
if (isSameOrDescendant(markdownRoot, output)) {
|
|
66
|
-
failCli(chalk.red('Web output folder cannot be inside the markdown folder.'));
|
|
67
|
-
}
|
|
68
|
-
if (opts.clean) {
|
|
69
|
-
await fs.rm(output, { recursive: true, force: true });
|
|
70
|
-
}
|
|
71
|
-
const renderableMarkdownFiles = await discoverRenderableMarkdownFiles(markdownRoot, output);
|
|
72
|
-
const discoveredWorkspaceMarkdownFiles = await discoverMarkdownFiles(workspaceRoot, output);
|
|
73
|
-
const templateFiles = await discoverTemplateMarkdownFiles(discoveredWorkspaceMarkdownFiles);
|
|
74
|
-
const templateCatalog = buildTemplateCatalog(templateFiles);
|
|
75
|
-
const explicitContextModelUri = resolveModelUriOption(opts.context, workspaceRoot);
|
|
76
|
-
const templateGenerationEnabled = explicitContextModelUri !== undefined;
|
|
77
|
-
const memberLabelSnapshot = await backend.getWorkspaceMemberLabelSnapshot(workspaceRoot);
|
|
78
|
-
const wikiPageIndex = buildWikiPageIndex(renderableMarkdownFiles, markdownRoot, output);
|
|
79
|
-
const generatedInstancePages = new Set();
|
|
80
|
-
const instancePageByIri = new Map();
|
|
81
|
-
const attemptedInstanceIris = new Set();
|
|
82
|
-
const workspaceAssetFiles = new Set();
|
|
83
|
-
const staticAssets = await writeStaticAssets(output);
|
|
84
|
-
let blockArtifactFiles = 0;
|
|
85
|
-
for (const file of renderableMarkdownFiles) {
|
|
86
|
-
const relative = path.relative(markdownRoot, file);
|
|
87
|
-
const outputFile = path.join(output, relative.replace(/\.md$/i, '.html'));
|
|
88
|
-
const rendered = await renderMarkdownFile(backend, workspaceRoot, markdownRoot, output, file, outputFile, staticAssets.runtimeScriptFile, staticAssets.stylesheetFile, templateGenerationEnabled, explicitContextModelUri, memberLabelSnapshot, wikiPageIndex, templateCatalog, generatedInstancePages, instancePageByIri, attemptedInstanceIris);
|
|
89
|
-
const referencedWorkspaceAssets = rendered.workspaceAssets;
|
|
90
|
-
for (const asset of referencedWorkspaceAssets) {
|
|
91
|
-
workspaceAssetFiles.add(asset);
|
|
92
|
-
}
|
|
93
|
-
blockArtifactFiles += rendered.blockArtifactFiles;
|
|
94
|
-
}
|
|
95
|
-
for (const file of workspaceAssetFiles) {
|
|
96
|
-
const workspaceRelative = path.relative(workspaceRoot, file);
|
|
97
|
-
if (workspaceRelative.startsWith('..') || path.isAbsolute(workspaceRelative)) {
|
|
98
|
-
continue;
|
|
99
|
-
}
|
|
100
|
-
if (workspaceRelative.toLowerCase().endsWith('.md')) {
|
|
101
|
-
continue;
|
|
102
|
-
}
|
|
103
|
-
const markdownRelative = path.relative(markdownRoot, file);
|
|
104
|
-
const isInsideMarkdownRoot = !markdownRelative.startsWith('..') && !path.isAbsolute(markdownRelative);
|
|
105
|
-
const outputRelative = isInsideMarkdownRoot ? markdownRelative : workspaceRelative;
|
|
106
|
-
const target = path.join(output, outputRelative);
|
|
107
|
-
await fs.mkdir(path.dirname(target), { recursive: true });
|
|
108
|
-
await fs.copyFile(file, target);
|
|
109
|
-
}
|
|
110
|
-
if (renderableMarkdownFiles.length === 0) {
|
|
111
|
-
console.log(chalk.yellow(`No markdown files found under ${markdownRoot}.`));
|
|
112
|
-
}
|
|
113
|
-
console.log(chalk.green(`render: ${renderableMarkdownFiles.length} markdown file(s) rendered in ${path.relative(process.cwd(), output) || output} [${formatDuration(Date.now() - renderStartedAt)}]`));
|
|
114
|
-
}
|
|
115
|
-
finally {
|
|
116
|
-
await backend.dispose();
|
|
117
|
-
}
|
|
118
|
-
};
|
|
119
|
-
function isSameOrDescendant(parent, candidate) {
|
|
120
|
-
const relative = path.relative(parent, candidate);
|
|
121
|
-
return relative === '' || (!relative.startsWith('..') && !path.isAbsolute(relative));
|
|
122
|
-
}
|
|
123
|
-
async function discoverTemplateMarkdownFiles(markdownFiles) {
|
|
124
|
-
const templateFiles = [];
|
|
125
|
-
for (const filePath of markdownFiles) {
|
|
126
|
-
const content = await fs.readFile(filePath, 'utf-8');
|
|
127
|
-
const frontMatter = extractLeadingFrontMatter(content);
|
|
128
|
-
const rawType = frontMatter?.data?.type;
|
|
129
|
-
if (typeof rawType === 'string' && rawType.trim().length > 0) {
|
|
130
|
-
const priorityValue = frontMatter?.data?.priority;
|
|
131
|
-
const priority = typeof priorityValue === 'number'
|
|
132
|
-
? priorityValue
|
|
133
|
-
: Number.parseInt(String(priorityValue ?? '0'), 10);
|
|
134
|
-
templateFiles.push({
|
|
135
|
-
filePath,
|
|
136
|
-
typeIri: normalizeTemplateTypeIri(rawType),
|
|
137
|
-
priority: Number.isFinite(priority) ? priority : 0
|
|
138
|
-
});
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
return templateFiles;
|
|
142
|
-
}
|
|
143
|
-
function normalizeTemplateTypeIri(value) {
|
|
144
|
-
return value.trim().replace(/^<|>$/g, '');
|
|
145
|
-
}
|
|
146
|
-
function buildTemplateCatalog(templateFiles) {
|
|
147
|
-
const byType = new Map();
|
|
148
|
-
for (const template of templateFiles) {
|
|
149
|
-
const list = byType.get(template.typeIri) ?? [];
|
|
150
|
-
list.push(template);
|
|
151
|
-
byType.set(template.typeIri, list);
|
|
152
|
-
}
|
|
153
|
-
for (const list of byType.values()) {
|
|
154
|
-
list.sort((left, right) => (left.priority - right.priority) || left.filePath.localeCompare(right.filePath));
|
|
155
|
-
}
|
|
156
|
-
return { byType };
|
|
157
|
-
}
|
|
158
|
-
function resolveModelUriOption(value, workspaceRoot) {
|
|
159
|
-
if (!value) {
|
|
160
|
-
return undefined;
|
|
161
|
-
}
|
|
162
|
-
const trimmed = value.trim();
|
|
163
|
-
if (!trimmed) {
|
|
164
|
-
return undefined;
|
|
165
|
-
}
|
|
166
|
-
if (trimmed.startsWith('workspace:/')) {
|
|
167
|
-
const resolved = resolveWorkspacePath(workspaceRoot, trimmed);
|
|
168
|
-
return resolved ? url.pathToFileURL(resolved).toString() : undefined;
|
|
169
|
-
}
|
|
170
|
-
if (/^[a-z][a-z0-9+.-]*:/i.test(trimmed)) {
|
|
171
|
-
return trimmed;
|
|
172
|
-
}
|
|
173
|
-
const absolute = path.isAbsolute(trimmed)
|
|
174
|
-
? trimmed
|
|
175
|
-
: path.resolve(workspaceRoot, trimmed);
|
|
176
|
-
return url.pathToFileURL(absolute).toString();
|
|
177
|
-
}
|
|
178
|
-
async function discoverRenderableMarkdownFiles(root, outputRoot) {
|
|
179
|
-
const markdownFiles = await discoverMarkdownFiles(root, outputRoot);
|
|
180
|
-
const renderableFiles = [];
|
|
181
|
-
for (const filePath of markdownFiles) {
|
|
182
|
-
const content = await fs.readFile(filePath, 'utf-8');
|
|
183
|
-
const frontMatter = extractLeadingFrontMatter(content);
|
|
184
|
-
const rawType = frontMatter?.data?.type;
|
|
185
|
-
if (typeof rawType === 'string' && rawType.trim().length > 0) {
|
|
186
|
-
continue;
|
|
187
|
-
}
|
|
188
|
-
renderableFiles.push(filePath);
|
|
189
|
-
}
|
|
190
|
-
return renderableFiles;
|
|
191
|
-
}
|
|
192
|
-
async function discoverMarkdownFiles(root, outputRoot) {
|
|
193
|
-
const entries = await fs.readdir(root, { withFileTypes: true });
|
|
194
|
-
const markdownFiles = [];
|
|
195
|
-
for (const entry of entries) {
|
|
196
|
-
const fullPath = path.join(root, entry.name);
|
|
197
|
-
if (entry.isDirectory()) {
|
|
198
|
-
if (entry.name === 'node_modules' || entry.name.startsWith('.')) {
|
|
199
|
-
continue;
|
|
200
|
-
}
|
|
201
|
-
if (isSameOrDescendant(outputRoot, fullPath)) {
|
|
202
|
-
continue;
|
|
203
|
-
}
|
|
204
|
-
markdownFiles.push(...await discoverMarkdownFiles(fullPath, outputRoot));
|
|
205
|
-
continue;
|
|
206
|
-
}
|
|
207
|
-
if (!entry.isFile()) {
|
|
208
|
-
continue;
|
|
209
|
-
}
|
|
210
|
-
if (entry.name.toLowerCase().endsWith('.md')) {
|
|
211
|
-
markdownFiles.push(fullPath);
|
|
212
|
-
}
|
|
213
|
-
}
|
|
214
|
-
return markdownFiles;
|
|
215
|
-
}
|
|
216
|
-
async function renderMarkdownFile(backend, workspaceRoot, inputRoot, outputRoot, inputFile, outputFile, runtimeScriptFile, stylesheetFile, templateGenerationEnabled, defaultContextModelUri, memberLabelSnapshot, wikiPageIndex, templateCatalog, generatedInstancePages, instancePageByIri, attemptedInstanceIris, currentPageStack = new Set(), explicitMarkdown, forcedModelUri) {
|
|
217
|
-
const markdown = explicitMarkdown ?? await fs.readFile(inputFile, 'utf-8');
|
|
218
|
-
const inlineContextUri = extractLeadingFrontMatter(markdown)?.contextUri;
|
|
219
|
-
const modelUri = forcedModelUri ?? resolveContextModelUri(inputFile, inlineContextUri, workspaceRoot) ?? defaultContextModelUri;
|
|
220
|
-
const prepared = runWithIriLabelSnapshot(memberLabelSnapshot, () => markdownRuntime.prepare(markdown));
|
|
221
|
-
const rewriteResult = rewriteRenderedLinks(prepared.renderedHtml, {
|
|
222
|
-
workspaceRoot,
|
|
223
|
-
inputRoot,
|
|
224
|
-
inputFile,
|
|
225
|
-
outputRoot,
|
|
226
|
-
outputFile,
|
|
227
|
-
});
|
|
228
|
-
const executableBlocks = toExecutableBlocks(prepared.codeBlocks);
|
|
229
|
-
const optionsByBlockId = new Map(prepared.codeBlocks.map((block) => [block.id, block.options]));
|
|
230
|
-
const blockResults = executableBlocks.length === 0
|
|
231
|
-
? []
|
|
232
|
-
: (await backend.executeMarkdownBlocks({
|
|
233
|
-
documentUri: url.pathToFileURL(path.resolve(inputFile)).toString(),
|
|
234
|
-
modelUri,
|
|
235
|
-
blocks: executableBlocks
|
|
236
|
-
}, workspaceRoot)).results;
|
|
237
|
-
const renderedBlockResults = blockResults.map((result) => ({
|
|
238
|
-
...result,
|
|
239
|
-
options: optionsByBlockId.get(result.blockId)
|
|
240
|
-
}));
|
|
241
|
-
const blockRewriteResult = rewriteBlockResultLinks(renderedBlockResults, {
|
|
242
|
-
workspaceRoot,
|
|
243
|
-
inputRoot,
|
|
244
|
-
inputFile,
|
|
245
|
-
outputRoot,
|
|
246
|
-
outputFile,
|
|
247
|
-
});
|
|
248
|
-
const blockArtifacts = await writeBlockArtifacts(outputFile, blockRewriteResult.results);
|
|
249
|
-
const pageWikilinkIris = collectWikilinkIrisFromHtml(rewriteResult.html);
|
|
250
|
-
const iriAliasHrefByIri = templateGenerationEnabled && modelUri
|
|
251
|
-
? await generateInstanceTemplatePages(backend, workspaceRoot, inputRoot, outputRoot, outputFile, runtimeScriptFile, stylesheetFile, templateGenerationEnabled, modelUri, memberLabelSnapshot, pageWikilinkIris, renderedBlockResults, wikiPageIndex, templateCatalog, generatedInstancePages, instancePageByIri, attemptedInstanceIris, currentPageStack)
|
|
252
|
-
: {};
|
|
253
|
-
const runtimeScriptRelative = toRelativeWebPath(path.dirname(outputFile), runtimeScriptFile);
|
|
254
|
-
const stylesheetRelative = toRelativeWebPath(path.dirname(outputFile), stylesheetFile);
|
|
255
|
-
const wikiLinkHrefByKey = buildWikiLinkHrefMapForPage(wikiPageIndex, outputFile);
|
|
256
|
-
const resolvedInstanceLinks = Object.fromEntries([...instancePageByIri.entries()].map(([iri, absolute]) => [iri, toRelativeWebPath(path.dirname(outputFile), absolute)]));
|
|
257
|
-
const html = wrapHtml(rewriteResult.html, runtimeScriptRelative, stylesheetRelative, blockArtifacts.manifest, blockRewriteResult.results, wikiLinkHrefByKey, { ...resolvedInstanceLinks, ...iriAliasHrefByIri }, templateGenerationEnabled && Boolean(modelUri), memberLabelSnapshot);
|
|
258
|
-
await fs.mkdir(path.dirname(outputFile), { recursive: true });
|
|
259
|
-
await fs.writeFile(outputFile, html, 'utf-8');
|
|
260
|
-
const workspaceAssets = new Set(rewriteResult.workspaceAssets);
|
|
261
|
-
for (const asset of blockRewriteResult.workspaceAssets) {
|
|
262
|
-
workspaceAssets.add(asset);
|
|
263
|
-
}
|
|
264
|
-
return { workspaceAssets, blockArtifactFiles: blockArtifacts.count };
|
|
265
|
-
}
|
|
266
|
-
function toExecutableBlocks(codeBlocks) {
|
|
267
|
-
const executable = [];
|
|
268
|
-
for (const block of codeBlocks) {
|
|
269
|
-
const kind = toMdBlockKind(block.language);
|
|
270
|
-
if (!kind) {
|
|
271
|
-
continue;
|
|
272
|
-
}
|
|
273
|
-
executable.push({
|
|
274
|
-
id: block.id,
|
|
275
|
-
kind,
|
|
276
|
-
source: block.content,
|
|
277
|
-
meta: block.meta,
|
|
278
|
-
options: block.options,
|
|
279
|
-
lineStart: block.lineStart,
|
|
280
|
-
lineEnd: block.lineEnd
|
|
281
|
-
});
|
|
282
|
-
}
|
|
283
|
-
return executable;
|
|
284
|
-
}
|
|
285
|
-
function toMdBlockKind(language) {
|
|
286
|
-
return SUPPORTED_MD_BLOCK_KINDS.has(language) ? language : undefined;
|
|
287
|
-
}
|
|
288
|
-
function resolveContextModelUri(documentFile, contextUri, workspaceRoot) {
|
|
289
|
-
if (!contextUri) {
|
|
290
|
-
return undefined;
|
|
291
|
-
}
|
|
292
|
-
const trimmed = contextUri.trim();
|
|
293
|
-
if (!trimmed) {
|
|
294
|
-
return undefined;
|
|
295
|
-
}
|
|
296
|
-
if (trimmed.startsWith('workspace:/')) {
|
|
297
|
-
const resolved = resolveWorkspacePath(workspaceRoot, trimmed);
|
|
298
|
-
return resolved ? url.pathToFileURL(resolved).toString() : undefined;
|
|
299
|
-
}
|
|
300
|
-
if (/^[a-z][a-z0-9+.-]*:/i.test(trimmed)) {
|
|
301
|
-
return trimmed;
|
|
302
|
-
}
|
|
303
|
-
if (trimmed.startsWith('/')) {
|
|
304
|
-
return url.pathToFileURL(path.resolve(workspaceRoot, trimmed.replace(/^\/+/, ''))).toString();
|
|
305
|
-
}
|
|
306
|
-
return url.pathToFileURL(path.resolve(path.dirname(documentFile), trimmed)).toString();
|
|
307
|
-
}
|
|
308
|
-
async function writeStaticAssets(outputRoot) {
|
|
309
|
-
const runtimeBundle = await loadStaticRuntimeBundle();
|
|
310
|
-
const sourceStylesheet = await loadCodeBlockStylesheet();
|
|
311
|
-
const mergedStylesheet = `${sourceStylesheet}\n\n${STATIC_MARKDOWN_RUNTIME_CSS}\n`;
|
|
312
|
-
const runtimeVersion = createHash('sha1').update(runtimeBundle).digest('hex').slice(0, 12);
|
|
313
|
-
const stylesheetVersion = createHash('sha1').update(mergedStylesheet).digest('hex').slice(0, 12);
|
|
314
|
-
const runtimeFile = path.join(outputRoot, 'assets', `markdown-static-${runtimeVersion}.js`);
|
|
315
|
-
const stylesheetFile = path.join(outputRoot, 'assets', `markdown-webview-${stylesheetVersion}.css`);
|
|
316
|
-
await fs.mkdir(path.dirname(runtimeFile), { recursive: true });
|
|
317
|
-
await fs.writeFile(runtimeFile, runtimeBundle, 'utf-8');
|
|
318
|
-
await fs.writeFile(stylesheetFile, mergedStylesheet, 'utf-8');
|
|
319
|
-
return { runtimeScriptFile: runtimeFile, stylesheetFile };
|
|
320
|
-
}
|
|
321
|
-
async function loadStaticRuntimeBundle() {
|
|
322
|
-
const require = createRequire(import.meta.url);
|
|
323
|
-
const staticEntry = require.resolve('@oml/markdown/static');
|
|
324
|
-
const bundlePath = path.join(path.dirname(staticEntry), STATIC_MARKDOWN_RUNTIME_BUNDLE_FILE);
|
|
325
|
-
try {
|
|
326
|
-
return await fs.readFile(bundlePath, 'utf-8');
|
|
327
|
-
}
|
|
328
|
-
catch {
|
|
329
|
-
throw new Error(`Unable to load markdown static runtime bundle at '${bundlePath}'. `
|
|
330
|
-
+ 'Run the markdown package build to generate it.');
|
|
331
|
-
}
|
|
332
|
-
}
|
|
333
|
-
async function loadCodeBlockStylesheet() {
|
|
334
|
-
const require = createRequire(import.meta.url);
|
|
335
|
-
const staticEntry = require.resolve('@oml/markdown/static');
|
|
336
|
-
const stylesheetPath = path.resolve(path.dirname(staticEntry), '..', '..', 'src', 'static', 'markdown-webview.css');
|
|
337
|
-
try {
|
|
338
|
-
return await fs.readFile(stylesheetPath, 'utf-8');
|
|
339
|
-
}
|
|
340
|
-
catch {
|
|
341
|
-
throw new Error(`Unable to load markdown webview stylesheet at '${stylesheetPath}'. `
|
|
342
|
-
+ 'The installed @oml/markdown package is missing a required static asset.');
|
|
343
|
-
}
|
|
344
|
-
}
|
|
345
|
-
async function writeBlockArtifacts(outputFile, results) {
|
|
346
|
-
if (results.length === 0) {
|
|
347
|
-
return { count: 0, manifest: [] };
|
|
348
|
-
}
|
|
349
|
-
const blockDirName = `${path.basename(outputFile, '.html')}.blocks`;
|
|
350
|
-
const blockDir = path.join(path.dirname(outputFile), blockDirName);
|
|
351
|
-
await fs.mkdir(blockDir, { recursive: true });
|
|
352
|
-
const manifest = [];
|
|
353
|
-
for (const result of results) {
|
|
354
|
-
const safeId = sanitizeBlockId(result.blockId);
|
|
355
|
-
const fileName = `${safeId}.json`;
|
|
356
|
-
const filePath = path.join(blockDir, fileName);
|
|
357
|
-
await fs.writeFile(filePath, JSON.stringify(result, null, 2), 'utf-8');
|
|
358
|
-
manifest.push({
|
|
359
|
-
blockId: result.blockId,
|
|
360
|
-
path: `./${blockDirName}/${fileName}`
|
|
361
|
-
});
|
|
362
|
-
}
|
|
363
|
-
return { count: results.length, manifest };
|
|
364
|
-
}
|
|
365
|
-
function rewriteBlockResultLinks(results, context) {
|
|
366
|
-
const workspaceAssets = new Set();
|
|
367
|
-
const rewrittenResults = results.map((result) => rewriteLinkValue(result, context, workspaceAssets));
|
|
368
|
-
return { results: rewrittenResults, workspaceAssets };
|
|
369
|
-
}
|
|
370
|
-
function rewriteLinkValue(value, context, workspaceAssets, parentKey) {
|
|
371
|
-
if (typeof value === 'string') {
|
|
372
|
-
if (parentKey && LINK_ATTRIBUTE_KEYS.has(parentKey)) {
|
|
373
|
-
return rewriteHref(value, context, workspaceAssets);
|
|
374
|
-
}
|
|
375
|
-
return value;
|
|
376
|
-
}
|
|
377
|
-
if (Array.isArray(value)) {
|
|
378
|
-
return value.map((entry) => rewriteLinkValue(entry, context, workspaceAssets));
|
|
379
|
-
}
|
|
380
|
-
if (!value || typeof value !== 'object') {
|
|
381
|
-
return value;
|
|
382
|
-
}
|
|
383
|
-
const source = value;
|
|
384
|
-
const rewritten = {};
|
|
385
|
-
for (const [key, entry] of Object.entries(source)) {
|
|
386
|
-
rewritten[key] = rewriteLinkValue(entry, context, workspaceAssets, key);
|
|
387
|
-
}
|
|
388
|
-
return rewritten;
|
|
389
|
-
}
|
|
390
|
-
function sanitizeBlockId(value) {
|
|
391
|
-
const trimmed = value.trim();
|
|
392
|
-
if (!trimmed) {
|
|
393
|
-
return 'block';
|
|
394
|
-
}
|
|
395
|
-
return trimmed.replace(/[^a-zA-Z0-9._-]/g, '_');
|
|
396
|
-
}
|
|
397
|
-
function rewriteRenderedLinks(content, context) {
|
|
398
|
-
const workspaceAssets = new Set();
|
|
399
|
-
const html = content.replace(/(\b(?:href|src)\s*=\s*)(["'])([^"']+)\2/gi, (_match, prefix, quote, rawHref) => {
|
|
400
|
-
const rewritten = rewriteHref(rawHref, context, workspaceAssets);
|
|
401
|
-
return `${prefix}${quote}${rewritten}${quote}`;
|
|
402
|
-
});
|
|
403
|
-
return { html, workspaceAssets };
|
|
404
|
-
}
|
|
405
|
-
function rewriteHref(href, context, workspaceAssets) {
|
|
406
|
-
const parts = splitHref(href);
|
|
407
|
-
if (!parts.path) {
|
|
408
|
-
return href;
|
|
409
|
-
}
|
|
410
|
-
const trimmedPath = parts.path.trim();
|
|
411
|
-
if (!trimmedPath || trimmedPath.startsWith('#') || trimmedPath.startsWith('//')) {
|
|
412
|
-
return href;
|
|
413
|
-
}
|
|
414
|
-
if (trimmedPath.startsWith('workspace:/')) {
|
|
415
|
-
const resolved = resolveWorkspacePath(context.workspaceRoot, trimmedPath);
|
|
416
|
-
if (!resolved) {
|
|
417
|
-
return href;
|
|
418
|
-
}
|
|
419
|
-
if (!resolved.toLowerCase().endsWith('.md')) {
|
|
420
|
-
workspaceAssets.add(resolved);
|
|
421
|
-
}
|
|
422
|
-
const workspaceRelative = path.relative(context.workspaceRoot, resolved);
|
|
423
|
-
const inputRelative = path.relative(context.inputRoot, resolved);
|
|
424
|
-
const isInsideInput = !inputRelative.startsWith('..') && !path.isAbsolute(inputRelative);
|
|
425
|
-
const outputRelative = isInsideInput ? inputRelative : workspaceRelative;
|
|
426
|
-
const targetInOutput = path.join(context.outputRoot, resolved.toLowerCase().endsWith('.md')
|
|
427
|
-
? outputRelative.replace(/\.md$/i, '.html')
|
|
428
|
-
: outputRelative);
|
|
429
|
-
const rewrittenPath = toRelativeWebPath(path.dirname(context.outputFile), targetInOutput);
|
|
430
|
-
return `${rewrittenPath}${parts.query}${parts.fragment}`;
|
|
431
|
-
}
|
|
432
|
-
if (/^[a-z][a-z0-9+.-]*:/i.test(trimmedPath)) {
|
|
433
|
-
return href;
|
|
434
|
-
}
|
|
435
|
-
if (!trimmedPath.startsWith('/')) {
|
|
436
|
-
const resolved = path.resolve(path.dirname(context.inputFile), trimmedPath);
|
|
437
|
-
const workspaceRelative = path.relative(context.workspaceRoot, resolved);
|
|
438
|
-
if (!workspaceRelative.startsWith('..') && !path.isAbsolute(workspaceRelative) && !resolved.toLowerCase().endsWith('.md')) {
|
|
439
|
-
workspaceAssets.add(resolved);
|
|
440
|
-
}
|
|
441
|
-
}
|
|
442
|
-
const rewrittenPath = trimmedPath.toLowerCase().endsWith('.md')
|
|
443
|
-
? trimmedPath.slice(0, -3) + '.html'
|
|
444
|
-
: trimmedPath;
|
|
445
|
-
return `${rewrittenPath}${parts.query}${parts.fragment}`;
|
|
446
|
-
}
|
|
447
|
-
function resolveWorkspacePath(workspaceRoot, hrefPath) {
|
|
448
|
-
const relative = hrefPath.slice('workspace:/'.length).replace(/^\/+/, '');
|
|
449
|
-
const resolved = path.resolve(workspaceRoot, relative);
|
|
450
|
-
const relativeToWorkspace = path.relative(workspaceRoot, resolved);
|
|
451
|
-
if (relativeToWorkspace.startsWith('..') || path.isAbsolute(relativeToWorkspace)) {
|
|
452
|
-
return undefined;
|
|
453
|
-
}
|
|
454
|
-
return resolved;
|
|
455
|
-
}
|
|
456
|
-
function splitHref(href) {
|
|
457
|
-
const hashIndex = href.indexOf('#');
|
|
458
|
-
const pathAndQuery = hashIndex >= 0 ? href.slice(0, hashIndex) : href;
|
|
459
|
-
const fragment = hashIndex >= 0 ? href.slice(hashIndex) : '';
|
|
460
|
-
const queryIndex = pathAndQuery.indexOf('?');
|
|
461
|
-
return {
|
|
462
|
-
path: queryIndex >= 0 ? pathAndQuery.slice(0, queryIndex) : pathAndQuery,
|
|
463
|
-
query: queryIndex >= 0 ? pathAndQuery.slice(queryIndex) : '',
|
|
464
|
-
fragment
|
|
465
|
-
};
|
|
466
|
-
}
|
|
467
|
-
function toRelativeWebPath(fromDir, toFile) {
|
|
468
|
-
const relative = path.relative(fromDir, toFile).split(path.sep).join('/');
|
|
469
|
-
if (!relative || relative === '.') {
|
|
470
|
-
return '.';
|
|
471
|
-
}
|
|
472
|
-
return relative.startsWith('.') ? relative : `./${relative}`;
|
|
473
|
-
}
|
|
474
|
-
function normalizeWikiPathKey(raw) {
|
|
475
|
-
const normalized = raw.replace(/\\/g, '/').replace(/^\/+/, '').replace(/\/+/g, '/');
|
|
476
|
-
if (!normalized) {
|
|
477
|
-
return '';
|
|
478
|
-
}
|
|
479
|
-
const withoutHtml = normalized.replace(/\.html$/i, '');
|
|
480
|
-
return withoutHtml.replace(/^\.\//, '').toLowerCase();
|
|
481
|
-
}
|
|
482
|
-
function buildWikiPageIndex(markdownFiles, inputRoot, outputRoot) {
|
|
483
|
-
const index = new Map();
|
|
484
|
-
for (const markdownFile of markdownFiles) {
|
|
485
|
-
const relativeInput = path.relative(inputRoot, markdownFile).split(path.sep).join('/');
|
|
486
|
-
const normalizedRelative = normalizeWikiPathKey(relativeInput.replace(/\.md$/i, ''));
|
|
487
|
-
if (!normalizedRelative) {
|
|
488
|
-
continue;
|
|
489
|
-
}
|
|
490
|
-
const outputFile = path.join(outputRoot, relativeInput.replace(/\.md$/i, '.html'));
|
|
491
|
-
index.set(normalizedRelative, outputFile);
|
|
492
|
-
}
|
|
493
|
-
return index;
|
|
494
|
-
}
|
|
495
|
-
function buildWikiLinkHrefMapForPage(wikiPageIndex, outputFile) {
|
|
496
|
-
const map = {};
|
|
497
|
-
for (const [key, targetFile] of wikiPageIndex.entries()) {
|
|
498
|
-
map[key] = toRelativeWebPath(path.dirname(outputFile), targetFile);
|
|
499
|
-
}
|
|
500
|
-
return map;
|
|
501
|
-
}
|
|
502
|
-
function collectFragmentIrisFromValue(value, collected) {
|
|
503
|
-
if (typeof value === 'string') {
|
|
504
|
-
const trimmed = value.trim();
|
|
505
|
-
if (trimmed.length > 0) {
|
|
506
|
-
const iriPattern = /[a-z][a-z0-9+.-]*:[^\s<>"')\]]+/gi;
|
|
507
|
-
for (const match of trimmed.matchAll(iriPattern)) {
|
|
508
|
-
let iri = (match[0] ?? '').trim();
|
|
509
|
-
iri = iri.replace(/[.,;:!?]+$/, '');
|
|
510
|
-
if (/^[a-z][a-z0-9+.-]*:/i.test(iri)) {
|
|
511
|
-
collected.add(iri);
|
|
512
|
-
}
|
|
513
|
-
}
|
|
514
|
-
}
|
|
515
|
-
return;
|
|
516
|
-
}
|
|
517
|
-
if (Array.isArray(value)) {
|
|
518
|
-
for (const entry of value) {
|
|
519
|
-
collectFragmentIrisFromValue(entry, collected);
|
|
520
|
-
}
|
|
9
|
+
await lintAction({ authToken: opts.authToken });
|
|
10
|
+
const renderStartedAt = Date.now();
|
|
11
|
+
const result = await restPost('/v0/render', {
|
|
12
|
+
...opts,
|
|
13
|
+
only: true,
|
|
14
|
+
}, opts.authToken);
|
|
15
|
+
if (!result.success) {
|
|
16
|
+
failCli(chalk.red(result.error?.trim() || 'render failed.'));
|
|
17
|
+
}
|
|
18
|
+
if (result.filesRendered === 0) {
|
|
19
|
+
console.log(chalk.yellow(`No markdown files found.`));
|
|
521
20
|
return;
|
|
522
21
|
}
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
collectFragmentIrisFromValue(entry, collected);
|
|
526
|
-
}
|
|
527
|
-
}
|
|
528
|
-
}
|
|
529
|
-
function collectWikilinkIrisFromResults(results) {
|
|
530
|
-
const collected = new Set();
|
|
531
|
-
for (const result of results) {
|
|
532
|
-
collectFragmentIrisFromValue(result, collected);
|
|
533
|
-
}
|
|
534
|
-
return collected;
|
|
535
|
-
}
|
|
536
|
-
function collectWikilinkIrisFromHtml(renderedHtml) {
|
|
537
|
-
const collected = new Set();
|
|
538
|
-
const pattern = /<a\b[^>]*\bclass=(["'])[^"']*\bwikilink\b[^"']*\1[^>]*\biri=(["'])([^"']+)\2/gi;
|
|
539
|
-
for (const match of renderedHtml.matchAll(pattern)) {
|
|
540
|
-
const iri = (match[3] ?? '').trim();
|
|
541
|
-
if (iri) {
|
|
542
|
-
collected.add(iri);
|
|
543
|
-
}
|
|
544
|
-
}
|
|
545
|
-
return collected;
|
|
546
|
-
}
|
|
547
|
-
function sanitizePathSegment(value) {
|
|
548
|
-
const decoded = decodeURIComponent(value);
|
|
549
|
-
const trimmed = decoded.trim();
|
|
550
|
-
if (!trimmed) {
|
|
551
|
-
return 'instance';
|
|
552
|
-
}
|
|
553
|
-
return encodeURIComponent(trimmed);
|
|
554
|
-
}
|
|
555
|
-
function resolveInstanceOutputFile(outputRoot, iri) {
|
|
556
|
-
let parsed;
|
|
557
|
-
try {
|
|
558
|
-
parsed = new URL(iri);
|
|
559
|
-
}
|
|
560
|
-
catch {
|
|
561
|
-
return undefined;
|
|
562
|
-
}
|
|
563
|
-
if (!parsed.hostname) {
|
|
564
|
-
return undefined;
|
|
565
|
-
}
|
|
566
|
-
const host = parsed.hostname.toLowerCase();
|
|
567
|
-
const pathSegments = parsed.pathname
|
|
568
|
-
.split('/')
|
|
569
|
-
.map((segment) => segment.trim())
|
|
570
|
-
.filter((segment) => segment.length > 0)
|
|
571
|
-
.map((segment) => sanitizePathSegment(segment));
|
|
572
|
-
const fragment = parsed.hash.replace(/^#/, '').trim();
|
|
573
|
-
const fileSegments = [host, ...pathSegments];
|
|
574
|
-
if (fragment.length > 0) {
|
|
575
|
-
fileSegments.push(sanitizePathSegment(fragment));
|
|
576
|
-
}
|
|
577
|
-
else if (fileSegments.length === 1) {
|
|
578
|
-
fileSegments.push('index');
|
|
579
|
-
}
|
|
580
|
-
if (fileSegments.length === 0) {
|
|
581
|
-
return undefined;
|
|
582
|
-
}
|
|
583
|
-
return path.join(outputRoot, ...fileSegments) + '.html';
|
|
584
|
-
}
|
|
585
|
-
function selectTemplateForTypes(catalog, typeIris) {
|
|
586
|
-
const candidates = [];
|
|
587
|
-
for (const typeIri of typeIris) {
|
|
588
|
-
const templates = catalog.byType.get(typeIri);
|
|
589
|
-
if (!templates || templates.length === 0) {
|
|
590
|
-
continue;
|
|
591
|
-
}
|
|
592
|
-
candidates.push(...templates);
|
|
593
|
-
}
|
|
594
|
-
if (candidates.length === 0) {
|
|
595
|
-
return undefined;
|
|
596
|
-
}
|
|
597
|
-
candidates.sort((left, right) => (left.priority - right.priority) || left.filePath.localeCompare(right.filePath));
|
|
598
|
-
return candidates[0];
|
|
599
|
-
}
|
|
600
|
-
async function queryRdfTypesForIris(backend, workspaceRoot, modelUri, iris) {
|
|
601
|
-
const byIri = new Map();
|
|
602
|
-
if (iris.length === 0) {
|
|
603
|
-
return byIri;
|
|
604
|
-
}
|
|
605
|
-
const valuesClause = iris.map((iri) => `<${iri}>`).join(' ');
|
|
606
|
-
const query = `PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
|
|
607
|
-
SELECT ?s ?type
|
|
608
|
-
WHERE {
|
|
609
|
-
VALUES ?s { ${valuesClause} }
|
|
610
|
-
GRAPH ?g { ?s rdf:type ?type . }
|
|
611
|
-
}`;
|
|
612
|
-
const result = await backend.executeMarkdownBlocks({
|
|
613
|
-
documentUri: 'file:///__oml_cli_wikilink_types__.md',
|
|
614
|
-
modelUri,
|
|
615
|
-
blocks: [{
|
|
616
|
-
id: '__oml_cli_wikilink_types__',
|
|
617
|
-
kind: 'table',
|
|
618
|
-
source: query,
|
|
619
|
-
lineStart: 0,
|
|
620
|
-
lineEnd: 0,
|
|
621
|
-
}]
|
|
622
|
-
}, workspaceRoot);
|
|
623
|
-
const block = result.results[0];
|
|
624
|
-
if (!block || block.status !== 'ok' || block.format !== 'table' || !block.payload) {
|
|
625
|
-
return byIri;
|
|
626
|
-
}
|
|
627
|
-
const subjectIndex = block.payload.columns.findIndex((column) => column === 's');
|
|
628
|
-
const typeIndex = block.payload.columns.findIndex((column) => column === 'type');
|
|
629
|
-
const left = subjectIndex >= 0 ? subjectIndex : 0;
|
|
630
|
-
const right = typeIndex >= 0 ? typeIndex : 1;
|
|
631
|
-
for (const row of block.payload.rows) {
|
|
632
|
-
const subject = (row[left] ?? '').trim();
|
|
633
|
-
const typeIri = (row[right] ?? '').trim().replace(/^<|>$/g, '');
|
|
634
|
-
if (!subject || !typeIri) {
|
|
635
|
-
continue;
|
|
636
|
-
}
|
|
637
|
-
const types = byIri.get(subject) ?? new Set();
|
|
638
|
-
types.add(typeIri);
|
|
639
|
-
byIri.set(subject, types);
|
|
640
|
-
}
|
|
641
|
-
return byIri;
|
|
642
|
-
}
|
|
643
|
-
function buildTemplatePageMarkdown(templateMarkdown, focusIri, queryContextOption) {
|
|
644
|
-
const body = stripLeadingFrontMatter(templateMarkdown).split('${contextIri}').join(focusIri);
|
|
645
|
-
const escapedContext = JSON.stringify(queryContextOption);
|
|
646
|
-
return `---
|
|
647
|
-
contextUri: ${escapedContext}
|
|
648
|
-
---
|
|
649
|
-
${body}`;
|
|
650
|
-
}
|
|
651
|
-
async function generateInstanceTemplatePages(backend, workspaceRoot, inputRoot, outputRoot, pageOutputFile, runtimeScriptFile, stylesheetFile, templateGenerationEnabled, queryContextModelUri, memberLabelSnapshot, pageWikilinkIris, results, wikiPageIndex, templateCatalog, generatedInstancePages, instancePageByIri, attemptedInstanceIris, currentPageStack) {
|
|
652
|
-
const iriToHref = {};
|
|
653
|
-
if (!templateGenerationEnabled) {
|
|
654
|
-
return iriToHref;
|
|
655
|
-
}
|
|
656
|
-
const wikilinkIris = [...new Set([
|
|
657
|
-
...pageWikilinkIris,
|
|
658
|
-
...collectWikilinkIrisFromResults(results),
|
|
659
|
-
])];
|
|
660
|
-
const unresolved = wikilinkIris.filter((iri) => !attemptedInstanceIris.has(iri));
|
|
661
|
-
for (const iri of unresolved) {
|
|
662
|
-
attemptedInstanceIris.add(iri);
|
|
663
|
-
}
|
|
664
|
-
const typesByIri = await queryRdfTypesForIris(backend, workspaceRoot, queryContextModelUri, unresolved);
|
|
665
|
-
for (const iri of unresolved) {
|
|
666
|
-
const types = typesByIri.get(iri) ?? new Set();
|
|
667
|
-
const template = selectTemplateForTypes(templateCatalog, types);
|
|
668
|
-
if (!template) {
|
|
669
|
-
continue;
|
|
670
|
-
}
|
|
671
|
-
const instanceOutputFile = resolveInstanceOutputFile(outputRoot, iri);
|
|
672
|
-
if (!instanceOutputFile) {
|
|
673
|
-
continue;
|
|
674
|
-
}
|
|
675
|
-
instancePageByIri.set(iri, instanceOutputFile);
|
|
676
|
-
if (generatedInstancePages.has(instanceOutputFile) || currentPageStack.has(instanceOutputFile)) {
|
|
677
|
-
continue;
|
|
678
|
-
}
|
|
679
|
-
generatedInstancePages.add(instanceOutputFile);
|
|
680
|
-
const templateMarkdown = await fs.readFile(template.filePath, 'utf-8');
|
|
681
|
-
const instantiatedMarkdown = buildTemplatePageMarkdown(templateMarkdown, iri, queryContextModelUri);
|
|
682
|
-
const nextStack = new Set(currentPageStack);
|
|
683
|
-
nextStack.add(instanceOutputFile);
|
|
684
|
-
await renderMarkdownFile(backend, workspaceRoot, inputRoot, outputRoot, template.filePath, instanceOutputFile, runtimeScriptFile, stylesheetFile, templateGenerationEnabled, queryContextModelUri, memberLabelSnapshot, wikiPageIndex, templateCatalog, generatedInstancePages, instancePageByIri, attemptedInstanceIris, nextStack, instantiatedMarkdown, queryContextModelUri);
|
|
685
|
-
}
|
|
686
|
-
for (const iri of wikilinkIris) {
|
|
687
|
-
const absolute = instancePageByIri.get(iri);
|
|
688
|
-
if (!absolute) {
|
|
689
|
-
continue;
|
|
690
|
-
}
|
|
691
|
-
iriToHref[iri] = toRelativeWebPath(path.dirname(pageOutputFile), absolute);
|
|
692
|
-
}
|
|
693
|
-
return iriToHref;
|
|
694
|
-
}
|
|
695
|
-
function wrapHtml(content, runtimeScriptPath, stylesheetPath, blockManifest, blockResults, wikiLinkHrefByKey, iriAliasHrefByIri, linkingEnabled, memberLabelSnapshot) {
|
|
696
|
-
const escapedManifest = escapeJsonForScript(JSON.stringify(blockManifest));
|
|
697
|
-
const inlineResults = Object.fromEntries(blockResults.map((result) => [result.blockId, result]));
|
|
698
|
-
const escapedInlineResults = escapeJsonForScript(JSON.stringify(inlineResults));
|
|
699
|
-
const escapedWikiIndex = escapeJsonForScript(JSON.stringify(wikiLinkHrefByKey));
|
|
700
|
-
const escapedIriAliasIndex = escapeJsonForScript(JSON.stringify(iriAliasHrefByIri));
|
|
701
|
-
const escapedLinkingConfig = escapeJsonForScript(JSON.stringify({ linkingEnabled }));
|
|
702
|
-
const escapedMemberLabels = escapeJsonForScript(JSON.stringify(memberLabelSnapshot ?? {}));
|
|
703
|
-
return `<!doctype html>
|
|
704
|
-
<html lang="en">
|
|
705
|
-
<head>
|
|
706
|
-
<meta charset="UTF-8">
|
|
707
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
708
|
-
<title>OML Markdown</title>
|
|
709
|
-
<link rel="stylesheet" href="${escapeAttribute(stylesheetPath)}">
|
|
710
|
-
</head>
|
|
711
|
-
<body>
|
|
712
|
-
${content}
|
|
713
|
-
<script id="oml-md-block-manifest" type="application/json">${escapedManifest}</script>
|
|
714
|
-
<script id="oml-md-block-inline-results" type="application/json">${escapedInlineResults}</script>
|
|
715
|
-
<script id="oml-md-wikilink-index" type="application/json">${escapedWikiIndex}</script>
|
|
716
|
-
<script id="oml-md-wikilink-iri-aliases" type="application/json">${escapedIriAliasIndex}</script>
|
|
717
|
-
<script id="oml-md-wikilink-config" type="application/json">${escapedLinkingConfig}</script>
|
|
718
|
-
<script id="oml-md-member-labels" type="application/json">${escapedMemberLabels}</script>
|
|
719
|
-
<script src="${escapeAttribute(runtimeScriptPath)}"></script>
|
|
720
|
-
</body>
|
|
721
|
-
</html>
|
|
722
|
-
`;
|
|
723
|
-
}
|
|
724
|
-
function escapeAttribute(value) {
|
|
725
|
-
return value
|
|
726
|
-
.replace(/&/g, '&')
|
|
727
|
-
.replace(/</g, '<')
|
|
728
|
-
.replace(/>/g, '>')
|
|
729
|
-
.replace(/"/g, '"')
|
|
730
|
-
.replace(/'/g, ''');
|
|
731
|
-
}
|
|
732
|
-
function escapeJsonForScript(value) {
|
|
733
|
-
return value.replace(/</g, '\\u003c');
|
|
734
|
-
}
|
|
22
|
+
console.log(chalk.green(`render: ${result.filesRendered} markdown file(s) rendered in ${path.relative(process.cwd(), result.outputDir) || result.outputDir} [${formatDuration(Date.now() - renderStartedAt)}]`));
|
|
23
|
+
};
|
|
735
24
|
//# sourceMappingURL=render.js.map
|