@hpcc-js/observablehq-compiler 1.1.4 → 1.2.1
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/bin/ojscc.mjs +4 -5
- package/dist/index.esm.js +156 -98
- package/dist/index.esm.js.map +1 -1
- package/dist/index.esm.min.js +3 -3
- package/dist/index.esm.min.js.map +1 -1
- package/dist/index.js +160 -100
- package/dist/index.js.map +1 -1
- package/dist/index.min.js +3 -3
- package/dist/index.min.js.map +1 -1
- package/package.json +3 -4
- package/src/__package__.ts +2 -2
- package/src/__tests__/m1.mjs +3 -0
- package/src/__tests__/node.ts +24 -2
- package/src/compiler.ts +135 -103
- package/src/cst.ts +9 -6
- package/src/index.ts +1 -1
- package/src/util.ts +22 -4
- package/types/__package__.d.ts +2 -2
- package/types/__package__.d.ts.map +1 -1
- package/types/compiler.d.ts +108 -39
- package/types/compiler.d.ts.map +1 -1
- package/types/cst.d.ts +1 -1
- package/types/cst.d.ts.map +1 -1
- package/types/index.d.ts +1 -1
- package/types/index.d.ts.map +1 -1
- package/types/util.d.ts +2 -1
- package/types/util.d.ts.map +1 -1
- package/types-3.4/__package__.d.ts +2 -2
- package/types-3.4/compiler.d.ts +108 -42
- package/types-3.4/cst.d.ts +1 -1
- package/types-3.4/index.d.ts +1 -1
- package/types-3.4/util.d.ts +2 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hpcc-js/observablehq-compiler",
|
|
3
|
-
"version": "1.1
|
|
3
|
+
"version": "1.2.1",
|
|
4
4
|
"description": "hpcc-js - ObservableHQ Compiler (unoffical)",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"observablehq",
|
|
@@ -56,13 +56,12 @@
|
|
|
56
56
|
"update": "npx --yes npm-check-updates -u -t minor"
|
|
57
57
|
},
|
|
58
58
|
"dependencies": {
|
|
59
|
-
"@hpcc-js/observable-shim": "^2.
|
|
59
|
+
"@hpcc-js/observable-shim": "^2.4.0",
|
|
60
60
|
"node-fetch": "3.2.10",
|
|
61
61
|
"yargs": "17.5.1"
|
|
62
62
|
},
|
|
63
63
|
"devDependencies": {
|
|
64
64
|
"@hpcc-js/bundle": "^2.11.3",
|
|
65
|
-
"@hpcc-js/util": "^2.50.0",
|
|
66
65
|
"@observablehq/runtime": "4.25.0",
|
|
67
66
|
"tslib": "2.4.0"
|
|
68
67
|
},
|
|
@@ -77,5 +76,5 @@
|
|
|
77
76
|
"url": "https://github.com/hpcc-systems/Visualization/issues"
|
|
78
77
|
},
|
|
79
78
|
"homepage": "https://github.com/hpcc-systems/Visualization/tree/trunk/packages/observablehq-compiler",
|
|
80
|
-
"gitHead": "
|
|
79
|
+
"gitHead": "015f4b88a046e6fd114ba409eff0ce286d0c063d"
|
|
81
80
|
}
|
package/src/__package__.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
export const PKG_NAME = "@hpcc-js/observablehq-compiler";
|
|
2
|
-
export const PKG_VERSION = "1.1
|
|
3
|
-
export const BUILD_VERSION = "2.104.
|
|
2
|
+
export const PKG_VERSION = "1.2.1";
|
|
3
|
+
export const BUILD_VERSION = "2.104.10";
|
package/src/__tests__/node.ts
CHANGED
|
@@ -59,7 +59,7 @@ describe("ojs", function () {
|
|
|
59
59
|
});
|
|
60
60
|
});
|
|
61
61
|
|
|
62
|
-
it
|
|
62
|
+
it("simple", async function () {
|
|
63
63
|
this.timeout(10000);
|
|
64
64
|
|
|
65
65
|
const notebook = ojs2notebook(ojs);
|
|
@@ -99,7 +99,7 @@ describe("ojs", function () {
|
|
|
99
99
|
await main.value("tenTimes");
|
|
100
100
|
|
|
101
101
|
for (const cellID in define.cells) {
|
|
102
|
-
define.
|
|
102
|
+
define.delete(cellID);
|
|
103
103
|
break;
|
|
104
104
|
}
|
|
105
105
|
});
|
|
@@ -132,6 +132,28 @@ describe("ojs", function () {
|
|
|
132
132
|
|
|
133
133
|
});
|
|
134
134
|
|
|
135
|
+
it("esm imports", async function () {
|
|
136
|
+
this.timeout(10000);
|
|
137
|
+
|
|
138
|
+
const define = await compile(`\
|
|
139
|
+
m1 = import("../src/__tests__/m1.mjs");
|
|
140
|
+
x = m1.f(5, 7);
|
|
141
|
+
`);
|
|
142
|
+
|
|
143
|
+
const library = new Library();
|
|
144
|
+
const runtime = new Runtime(library);
|
|
145
|
+
const main: ohq.Module = define(runtime, name => {
|
|
146
|
+
return {
|
|
147
|
+
pending() { },
|
|
148
|
+
fulfilled(value) { console.info("fulfilled", name, value); },
|
|
149
|
+
rejected(error) { console.error("rejected", name, error); },
|
|
150
|
+
};
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
expect(await main.value("x")).to.equal(35);
|
|
154
|
+
|
|
155
|
+
});
|
|
156
|
+
|
|
135
157
|
it("Introduction to Imports", async function () {
|
|
136
158
|
|
|
137
159
|
const define = await compile(imports as any);
|
package/src/compiler.ts
CHANGED
|
@@ -1,43 +1,50 @@
|
|
|
1
1
|
import { ohq, splitModule } from "@hpcc-js/observable-shim";
|
|
2
|
-
|
|
3
|
-
import { endsWith, join } from "@hpcc-js/util";
|
|
4
2
|
import { parseCell, ParsedImportCell } from "./cst";
|
|
5
3
|
import { Writer } from "./writer";
|
|
6
|
-
import { encodeBacktick, fetchEx, obfuscatedImport, ojs2notebook, omd2notebook } from "./util";
|
|
4
|
+
import { fixRelativeUrl, isRelativePath, encodeBacktick, fetchEx, obfuscatedImport, ojs2notebook, omd2notebook } from "./util";
|
|
5
|
+
|
|
6
|
+
// Inspector Factory ---
|
|
7
|
+
export type InspectorFactoryEx = (name: string | undefined, id: string | number) => Inspector;
|
|
8
|
+
|
|
9
|
+
export interface Inspector {
|
|
10
|
+
_node?: HTMLDivElement;
|
|
11
|
+
pending();
|
|
12
|
+
fulfilled(value);
|
|
13
|
+
rejected(error);
|
|
14
|
+
}
|
|
7
15
|
|
|
8
|
-
|
|
9
|
-
const fullUrl = (path: string, basePath: string) => isRelativePath(path) ? join(basePath, path) : path;
|
|
16
|
+
// Module ---
|
|
10
17
|
|
|
11
18
|
interface ImportDefine {
|
|
12
|
-
(runtime: ohq.Runtime, inspector?:
|
|
13
|
-
|
|
19
|
+
(runtime: ohq.Runtime, inspector?: InspectorFactoryEx): ohq.Module;
|
|
20
|
+
delete: () => void;
|
|
14
21
|
write: (w: Writer) => void;
|
|
15
22
|
}
|
|
16
23
|
|
|
17
24
|
async function importFile(relativePath: string, baseUrl: string) {
|
|
18
|
-
const path =
|
|
25
|
+
const path = fixRelativeUrl(relativePath, baseUrl);
|
|
19
26
|
const content = await fetchEx(path).then(r => r.text());
|
|
20
27
|
let notebook: ohq.Notebook;
|
|
21
|
-
if (endsWith(
|
|
28
|
+
if (relativePath.endsWith(".ojsnb")) {
|
|
22
29
|
notebook = JSON.parse(content);
|
|
23
|
-
} else if (endsWith(
|
|
30
|
+
} else if (relativePath.endsWith(".ojs")) {
|
|
24
31
|
notebook = ojs2notebook(content);
|
|
25
|
-
} else if (endsWith(
|
|
32
|
+
} else if (relativePath.endsWith(".omd")) {
|
|
26
33
|
notebook = omd2notebook(content);
|
|
27
34
|
}
|
|
28
|
-
const retVal: ImportDefine = compile(notebook, baseUrl) as any;
|
|
29
|
-
retVal.
|
|
35
|
+
const retVal: ImportDefine = compile(notebook, { baseUrl }) as any;
|
|
36
|
+
retVal.delete = () => { };
|
|
30
37
|
retVal.write = (w: Writer) => {
|
|
31
38
|
w.import(path);
|
|
32
39
|
};
|
|
33
40
|
return retVal;
|
|
34
41
|
}
|
|
35
42
|
|
|
36
|
-
//
|
|
43
|
+
// Import precompiled notebook from observable ---
|
|
37
44
|
async function importCompiledNotebook(partial: string) {
|
|
38
45
|
const url = `https://api.observablehq.com/${partial[0] === "@" ? partial : `d/${partial}`}.js?v=3`;
|
|
39
46
|
let impMod = {
|
|
40
|
-
default: function (runtime: ohq.Runtime, inspector?:
|
|
47
|
+
default: function (runtime: ohq.Runtime, inspector?: InspectorFactoryEx): ohq.Module {
|
|
41
48
|
return undefined;
|
|
42
49
|
} as any
|
|
43
50
|
};
|
|
@@ -46,14 +53,14 @@ async function importCompiledNotebook(partial: string) {
|
|
|
46
53
|
} catch (e) {
|
|
47
54
|
}
|
|
48
55
|
const retVal: ImportDefine = impMod.default;
|
|
49
|
-
retVal.
|
|
56
|
+
retVal.delete = () => { };
|
|
50
57
|
retVal.write = (w: Writer) => {
|
|
51
58
|
w.import(url);
|
|
52
59
|
};
|
|
53
60
|
return retVal;
|
|
54
61
|
}
|
|
55
62
|
|
|
56
|
-
//
|
|
63
|
+
// Recursive notebook parsing and compiling
|
|
57
64
|
async function importNotebook(partial: string) {
|
|
58
65
|
const url = `https://api.observablehq.com/document/${partial}`;
|
|
59
66
|
const notebook = fetchEx(url)
|
|
@@ -64,20 +71,63 @@ async function importNotebook(partial: string) {
|
|
|
64
71
|
console.error(e);
|
|
65
72
|
});
|
|
66
73
|
const retVal: ImportDefine = compile(await notebook) as any;
|
|
67
|
-
retVal.
|
|
74
|
+
retVal.delete = () => { };
|
|
68
75
|
retVal.write = (w: Writer) => {
|
|
69
76
|
w.import(url);
|
|
70
77
|
};
|
|
71
78
|
return retVal;
|
|
72
79
|
}
|
|
73
80
|
|
|
74
|
-
function
|
|
81
|
+
async function createModule(node: ohq.Node, parsed: ParsedImportCell, text: string, { baseUrl, importMode }: CompileOptions) {
|
|
82
|
+
const otherModule = isRelativePath(parsed.src) ?
|
|
83
|
+
await importFile(parsed.src, baseUrl) :
|
|
84
|
+
importMode === "recursive" ?
|
|
85
|
+
await importNotebook(parsed.src) :
|
|
86
|
+
await importCompiledNotebook(parsed.src);
|
|
87
|
+
|
|
88
|
+
const importVariables: ImportVariableFunc[] = [];
|
|
89
|
+
const variables: VariableFunc[] = [];
|
|
90
|
+
parsed.specifiers.forEach(spec => {
|
|
91
|
+
const viewof = spec.view ? "viewof " : "";
|
|
92
|
+
importVariables.push(createImportVariable(viewof + spec.name, viewof + spec.alias));
|
|
93
|
+
if (spec.view) {
|
|
94
|
+
importVariables.push(createImportVariable(spec.name, spec.alias));
|
|
95
|
+
}
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
const retVal = (runtime: ohq.Runtime, main: ohq.Module, inspector?: InspectorFactoryEx) => {
|
|
99
|
+
|
|
100
|
+
let mod = runtime.module(otherModule);
|
|
101
|
+
if (parsed.injections.length) {
|
|
102
|
+
mod = mod.derive(parsed.injections, main);
|
|
103
|
+
}
|
|
104
|
+
variables.forEach(v => v(main, inspector));
|
|
105
|
+
importVariables.forEach(v => v(main, mod));
|
|
106
|
+
return mod;
|
|
107
|
+
};
|
|
108
|
+
retVal.importVariables = importVariables;
|
|
109
|
+
retVal.variables = variables;
|
|
110
|
+
retVal.delete = () => {
|
|
111
|
+
importVariables.forEach(v => v.delete());
|
|
112
|
+
variables.forEach(v => v.delete());
|
|
113
|
+
otherModule.delete();
|
|
114
|
+
};
|
|
115
|
+
retVal.write = (w: Writer) => {
|
|
116
|
+
otherModule.write(w);
|
|
117
|
+
w.importDefine(parsed);
|
|
118
|
+
};
|
|
119
|
+
return retVal;
|
|
120
|
+
}
|
|
121
|
+
type ModuleFunc = Awaited<ReturnType<typeof createModule>>;
|
|
122
|
+
|
|
123
|
+
// Variable ---
|
|
124
|
+
function createVariable(node: ohq.Node, inspect: boolean, name?: string, inputs?: string[], definition?: any, inline = false) {
|
|
75
125
|
|
|
76
126
|
let i: ohq.Inspector;
|
|
77
127
|
let v: ohq.Variable;
|
|
78
128
|
|
|
79
|
-
const retVal = (module: ohq.Module, inspector?:
|
|
80
|
-
i = inspect ? inspector(name) : undefined;
|
|
129
|
+
const retVal = (module: ohq.Module, inspector?: InspectorFactoryEx) => {
|
|
130
|
+
i = inspect ? inspector(name, node.id) : undefined;
|
|
81
131
|
v = module.variable(i);
|
|
82
132
|
if (arguments.length > 1) {
|
|
83
133
|
try {
|
|
@@ -86,9 +136,21 @@ function createVariable(inspect: boolean, name?: string, inputs?: string[], defi
|
|
|
86
136
|
console.error(e?.message);
|
|
87
137
|
}
|
|
88
138
|
}
|
|
139
|
+
if (node.pinned) {
|
|
140
|
+
v = module.variable(inspector(name, node.id));
|
|
141
|
+
try {
|
|
142
|
+
v.define(undefined, ["md"], md => {
|
|
143
|
+
return md`\`\`\`js
|
|
144
|
+
${node.value}
|
|
145
|
+
\`\`\``;
|
|
146
|
+
});
|
|
147
|
+
} catch (e: any) {
|
|
148
|
+
console.error(e?.message);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
89
151
|
return v;
|
|
90
152
|
};
|
|
91
|
-
retVal.
|
|
153
|
+
retVal.delete = () => {
|
|
92
154
|
try {
|
|
93
155
|
i?._node?.remove();
|
|
94
156
|
} catch (e) {
|
|
@@ -121,98 +183,54 @@ function createImportVariable(name?: string, alias?: string) {
|
|
|
121
183
|
v.import(name, alias, otherModule);
|
|
122
184
|
};
|
|
123
185
|
|
|
124
|
-
retVal.
|
|
186
|
+
retVal.delete = () => {
|
|
125
187
|
v?.delete();
|
|
126
188
|
};
|
|
127
189
|
return retVal;
|
|
128
190
|
}
|
|
129
191
|
type ImportVariableFunc = ReturnType<typeof createImportVariable>;
|
|
130
192
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
await importFile(parsed.src, baseUrl) :
|
|
134
|
-
await importCompiledNotebook(parsed.src);
|
|
135
|
-
|
|
136
|
-
const importVariables: ImportVariableFunc[] = [];
|
|
137
|
-
const variables: VariableFunc[] = [];
|
|
138
|
-
parsed.specifiers.forEach(spec => {
|
|
139
|
-
const viewof = spec.view ? "viewof " : "";
|
|
140
|
-
importVariables.push(createImportVariable(viewof + spec.name, viewof + spec.alias));
|
|
141
|
-
if (spec.view) {
|
|
142
|
-
importVariables.push(createImportVariable(spec.name, spec.alias));
|
|
143
|
-
}
|
|
144
|
-
});
|
|
145
|
-
variables.push(createVariable(true, undefined, ["md"], md => {
|
|
146
|
-
return md`\`\`\`JavaScript
|
|
147
|
-
${text}
|
|
148
|
-
\`\`\``;
|
|
149
|
-
}));
|
|
150
|
-
|
|
151
|
-
const retVal = (runtime: ohq.Runtime, main: ohq.Module, inspector?: ohq.InspectorFactory) => {
|
|
152
|
-
|
|
153
|
-
let mod = runtime.module(otherModule);
|
|
154
|
-
if (parsed.injections.length) {
|
|
155
|
-
mod = mod.derive(parsed.injections, main);
|
|
156
|
-
}
|
|
157
|
-
variables.forEach(v => v(main, inspector));
|
|
158
|
-
importVariables.forEach(v => v(main, mod));
|
|
159
|
-
return mod;
|
|
160
|
-
};
|
|
161
|
-
retVal.importVariables = importVariables;
|
|
162
|
-
retVal.variables = variables;
|
|
163
|
-
retVal.dispose = () => {
|
|
164
|
-
importVariables.forEach(v => v.dispose());
|
|
165
|
-
variables.forEach(v => v.dispose());
|
|
166
|
-
otherModule.dispose();
|
|
167
|
-
};
|
|
168
|
-
retVal.write = (w: Writer) => {
|
|
169
|
-
otherModule.write(w);
|
|
170
|
-
w.importDefine(parsed);
|
|
171
|
-
};
|
|
172
|
-
return retVal;
|
|
173
|
-
}
|
|
174
|
-
type ModuleFunc = Awaited<ReturnType<typeof createModule>>;
|
|
175
|
-
|
|
176
|
-
async function createCell(node: ohq.Node, baseUrl: string) {
|
|
193
|
+
// Cell ---
|
|
194
|
+
async function createCell(node: ohq.Node, options: CompileOptions) {
|
|
177
195
|
const modules: ModuleFunc[] = [];
|
|
178
196
|
const variables: VariableFunc[] = [];
|
|
179
197
|
try {
|
|
180
198
|
const text = node.mode && node.mode !== "js" ? `${node.mode}\`${encodeBacktick(node.value)}\`` : node.value;
|
|
181
199
|
const parsedModule = splitModule(text);
|
|
182
|
-
for (const
|
|
183
|
-
const parsed = parseCell(text);
|
|
200
|
+
for (const cell of parsedModule) {
|
|
201
|
+
const parsed = parseCell(cell.text, options.baseUrl);
|
|
184
202
|
switch (parsed.type) {
|
|
185
203
|
case "import":
|
|
186
|
-
modules.push(await createModule(parsed, text,
|
|
204
|
+
modules.push(await createModule(node, parsed, cell.text, options));
|
|
187
205
|
break;
|
|
188
206
|
case "viewof":
|
|
189
|
-
variables.push(createVariable(true, parsed.variable.id, parsed.variable.inputs, parsed.variable.func));
|
|
190
|
-
variables.push(createVariable(false, parsed.variableValue.id, parsed.variableValue.inputs, parsed.variableValue.func, true));
|
|
207
|
+
variables.push(createVariable(node, true, parsed.variable.id, parsed.variable.inputs, parsed.variable.func));
|
|
208
|
+
variables.push(createVariable(node, false, parsed.variableValue.id, parsed.variableValue.inputs, parsed.variableValue.func, true));
|
|
191
209
|
break;
|
|
192
210
|
case "mutable":
|
|
193
|
-
variables.push(createVariable(false, parsed.initial.id, parsed.initial.inputs, parsed.initial.func));
|
|
194
|
-
variables.push(createVariable(false, parsed.variable.id, parsed.variable.inputs, parsed.variable.func));
|
|
195
|
-
variables.push(createVariable(true, parsed.variableValue.id, parsed.variableValue.inputs, parsed.variableValue.func, true));
|
|
211
|
+
variables.push(createVariable(node, false, parsed.initial.id, parsed.initial.inputs, parsed.initial.func));
|
|
212
|
+
variables.push(createVariable(node, false, parsed.variable.id, parsed.variable.inputs, parsed.variable.func));
|
|
213
|
+
variables.push(createVariable(node, true, parsed.variableValue.id, parsed.variableValue.inputs, parsed.variableValue.func, true));
|
|
196
214
|
break;
|
|
197
215
|
case "variable":
|
|
198
|
-
variables.push(createVariable(true, parsed.id, parsed.inputs, parsed.func));
|
|
216
|
+
variables.push(createVariable(node, true, parsed.id, parsed.inputs, parsed.func));
|
|
199
217
|
break;
|
|
200
218
|
}
|
|
201
219
|
}
|
|
202
220
|
} catch (e) {
|
|
203
|
-
variables.push(createVariable(true, undefined, [], e.message));
|
|
221
|
+
variables.push(createVariable(node, true, undefined, [], e.message));
|
|
204
222
|
}
|
|
205
223
|
|
|
206
|
-
const retVal = (runtime: ohq.Runtime, main: ohq.Module, inspector?:
|
|
224
|
+
const retVal = (runtime: ohq.Runtime, main: ohq.Module, inspector?: InspectorFactoryEx) => {
|
|
207
225
|
modules.forEach(imp => imp(runtime, main, inspector));
|
|
208
226
|
variables.forEach(v => v(main, inspector));
|
|
209
227
|
};
|
|
210
|
-
retVal.id =
|
|
228
|
+
retVal.id = node.id;
|
|
211
229
|
retVal.modules = modules;
|
|
212
230
|
retVal.variables = variables;
|
|
213
|
-
retVal.
|
|
214
|
-
variables.forEach(v => v.
|
|
215
|
-
modules.forEach(mod => mod.
|
|
231
|
+
retVal.delete = () => {
|
|
232
|
+
variables.forEach(v => v.delete());
|
|
233
|
+
modules.forEach(mod => mod.delete());
|
|
216
234
|
};
|
|
217
235
|
retVal.write = (w: Writer) => {
|
|
218
236
|
modules.forEach(imp => imp.write(w));
|
|
@@ -222,23 +240,27 @@ async function createCell(node: ohq.Node, baseUrl: string) {
|
|
|
222
240
|
}
|
|
223
241
|
export type CellFunc = Awaited<ReturnType<typeof createCell>>;
|
|
224
242
|
|
|
225
|
-
|
|
243
|
+
// File ---
|
|
244
|
+
function createFile(file: ohq.File, options: CompileOptions): [string, any] {
|
|
226
245
|
function toString() { return globalThis.url; }
|
|
227
|
-
return [file.name, { url: new URL(
|
|
246
|
+
return [file.name, { url: new URL(fixRelativeUrl(file.url, options.baseUrl)), mimeType: file.mime_type, toString }];
|
|
228
247
|
}
|
|
229
|
-
|
|
248
|
+
type FileFunc = ReturnType<typeof createFile>;
|
|
230
249
|
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
250
|
+
// Interpret ---
|
|
251
|
+
export interface CompileOptions {
|
|
252
|
+
baseUrl?: string;
|
|
253
|
+
importMode?: "recursive" | "precompiled";
|
|
254
|
+
}
|
|
255
|
+
export function notebook(_files: ohq.File[] = [], _cells: CellFunc[] = [], { baseUrl = ".", importMode = "precompiled" }: CompileOptions = {}) {
|
|
256
|
+
const files: FileFunc[] = _files.map(f => createFile(f, { baseUrl, importMode }));
|
|
234
257
|
const fileAttachments = new Map<string, any>(files);
|
|
235
|
-
const
|
|
236
|
-
const cells = new Map<string, CellFunc>(_cells.map(c => [c.id, c]));
|
|
258
|
+
const cells = new Map<string | number, CellFunc>(_cells.map(c => [c.id, c]));
|
|
237
259
|
|
|
238
|
-
const retVal = (runtime: ohq.Runtime, inspector?:
|
|
260
|
+
const retVal = (runtime: ohq.Runtime, inspector?: InspectorFactoryEx): ohq.Module => {
|
|
239
261
|
const main = runtime.module();
|
|
240
262
|
main.builtin("FileAttachment", runtime.fileAttachments(name => {
|
|
241
|
-
return fileAttachments.get(name) ?? { url: new URL(
|
|
263
|
+
return fileAttachments.get(name) ?? { url: new URL(fixRelativeUrl(name, baseUrl)), mimeType: null };
|
|
242
264
|
}));
|
|
243
265
|
main.builtin("fetchEx", fetchEx);
|
|
244
266
|
|
|
@@ -249,25 +271,29 @@ export async function compile(notebook: ohq.Notebook, baseUrl: string = ".") {
|
|
|
249
271
|
};
|
|
250
272
|
retVal.fileAttachments = fileAttachments;
|
|
251
273
|
retVal.cells = cells;
|
|
252
|
-
retVal.
|
|
253
|
-
const cell = await createCell(n, baseUrl);
|
|
254
|
-
retVal.
|
|
274
|
+
retVal.set = async (n: ohq.Node): Promise<CellFunc> => {
|
|
275
|
+
const cell = await createCell(n, { baseUrl, importMode });
|
|
276
|
+
retVal.delete(cell.id);
|
|
255
277
|
cells.set(cell.id, cell);
|
|
256
278
|
return cell;
|
|
257
279
|
};
|
|
258
|
-
retVal.
|
|
280
|
+
retVal.get = (id: string | number): CellFunc => {
|
|
281
|
+
return cells.get(id);
|
|
282
|
+
};
|
|
283
|
+
retVal.delete = (id: string | number): boolean => {
|
|
259
284
|
const cell = cells.get(id);
|
|
260
285
|
if (cell) {
|
|
261
|
-
|
|
262
|
-
|
|
286
|
+
cell.delete();
|
|
287
|
+
return cells.delete(id);
|
|
263
288
|
}
|
|
289
|
+
return false;
|
|
264
290
|
};
|
|
265
|
-
retVal.
|
|
266
|
-
cells.forEach(cell => cell.
|
|
291
|
+
retVal.clear = () => {
|
|
292
|
+
cells.forEach(cell => cell.delete());
|
|
267
293
|
cells.clear();
|
|
268
294
|
};
|
|
269
295
|
retVal.write = (w: Writer) => {
|
|
270
|
-
w.files(
|
|
296
|
+
w.files(_files);
|
|
271
297
|
cells.forEach(cell => cell.write(w));
|
|
272
298
|
};
|
|
273
299
|
retVal.toString = (w = new Writer()) => {
|
|
@@ -276,4 +302,10 @@ export async function compile(notebook: ohq.Notebook, baseUrl: string = ".") {
|
|
|
276
302
|
};
|
|
277
303
|
return retVal;
|
|
278
304
|
}
|
|
305
|
+
|
|
306
|
+
export async function compile(notebookOrOjs: ohq.Notebook | string, { baseUrl = ".", importMode = "precompiled" }: CompileOptions = {}) {
|
|
307
|
+
const ojsNotebook = typeof notebookOrOjs === "string" ? ojs2notebook(notebookOrOjs) : notebookOrOjs;
|
|
308
|
+
const _cells: CellFunc[] = await Promise.all(ojsNotebook.nodes.map(n => createCell(n, { baseUrl, importMode })));
|
|
309
|
+
return notebook(ojsNotebook.files, _cells, { baseUrl, importMode });
|
|
310
|
+
}
|
|
279
311
|
export type compileFunc = Awaited<ReturnType<typeof compile>>;
|
package/src/cst.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { parseCell as ohqParseCell, ancestor, walk } from "@hpcc-js/observable-shim";
|
|
2
|
-
import { createFunction, Refs } from "./util";
|
|
2
|
+
import { fixRelativeUrl, createFunction, Refs } from "./util";
|
|
3
3
|
|
|
4
4
|
function calcRefs(cellAst, cellStr): Refs {
|
|
5
5
|
if (cellAst.references === undefined) return { inputs: [], args: [], patches: [] };
|
|
@@ -51,7 +51,7 @@ export interface ParsedImportCell extends ParsedCell {
|
|
|
51
51
|
injections: { name: string, alias: string }[];
|
|
52
52
|
}
|
|
53
53
|
|
|
54
|
-
function
|
|
54
|
+
function parseImportDeclaration(cellAst): ParsedImportCell {
|
|
55
55
|
return {
|
|
56
56
|
type: "import",
|
|
57
57
|
src: cellAst.body.source.value,
|
|
@@ -153,14 +153,17 @@ function parseVariableExpression(cellStr: string, cellAst, refs: Refs, bodyStr?:
|
|
|
153
153
|
};
|
|
154
154
|
}
|
|
155
155
|
|
|
156
|
-
export function parseCell(cellStr: string): ParsedImportCell | ParsedViewCell | ParsedMutableCell | ParsedVariableCell {
|
|
156
|
+
export function parseCell(cellStr: string, baseUrl: string): ParsedImportCell | ParsedViewCell | ParsedMutableCell | ParsedVariableCell {
|
|
157
157
|
const cellAst = ohqParseCell(cellStr);
|
|
158
|
-
|
|
159
|
-
|
|
158
|
+
let bodyStr = cellAst.body && cellStr.substring(cellAst.body.start, cellAst.body.end);
|
|
159
|
+
switch ((cellAst.body)?.type) {
|
|
160
|
+
case "ImportDeclaration":
|
|
161
|
+
return parseImportDeclaration(cellAst);
|
|
162
|
+
case "ImportExpression":
|
|
163
|
+
bodyStr = `import("${fixRelativeUrl(cellAst.body.source.value, baseUrl)}")`;
|
|
160
164
|
}
|
|
161
165
|
const refs = calcRefs(cellAst, cellStr);
|
|
162
166
|
|
|
163
|
-
const bodyStr = cellAst.body && cellStr.substring(cellAst.body.start, cellAst.body.end);
|
|
164
167
|
switch (cellAst.id?.type) {
|
|
165
168
|
case "ViewExpression":
|
|
166
169
|
return parseViewExpression(cellStr, cellAst, refs, bodyStr);
|
package/src/index.ts
CHANGED
package/src/util.ts
CHANGED
|
@@ -41,6 +41,20 @@ export function createFunction(refs: Refs, async = false, generator = false, blo
|
|
|
41
41
|
`return (\n${body}\n);`);
|
|
42
42
|
}
|
|
43
43
|
|
|
44
|
+
function join(baseURL, relativeURL) {
|
|
45
|
+
return relativeURL
|
|
46
|
+
? baseURL.replace(/\/+$/, "") + "/" + relativeURL.replace(/^\/+/, "")
|
|
47
|
+
: baseURL;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export const isRelativePath = (path: string) => path[0] === ".";
|
|
51
|
+
export const fixRelativeUrl = (path: string, basePath: string) => {
|
|
52
|
+
if (isRelativePath(path)) {
|
|
53
|
+
return join(basePath, path);
|
|
54
|
+
}
|
|
55
|
+
return path;
|
|
56
|
+
};
|
|
57
|
+
|
|
44
58
|
// Hide "import" from bundlers as they have a habit of replacing "import" with "require"
|
|
45
59
|
export async function obfuscatedImport(url: string) {
|
|
46
60
|
return new FuncTypes.asyncFunctionType("url", "return import(url)")(url);
|
|
@@ -77,7 +91,7 @@ function createParsedOJS(ojs: string, offset: number, inlineMD: boolean): Parsed
|
|
|
77
91
|
};
|
|
78
92
|
}
|
|
79
93
|
|
|
80
|
-
|
|
94
|
+
function splitOmd(_: string): ParsedOJS[] {
|
|
81
95
|
const retVal: ParsedOJS[] = [];
|
|
82
96
|
// Load Markdown ---
|
|
83
97
|
const re = /(```(?:\s|\S)[\s\S]*?```)/g;
|
|
@@ -119,21 +133,25 @@ export function ojs2notebook(ojs: string): ohq.Notebook {
|
|
|
119
133
|
return {
|
|
120
134
|
id: idx,
|
|
121
135
|
mode: "js",
|
|
122
|
-
value: cell
|
|
136
|
+
value: cell.text,
|
|
137
|
+
start: cell.start,
|
|
138
|
+
end: cell.end
|
|
123
139
|
};
|
|
124
140
|
})
|
|
125
141
|
} as ohq.Notebook;
|
|
126
142
|
}
|
|
127
143
|
|
|
128
144
|
export function omd2notebook(omd: string): ohq.Notebook {
|
|
129
|
-
const cells =
|
|
145
|
+
const cells = splitOmd(omd);
|
|
130
146
|
return {
|
|
131
147
|
files: [],
|
|
132
148
|
nodes: cells.map((cell, idx) => {
|
|
133
149
|
return {
|
|
134
150
|
id: idx,
|
|
135
151
|
mode: cell.inlineMD ? "md" : "js",
|
|
136
|
-
value: cell.ojs
|
|
152
|
+
value: cell.ojs,
|
|
153
|
+
start: cell.offset,
|
|
154
|
+
end: cell.offset + cell.ojs.length
|
|
137
155
|
};
|
|
138
156
|
})
|
|
139
157
|
} as ohq.Notebook;
|
package/types/__package__.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
export declare const PKG_NAME = "@hpcc-js/observablehq-compiler";
|
|
2
|
-
export declare const PKG_VERSION = "1.1
|
|
3
|
-
export declare const BUILD_VERSION = "2.104.
|
|
2
|
+
export declare const PKG_VERSION = "1.2.1";
|
|
3
|
+
export declare const BUILD_VERSION = "2.104.10";
|
|
4
4
|
//# sourceMappingURL=__package__.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"__package__.d.ts","sourceRoot":"","sources":["../src/__package__.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,QAAQ,mCAAmC,CAAC;AACzD,eAAO,MAAM,WAAW,UAAU,CAAC;AACnC,eAAO,MAAM,aAAa,
|
|
1
|
+
{"version":3,"file":"__package__.d.ts","sourceRoot":"","sources":["../src/__package__.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,QAAQ,mCAAmC,CAAC;AACzD,eAAO,MAAM,WAAW,UAAU,CAAC;AACnC,eAAO,MAAM,aAAa,aAAa,CAAC"}
|