@oml/server 0.16.1 → 0.16.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/out/rest/server.js +118 -25
- package/out/rest/server.js.map +1 -1
- package/out/rest/shell-index.d.ts +1 -0
- package/out/rest/shell-index.js +795 -0
- package/out/rest/shell-index.js.map +1 -0
- package/out/rest/template.js +0 -3
- package/out/rest/template.js.map +1 -1
- package/out/workspace-settings.d.ts +6 -0
- package/out/workspace-settings.js.map +1 -1
- package/package.json +4 -4
package/out/rest/server.js
CHANGED
|
@@ -22,6 +22,8 @@ import { createOpenApiSpec, dispatchRestOperation, resolveRestOperationId } from
|
|
|
22
22
|
import { buildTemplateCatalog, expandTemplateComposeBlocks, findFilesByExtension, frontMatterString, isTemplateMarkdownFile, normalizeContextOntologyIri, } from './template.js';
|
|
23
23
|
import { lintWorkspace, validateWorkspace } from './validation.js';
|
|
24
24
|
import { reindexWorkspaceShacl } from './shacl-index.js';
|
|
25
|
+
import { generateShellIndex } from './shell-index.js';
|
|
26
|
+
import { readWorkspaceSettings } from '../workspace-settings.js';
|
|
25
27
|
import { OmlAccessError, requiredFeatureForRestOperation, } from '../auth/feature-policy.js';
|
|
26
28
|
const JSON_CONTENT_TYPE = 'application/json; charset=utf-8';
|
|
27
29
|
const HTML_CONTENT_TYPE = 'text/html; charset=utf-8';
|
|
@@ -1671,6 +1673,38 @@ function toMdBlockKind(language) {
|
|
|
1671
1673
|
return SUPPORTED_MD_BLOCK_KINDS.has(language) ? language : undefined;
|
|
1672
1674
|
}
|
|
1673
1675
|
const SCRIPT_LANGUAGES = new Set(['javascript', 'js', 'python', 'r']);
|
|
1676
|
+
function extractScriptIncludePaths(code) {
|
|
1677
|
+
const re = /\binclude\s*\(\s*(?:"((?:[^"\\]|\\[\s\S])*)"|'((?:[^'\\]|\\[\s\S])*)'|`((?:[^`\\]|\\[\s\S])*)`)\s*\)/g;
|
|
1678
|
+
const seen = new Set();
|
|
1679
|
+
let m;
|
|
1680
|
+
while ((m = re.exec(code)) !== null) {
|
|
1681
|
+
seen.add(m[1] ?? m[2] ?? m[3]);
|
|
1682
|
+
}
|
|
1683
|
+
return [...seen];
|
|
1684
|
+
}
|
|
1685
|
+
async function buildScriptIncludeCache(codeBlocks, workspaceRoot) {
|
|
1686
|
+
const allPaths = new Set();
|
|
1687
|
+
for (const block of codeBlocks) {
|
|
1688
|
+
if (!SCRIPT_LANGUAGES.has(block.language)) {
|
|
1689
|
+
continue;
|
|
1690
|
+
}
|
|
1691
|
+
for (const p of extractScriptIncludePaths(block.content)) {
|
|
1692
|
+
allPaths.add(p);
|
|
1693
|
+
}
|
|
1694
|
+
}
|
|
1695
|
+
const cache = {};
|
|
1696
|
+
await Promise.all([...allPaths].map(async (p) => {
|
|
1697
|
+
try {
|
|
1698
|
+
const abs = path.resolve(workspaceRoot, p);
|
|
1699
|
+
const rel = path.relative(workspaceRoot, abs);
|
|
1700
|
+
if (!rel.startsWith('..') && !path.isAbsolute(rel)) {
|
|
1701
|
+
cache[p] = await fs.readFile(abs, 'utf-8');
|
|
1702
|
+
}
|
|
1703
|
+
}
|
|
1704
|
+
catch { /* silently omit missing/unreadable files */ }
|
|
1705
|
+
}));
|
|
1706
|
+
return cache;
|
|
1707
|
+
}
|
|
1674
1708
|
function extractScriptQueryStrings(code) {
|
|
1675
1709
|
const seen = new Set();
|
|
1676
1710
|
const patterns = [
|
|
@@ -1770,6 +1804,9 @@ function toRelativeWebPath(fromDir, toFile) {
|
|
|
1770
1804
|
}
|
|
1771
1805
|
return relative.startsWith('.') ? relative : `./${relative}`;
|
|
1772
1806
|
}
|
|
1807
|
+
function contentRelPathForShell(shellRelPath) {
|
|
1808
|
+
return path.posix.join('assets', 'pages', shellRelPath);
|
|
1809
|
+
}
|
|
1773
1810
|
function isImagePath(filePath) {
|
|
1774
1811
|
return /\.(png|jpe?g|gif|svg|webp|bmp|ico|avif)$/i.test(filePath);
|
|
1775
1812
|
}
|
|
@@ -2117,7 +2154,7 @@ function buildIriAliasMapForPage(aliasesByIri, outputFile) {
|
|
|
2117
2154
|
}
|
|
2118
2155
|
return aliases;
|
|
2119
2156
|
}
|
|
2120
|
-
function wrapHtml(content, runtimeScriptPath, stylesheetPath, blockManifest, blockResults, wikiLinkHrefByKey, iriAliasByIri, scriptSparqlCache) {
|
|
2157
|
+
function wrapHtml(content, runtimeScriptPath, stylesheetPath, blockManifest, blockResults, wikiLinkHrefByKey, iriAliasByIri, scriptSparqlCache, scriptIncludeCache) {
|
|
2121
2158
|
const escapedManifest = escapeJsonForScript(JSON.stringify(blockManifest));
|
|
2122
2159
|
const inlineResults = Object.fromEntries(blockResults.map((result) => [result.blockId, result]));
|
|
2123
2160
|
const escapedInlineResults = escapeJsonForScript(JSON.stringify(inlineResults));
|
|
@@ -2125,10 +2162,12 @@ function wrapHtml(content, runtimeScriptPath, stylesheetPath, blockManifest, blo
|
|
|
2125
2162
|
const escapedIriAliasIndex = escapeJsonForScript(JSON.stringify(iriAliasByIri));
|
|
2126
2163
|
const escapedLinkingConfig = escapeJsonForScript(JSON.stringify({ linkingEnabled: true }));
|
|
2127
2164
|
const escapedScriptCache = escapeJsonForScript(JSON.stringify(scriptSparqlCache));
|
|
2165
|
+
const escapedIncludeCache = escapeJsonForScript(JSON.stringify(scriptIncludeCache));
|
|
2128
2166
|
return `<!doctype html>
|
|
2129
2167
|
<html lang="en">
|
|
2130
2168
|
<head>
|
|
2131
2169
|
<meta charset="UTF-8">
|
|
2170
|
+
<base href="__OML_SHELL_BASE_HREF__" target="_top">
|
|
2132
2171
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
2133
2172
|
<title>OML Markdown</title>
|
|
2134
2173
|
<script>
|
|
@@ -2150,6 +2189,7 @@ function wrapHtml(content, runtimeScriptPath, stylesheetPath, blockManifest, blo
|
|
|
2150
2189
|
<script id="oml-md-wikilink-config" type="application/json">${escapedLinkingConfig}</script>
|
|
2151
2190
|
<script id="oml-md-member-labels" type="application/json">{}</script>
|
|
2152
2191
|
<script id="oml-md-script-sparql-cache" type="application/json">${escapedScriptCache}</script>
|
|
2192
|
+
<script id="oml-md-script-include-cache" type="application/json">${escapedIncludeCache}</script>
|
|
2153
2193
|
<script src="${escapeAttribute(runtimeScriptPath)}"></script>
|
|
2154
2194
|
</body>
|
|
2155
2195
|
</html>
|
|
@@ -2763,6 +2803,14 @@ class InMemoryJsonRpcLspClient {
|
|
|
2763
2803
|
}
|
|
2764
2804
|
async renderWorkspace(params) {
|
|
2765
2805
|
await this.ensureInitialized();
|
|
2806
|
+
const reasoningService = this.runtime.Oml.reasoning.ReasoningService;
|
|
2807
|
+
const render = () => this.renderWorkspaceWithInitializedRuntime(params);
|
|
2808
|
+
if (typeof reasoningService?.suppressSemanticChangeNotifications === 'function') {
|
|
2809
|
+
return await reasoningService.suppressSemanticChangeNotifications(render);
|
|
2810
|
+
}
|
|
2811
|
+
return await render();
|
|
2812
|
+
}
|
|
2813
|
+
async renderWorkspaceWithInitializedRuntime(params) {
|
|
2766
2814
|
await this.ensureWorkspaceSettled(false);
|
|
2767
2815
|
const lint = await this.lintWorkspace({});
|
|
2768
2816
|
if (lint.errors > 0 || lint.warnings > 0) {
|
|
@@ -2819,6 +2867,7 @@ class InMemoryJsonRpcLspClient {
|
|
|
2819
2867
|
const workspaceAssetFiles = new Set();
|
|
2820
2868
|
const aliasesByIri = new Map();
|
|
2821
2869
|
const renderJobs = [];
|
|
2870
|
+
const mdHtmlPaths = [];
|
|
2822
2871
|
const contextModelUris = new Set();
|
|
2823
2872
|
let filesRendered = 0;
|
|
2824
2873
|
let blockArtifactFiles = 0;
|
|
@@ -2851,13 +2900,13 @@ class InMemoryJsonRpcLspClient {
|
|
|
2851
2900
|
});
|
|
2852
2901
|
const prepared = runtime.prepare(expandedMarkdown);
|
|
2853
2902
|
const relative = path.relative(inputDir, markdownPath).replace(/\\/g, '/');
|
|
2854
|
-
const
|
|
2903
|
+
const shellPath = path.join(outputDir, relative.replace(/\.md$/i, '.html'));
|
|
2855
2904
|
const rewriteResult = rewriteRenderedLinks(prepared.renderedHtml, {
|
|
2856
2905
|
workspaceRoot,
|
|
2857
2906
|
inputRoot: inputDir,
|
|
2858
2907
|
inputFile: markdownPath,
|
|
2859
2908
|
outputRoot: outputDir,
|
|
2860
|
-
outputFile:
|
|
2909
|
+
outputFile: shellPath,
|
|
2861
2910
|
});
|
|
2862
2911
|
for (const asset of rewriteResult.workspaceAssets) {
|
|
2863
2912
|
workspaceAssetFiles.add(asset);
|
|
@@ -2879,22 +2928,25 @@ class InMemoryJsonRpcLspClient {
|
|
|
2879
2928
|
inputRoot: inputDir,
|
|
2880
2929
|
sourceFile: markdownPath,
|
|
2881
2930
|
outputRoot: outputDir,
|
|
2882
|
-
outputFile:
|
|
2931
|
+
outputFile: shellPath,
|
|
2883
2932
|
}, workspaceAssetFiles));
|
|
2884
|
-
const blockArtifacts = await writeBlockArtifacts(
|
|
2933
|
+
const blockArtifacts = await writeBlockArtifacts(shellPath, rewrittenBlockResults);
|
|
2885
2934
|
blockArtifactFiles += blockArtifacts.count;
|
|
2886
|
-
const wikiLinkHrefByKey = buildWikiLinkHrefMapForPage(wikiPageIndex,
|
|
2935
|
+
const wikiLinkHrefByKey = buildWikiLinkHrefMapForPage(wikiPageIndex, shellPath);
|
|
2887
2936
|
const scriptSparqlCache = contextModelUri
|
|
2888
2937
|
? await buildScriptSparqlCache(prepared.codeBlocks, (sparql) => reasoningService.getSparqlService().query(contextModelUri, sparql))
|
|
2889
2938
|
: {};
|
|
2939
|
+
const scriptIncludeCache = await buildScriptIncludeCache(prepared.codeBlocks, workspaceRoot);
|
|
2890
2940
|
renderJobs.push({
|
|
2891
|
-
|
|
2941
|
+
shellPath,
|
|
2892
2942
|
renderedHtml: rewriteResult.html,
|
|
2893
2943
|
blockManifest: blockArtifacts.manifest,
|
|
2894
2944
|
blockResults: rewrittenBlockResults,
|
|
2895
2945
|
wikiLinkHrefByKey,
|
|
2896
2946
|
scriptSparqlCache,
|
|
2947
|
+
scriptIncludeCache,
|
|
2897
2948
|
});
|
|
2949
|
+
mdHtmlPaths.push(shellPath);
|
|
2898
2950
|
filesRendered += 1;
|
|
2899
2951
|
}
|
|
2900
2952
|
const renderedNavigationPages = new Set();
|
|
@@ -2907,15 +2959,15 @@ class InMemoryJsonRpcLspClient {
|
|
|
2907
2959
|
if (!resolution.template) {
|
|
2908
2960
|
continue;
|
|
2909
2961
|
}
|
|
2910
|
-
const
|
|
2911
|
-
if (!
|
|
2962
|
+
const targetShellFile = memberIriToOutputFile(outputDir, memberIri);
|
|
2963
|
+
if (!targetShellFile) {
|
|
2912
2964
|
continue;
|
|
2913
2965
|
}
|
|
2914
|
-
aliasesByIri.set(memberIri,
|
|
2915
|
-
if (renderedNavigationPages.has(
|
|
2966
|
+
aliasesByIri.set(memberIri, targetShellFile);
|
|
2967
|
+
if (renderedNavigationPages.has(targetShellFile)) {
|
|
2916
2968
|
continue;
|
|
2917
2969
|
}
|
|
2918
|
-
renderedNavigationPages.add(
|
|
2970
|
+
renderedNavigationPages.add(targetShellFile);
|
|
2919
2971
|
const contextOntologyIri = inferOntologyIriFromMemberIri(memberIri);
|
|
2920
2972
|
const sourceDocumentUri = resolution.template.sourceUri?.trim() || pathToFileURL(path.join(workspaceRoot, 'index.md')).toString();
|
|
2921
2973
|
const invocation = {
|
|
@@ -2940,8 +2992,11 @@ class InMemoryJsonRpcLspClient {
|
|
|
2940
2992
|
},
|
|
2941
2993
|
args: {},
|
|
2942
2994
|
};
|
|
2943
|
-
|
|
2944
|
-
|
|
2995
|
+
let rendered;
|
|
2996
|
+
try {
|
|
2997
|
+
rendered = renderTemplate(resolution.template, invocation);
|
|
2998
|
+
}
|
|
2999
|
+
catch {
|
|
2945
3000
|
continue;
|
|
2946
3001
|
}
|
|
2947
3002
|
const syntheticSourcePath = resolution.template.sourceUri?.startsWith('file:')
|
|
@@ -2961,7 +3016,7 @@ class InMemoryJsonRpcLspClient {
|
|
|
2961
3016
|
inputRoot: inputDir,
|
|
2962
3017
|
inputFile: syntheticSourcePath,
|
|
2963
3018
|
outputRoot: outputDir,
|
|
2964
|
-
outputFile:
|
|
3019
|
+
outputFile: targetShellFile,
|
|
2965
3020
|
});
|
|
2966
3021
|
for (const asset of rewriteResult.workspaceAssets) {
|
|
2967
3022
|
workspaceAssetFiles.add(asset);
|
|
@@ -2983,18 +3038,20 @@ class InMemoryJsonRpcLspClient {
|
|
|
2983
3038
|
inputRoot: inputDir,
|
|
2984
3039
|
sourceFile: syntheticSourcePath,
|
|
2985
3040
|
outputRoot: outputDir,
|
|
2986
|
-
outputFile:
|
|
3041
|
+
outputFile: targetShellFile,
|
|
2987
3042
|
}, workspaceAssetFiles));
|
|
2988
|
-
const blockArtifacts = await writeBlockArtifacts(
|
|
3043
|
+
const blockArtifacts = await writeBlockArtifacts(targetShellFile, rewrittenBlockResults);
|
|
2989
3044
|
blockArtifactFiles += blockArtifacts.count;
|
|
2990
3045
|
const scriptSparqlCache = await buildScriptSparqlCache(prepared.codeBlocks, (sparql) => reasoningService.getSparqlService().query(modelUri, sparql));
|
|
3046
|
+
const scriptIncludeCache = await buildScriptIncludeCache(prepared.codeBlocks, workspaceRoot);
|
|
2991
3047
|
renderJobs.push({
|
|
2992
|
-
|
|
3048
|
+
shellPath: targetShellFile,
|
|
2993
3049
|
renderedHtml: rewriteResult.html,
|
|
2994
3050
|
blockManifest: blockArtifacts.manifest,
|
|
2995
3051
|
blockResults: rewrittenBlockResults,
|
|
2996
|
-
wikiLinkHrefByKey: buildWikiLinkHrefMapForPage(wikiPageIndex,
|
|
3052
|
+
wikiLinkHrefByKey: buildWikiLinkHrefMapForPage(wikiPageIndex, targetShellFile),
|
|
2997
3053
|
scriptSparqlCache,
|
|
3054
|
+
scriptIncludeCache,
|
|
2998
3055
|
});
|
|
2999
3056
|
filesRendered += 1;
|
|
3000
3057
|
});
|
|
@@ -3003,12 +3060,12 @@ class InMemoryJsonRpcLspClient {
|
|
|
3003
3060
|
for (const task of navTasks) {
|
|
3004
3061
|
await task();
|
|
3005
3062
|
}
|
|
3063
|
+
const shellContentByRelPath = new Map();
|
|
3006
3064
|
for (const job of renderJobs) {
|
|
3007
|
-
const runtimeScriptRelative = toRelativeWebPath(path.dirname(job.
|
|
3008
|
-
const stylesheetRelative = toRelativeWebPath(path.dirname(job.
|
|
3009
|
-
const html = wrapHtml(job.renderedHtml, runtimeScriptRelative, stylesheetRelative, job.blockManifest, job.blockResults, job.wikiLinkHrefByKey, buildIriAliasMapForPage(aliasesByIri, job.
|
|
3010
|
-
|
|
3011
|
-
await fs.writeFile(job.htmlPath, html, 'utf-8');
|
|
3065
|
+
const runtimeScriptRelative = toRelativeWebPath(path.dirname(job.shellPath), staticAssets.runtimeScriptFile);
|
|
3066
|
+
const stylesheetRelative = toRelativeWebPath(path.dirname(job.shellPath), staticAssets.stylesheetFile);
|
|
3067
|
+
const html = wrapHtml(job.renderedHtml, runtimeScriptRelative, stylesheetRelative, job.blockManifest, job.blockResults, job.wikiLinkHrefByKey, buildIriAliasMapForPage(aliasesByIri, job.shellPath), job.scriptSparqlCache, job.scriptIncludeCache);
|
|
3068
|
+
shellContentByRelPath.set(path.relative(outputDir, job.shellPath).replace(/\\/g, '/'), html);
|
|
3012
3069
|
}
|
|
3013
3070
|
for (const file of workspaceAssetFiles) {
|
|
3014
3071
|
const workspaceRelative = path.relative(workspaceRoot, file);
|
|
@@ -3034,6 +3091,33 @@ class InMemoryJsonRpcLspClient {
|
|
|
3034
3091
|
}
|
|
3035
3092
|
}
|
|
3036
3093
|
}
|
|
3094
|
+
const workspaceSettings = await readWorkspaceSettings(workspaceRoot);
|
|
3095
|
+
const projectTitle = workspaceSettings.project?.title?.trim() || undefined;
|
|
3096
|
+
const indexEntry = mdHtmlPaths.find(p => path.relative(outputDir, p).replace(/\\/g, '/').toLowerCase() === 'index.html');
|
|
3097
|
+
const homePath = indexEntry ? path.relative(outputDir, indexEntry).replace(/\\/g, '/') : undefined;
|
|
3098
|
+
const shellPaths = renderJobs.map(j => j.shellPath);
|
|
3099
|
+
const shellPathSet = new Set(shellPaths.map(p => path.relative(outputDir, p).replace(/\\/g, '/')));
|
|
3100
|
+
const contentPathByShellRelPath = new Map();
|
|
3101
|
+
for (const [shellRelPath, contentHtml] of shellContentByRelPath) {
|
|
3102
|
+
const shellFile = path.join(outputDir, shellRelPath);
|
|
3103
|
+
const contentRelPath = contentRelPathForShell(shellRelPath);
|
|
3104
|
+
const contentFile = path.join(outputDir, contentRelPath);
|
|
3105
|
+
const shellHrefFromContent = toRelativeWebPath(path.dirname(contentFile), shellFile);
|
|
3106
|
+
const html = contentHtml.replace(/__OML_SHELL_BASE_HREF__/g, escapeAttribute(shellHrefFromContent));
|
|
3107
|
+
await fs.mkdir(path.dirname(contentFile), { recursive: true });
|
|
3108
|
+
await fs.writeFile(contentFile, html, 'utf-8');
|
|
3109
|
+
contentPathByShellRelPath.set(shellRelPath, contentRelPath);
|
|
3110
|
+
}
|
|
3111
|
+
for (const shellRelPath of shellPathSet) {
|
|
3112
|
+
const shellHtml = generateShellIndex(outputDir, mdHtmlPaths, projectTitle, homePath, shellPaths, shellRelPath, contentPathByShellRelPath.get(shellRelPath));
|
|
3113
|
+
const shellFile = path.join(outputDir, shellRelPath);
|
|
3114
|
+
await fs.mkdir(path.dirname(shellFile), { recursive: true });
|
|
3115
|
+
await fs.writeFile(shellFile, shellHtml, 'utf-8');
|
|
3116
|
+
}
|
|
3117
|
+
if (!shellPathSet.has('index.html')) {
|
|
3118
|
+
const indexHtml = generateShellIndex(outputDir, mdHtmlPaths, projectTitle, undefined, shellPaths);
|
|
3119
|
+
await fs.writeFile(path.join(outputDir, 'index.html'), indexHtml, 'utf-8');
|
|
3120
|
+
}
|
|
3037
3121
|
return { success: true, filesRendered, outputDir, blockArtifactFiles };
|
|
3038
3122
|
}
|
|
3039
3123
|
async ontologiesWorkspace() {
|
|
@@ -3204,7 +3288,16 @@ class InMemoryJsonRpcLspClient {
|
|
|
3204
3288
|
.map((uri) => URI.parse(uri));
|
|
3205
3289
|
await Promise.all(changedUris.map((uri) => documents.getOrCreateDocument(uri)));
|
|
3206
3290
|
const builder = this.runtime.shared.workspace.DocumentBuilder;
|
|
3207
|
-
|
|
3291
|
+
const reasoningService = this.runtime.Oml.reasoning.ReasoningService;
|
|
3292
|
+
const runUpdate = async () => {
|
|
3293
|
+
await builder.update(changedUris, deletedUris);
|
|
3294
|
+
};
|
|
3295
|
+
if (typeof reasoningService?.suppressSemanticChangeNotifications === 'function') {
|
|
3296
|
+
await reasoningService.suppressSemanticChangeNotifications(runUpdate);
|
|
3297
|
+
}
|
|
3298
|
+
else {
|
|
3299
|
+
await runUpdate();
|
|
3300
|
+
}
|
|
3208
3301
|
await this.waitForValidatedWithTrace();
|
|
3209
3302
|
}
|
|
3210
3303
|
async bootstrapWorkspaceOmlDocuments() {
|