@hpcc-js/observablehq-compiler 1.4.0 → 3.2.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/bin/ojscc.mjs +13 -19
- package/dist/index.css +2 -1
- package/dist/index.css.map +7 -0
- package/dist/index.js +24 -7999
- package/dist/index.js.map +7 -1
- package/package.json +42 -52
- package/src/__package__.ts +2 -2
- package/src/compiler.ts +34 -22
- package/src/cst.ts +27 -23
- package/src/index.ts +4 -3
- package/src/observable-shim.ts +2 -0
- package/src/parse.ts +136 -0
- package/src/types.ts +180 -0
- package/src/util.ts +6 -3
- package/src/writer.ts +9 -6
- package/types/compiler.d.ts +7 -8
- package/types/cst.d.ts +0 -1
- package/types/index.d.ts +4 -4
- package/types/observable-shim.d.ts +2 -0
- package/types/parse.d.ts +26 -0
- package/types/types.d.ts +165 -0
- package/types/util.d.ts +2 -3
- package/types/writer.d.ts +2 -3
- package/dist/index.esm.css +0 -1
- package/dist/index.esm.js +0 -7999
- package/dist/index.esm.js.map +0 -1
- package/dist/index.esm.min.js +0 -4
- package/dist/index.esm.min.js.map +0 -1
- package/dist/index.min.js +0 -4
- package/dist/index.min.js.map +0 -1
- package/src/__tests__/File Attachments.ts +0 -895
- package/src/__tests__/Introduction to Imports.ts +0 -749
- package/src/__tests__/Observable TimeChart.ts +0 -772
- package/src/__tests__/index.ts +0 -13
- package/src/__tests__/m1.mjs +0 -3
- package/src/__tests__/node.ts +0 -199
- package/types/__package__.d.ts +0 -4
- package/types/__package__.d.ts.map +0 -1
- package/types/__tests__/File Attachments.d.ts +0 -110
- package/types/__tests__/File Attachments.d.ts.map +0 -1
- package/types/__tests__/Introduction to Imports.d.ts +0 -120
- package/types/__tests__/Introduction to Imports.d.ts.map +0 -1
- package/types/__tests__/Observable TimeChart.d.ts +0 -111
- package/types/__tests__/Observable TimeChart.d.ts.map +0 -1
- package/types/__tests__/index.d.ts +0 -2
- package/types/__tests__/index.d.ts.map +0 -1
- package/types/__tests__/node.d.ts +0 -2
- package/types/__tests__/node.d.ts.map +0 -1
- package/types/compiler.d.ts.map +0 -1
- package/types/cst.d.ts.map +0 -1
- package/types/index.d.ts.map +0 -1
- package/types/util.d.ts.map +0 -1
- package/types/writer.d.ts.map +0 -1
- package/types-3.4/__package__.d.ts +0 -4
- package/types-3.4/__tests__/File Attachments.d.ts +0 -110
- package/types-3.4/__tests__/Introduction to Imports.d.ts +0 -120
- package/types-3.4/__tests__/Observable TimeChart.d.ts +0 -111
- package/types-3.4/__tests__/index.d.ts +0 -2
- package/types-3.4/__tests__/node.d.ts +0 -2
- package/types-3.4/compiler.d.ts +0 -112
- package/types-3.4/cst.d.ts +0 -42
- package/types-3.4/index.d.ts +0 -5
- package/types-3.4/util.d.ts +0 -30
- package/types-3.4/writer.d.ts +0 -19
package/package.json
CHANGED
|
@@ -1,74 +1,64 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hpcc-js/observablehq-compiler",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "3.2.0",
|
|
4
4
|
"description": "hpcc-js - ObservableHQ Compiler (unoffical)",
|
|
5
|
-
"
|
|
6
|
-
|
|
7
|
-
"
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
"
|
|
12
|
-
],
|
|
13
|
-
"main": "dist/index.js",
|
|
14
|
-
"module": "dist/index.esm.js",
|
|
15
|
-
"browser": "dist/index.js",
|
|
16
|
-
"unpkg": "dist/index.min.js",
|
|
17
|
-
"jsdelivr": "dist/index.min.js",
|
|
18
|
-
"types": "types/index.d.ts",
|
|
19
|
-
"typesVersions": {
|
|
20
|
-
"<3.8": {
|
|
21
|
-
"*": [
|
|
22
|
-
"types-3.4/index.d.ts"
|
|
23
|
-
]
|
|
24
|
-
}
|
|
25
|
-
},
|
|
26
|
-
"bin": {
|
|
27
|
-
"ojscc": "bin/ojscc.mjs"
|
|
5
|
+
"type": "module",
|
|
6
|
+
"exports": {
|
|
7
|
+
".": {
|
|
8
|
+
"types": "./types/index.d.ts",
|
|
9
|
+
"default": "./dist/index.js"
|
|
10
|
+
},
|
|
11
|
+
"./dist/*": "./dist/*"
|
|
28
12
|
},
|
|
13
|
+
"main": "./dist/index.js",
|
|
14
|
+
"types": "./types/index.d.ts",
|
|
29
15
|
"files": [
|
|
30
16
|
"dist/*",
|
|
31
|
-
"
|
|
32
|
-
"types
|
|
33
|
-
"src/*"
|
|
17
|
+
"src/*",
|
|
18
|
+
"types/*"
|
|
34
19
|
],
|
|
20
|
+
"bin": {
|
|
21
|
+
"ojscc": "bin/ojscc.mjs"
|
|
22
|
+
},
|
|
35
23
|
"scripts": {
|
|
36
|
-
"clean": "rimraf --glob lib* dist
|
|
37
|
-
"
|
|
38
|
-
"
|
|
39
|
-
"
|
|
40
|
-
"
|
|
41
|
-
"
|
|
42
|
-
"bundle-watch": "npm run bundle -- -w",
|
|
43
|
-
"minimize-index": "terser dist/index.js -c -m --source-map \"content='dist/index.js.map',url='index.min.js.map'\" -o dist/index.min.js",
|
|
44
|
-
"minimize-index-es6": "terser dist/index.esm.js -c -m --source-map \"content='dist/index.esm.js.map',url='index.esm.min.js.map'\" -o dist/index.esm.min.js",
|
|
45
|
-
"minimize": "run-p minimize-index minimize-index-es6",
|
|
46
|
-
"gen-legacy-types": "downlevel-dts ./types ./types-3.4",
|
|
47
|
-
"build": "npm run compile-es6 && npm run bundle",
|
|
48
|
-
"watch": "npm-run-all compile-es6 -p compile-es6-watch bundle-watch",
|
|
49
|
-
"stamp": "node ../../node_modules/@hpcc-js/bundle/src/stamp.js",
|
|
24
|
+
"clean": "rimraf --glob lib* types dist dist-test *.tsbuildinfo .turbo",
|
|
25
|
+
"bundle": "node esbuild.js",
|
|
26
|
+
"bundle-watch": "npm run bundle -- --development --watch",
|
|
27
|
+
"gen-types": "tsc --project tsconfig.json",
|
|
28
|
+
"gen-types-watch": "npm run gen-types -- --watch",
|
|
29
|
+
"build": "run-p gen-types bundle",
|
|
50
30
|
"lint": "eslint ./src",
|
|
31
|
+
"lint-fix": "eslint --fix src/**/*.ts",
|
|
51
32
|
"docs": "typedoc --options tdoptions.json .",
|
|
52
|
-
"
|
|
53
|
-
"test-
|
|
54
|
-
"test-
|
|
55
|
-
"test": "
|
|
56
|
-
"
|
|
33
|
+
"test-browser": "vitest run --project browser",
|
|
34
|
+
"test-node": "vitest run --project node",
|
|
35
|
+
"test-both": "vitest run",
|
|
36
|
+
"test-bin": "node ./bin/ojscc.mjs --version",
|
|
37
|
+
"test": "run-p test-both test-bin",
|
|
38
|
+
"coverage": "vitest run --coverage",
|
|
39
|
+
"update": "npx -y npm-check-updates -u -t minor",
|
|
40
|
+
"update-major": "npx -y npm-check-updates -u"
|
|
57
41
|
},
|
|
58
42
|
"dependencies": {
|
|
59
|
-
"@hpcc-js/observable-shim": "^1.0.0",
|
|
60
|
-
"node-fetch": "3.3.2",
|
|
61
43
|
"yargs": "17.7.2"
|
|
62
44
|
},
|
|
63
45
|
"devDependencies": {
|
|
64
|
-
"@hpcc-js/
|
|
65
|
-
"@observablehq/
|
|
66
|
-
"
|
|
46
|
+
"@hpcc-js/esbuild-plugins": "^1.3.0",
|
|
47
|
+
"@observablehq/parser": "6.1.0",
|
|
48
|
+
"@observablehq/runtime": "5.9.9"
|
|
67
49
|
},
|
|
68
50
|
"repository": {
|
|
69
51
|
"type": "git",
|
|
70
52
|
"url": "git+https://github.com/hpcc-systems/Visualization.git"
|
|
71
53
|
},
|
|
54
|
+
"keywords": [
|
|
55
|
+
"observablehq",
|
|
56
|
+
"markdown",
|
|
57
|
+
"observable",
|
|
58
|
+
"compiler",
|
|
59
|
+
"interpreter",
|
|
60
|
+
"renderer"
|
|
61
|
+
],
|
|
72
62
|
"author": "Gordon Smith <gordonjsmith@gmail.com>",
|
|
73
63
|
"contributors": [],
|
|
74
64
|
"license": "Apache-2.0",
|
|
@@ -76,5 +66,5 @@
|
|
|
76
66
|
"url": "https://github.com/hpcc-systems/Visualization/issues"
|
|
77
67
|
},
|
|
78
68
|
"homepage": "https://github.com/hpcc-systems/Visualization/tree/trunk/packages/observablehq-compiler",
|
|
79
|
-
"gitHead": "
|
|
69
|
+
"gitHead": "658c50fd965a7744ba8db675ba6878607c44d5e2"
|
|
80
70
|
}
|
package/src/__package__.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
export const PKG_NAME = "@hpcc-js/observablehq-compiler";
|
|
2
|
-
export const PKG_VERSION = "
|
|
3
|
-
export const BUILD_VERSION = "2.
|
|
2
|
+
export const PKG_VERSION = "3.2.0";
|
|
3
|
+
export const BUILD_VERSION = "3.2.0";
|
package/src/compiler.ts
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
|
-
import { ohq, splitModule } from "
|
|
2
|
-
import { parseCell, ParsedImportCell } from "./cst";
|
|
3
|
-
import { Writer } from "./writer";
|
|
4
|
-
import { fixRelativeUrl, isRelativePath, encodeBacktick, fetchEx, obfuscatedImport, ojs2notebook, omd2notebook } from "./util";
|
|
1
|
+
import { ohq, splitModule } from "./observable-shim.ts";
|
|
2
|
+
import { parseCell, ParsedImportCell } from "./cst.ts";
|
|
3
|
+
import { Writer } from "./writer.ts";
|
|
4
|
+
import { fixRelativeUrl, isRelativePath, encodeBacktick, fetchEx, obfuscatedImport, ojs2notebook, omd2notebook } from "./util.ts";
|
|
5
5
|
|
|
6
6
|
// Inspector Factory ---
|
|
7
7
|
export type InspectorFactoryEx = (name: string | undefined, id: string | number) => Inspector;
|
|
8
8
|
|
|
9
9
|
export interface Inspector {
|
|
10
10
|
_node?: HTMLDivElement;
|
|
11
|
-
pending();
|
|
12
|
-
fulfilled(value);
|
|
13
|
-
rejected(error);
|
|
11
|
+
pending(): void;
|
|
12
|
+
fulfilled(value: any): void;
|
|
13
|
+
rejected(error: Error): void;
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
// Module ---
|
|
@@ -31,6 +31,9 @@ async function importFile(relativePath: string, baseUrl: string) {
|
|
|
31
31
|
notebook = ojs2notebook(content);
|
|
32
32
|
} else if (relativePath.endsWith(".omd")) {
|
|
33
33
|
notebook = omd2notebook(content);
|
|
34
|
+
} else {
|
|
35
|
+
console.warn(`Unknown file type: ${relativePath}, assuming .ojsnb`);
|
|
36
|
+
notebook = JSON.parse(content);
|
|
34
37
|
}
|
|
35
38
|
const retVal: ImportDefine = compile(notebook, { baseUrl }) as any;
|
|
36
39
|
retVal.delete = () => { };
|
|
@@ -44,7 +47,7 @@ async function importFile(relativePath: string, baseUrl: string) {
|
|
|
44
47
|
async function importCompiledNotebook(partial: string) {
|
|
45
48
|
const url = `https://api.observablehq.com/${partial[0] === "@" ? partial : `d/${partial}`}.js?v=3`;
|
|
46
49
|
let impMod = {
|
|
47
|
-
default: function (runtime: ohq.Runtime, inspector?: InspectorFactoryEx): ohq.Module {
|
|
50
|
+
default: function (runtime: ohq.Runtime, inspector?: InspectorFactoryEx): ohq.Module | undefined {
|
|
48
51
|
return undefined;
|
|
49
52
|
} as any
|
|
50
53
|
};
|
|
@@ -80,7 +83,7 @@ async function importNotebook(partial: string) {
|
|
|
80
83
|
|
|
81
84
|
async function createModule(node: ohq.Node, parsed: ParsedImportCell, text: string, { baseUrl, importMode }: CompileOptions) {
|
|
82
85
|
const otherModule = isRelativePath(parsed.src) ?
|
|
83
|
-
await importFile(parsed.src, baseUrl) :
|
|
86
|
+
await importFile(parsed.src, baseUrl ?? "") :
|
|
84
87
|
importMode === "recursive" ?
|
|
85
88
|
await importNotebook(parsed.src) :
|
|
86
89
|
await importCompiledNotebook(parsed.src);
|
|
@@ -123,11 +126,13 @@ type ModuleFunc = Awaited<ReturnType<typeof createModule>>;
|
|
|
123
126
|
// Variable ---
|
|
124
127
|
function createVariable(node: ohq.Node, inspect: boolean, name?: string, inputs?: string[], definition?: any, inline = false) {
|
|
125
128
|
|
|
126
|
-
let i: ohq.Inspector;
|
|
127
|
-
let v: ohq.Variable;
|
|
129
|
+
let i: ohq.Inspector | undefined;
|
|
130
|
+
let v: ohq.Variable | undefined;
|
|
128
131
|
|
|
129
132
|
const retVal = (module: ohq.Module, inspector?: InspectorFactoryEx) => {
|
|
130
|
-
|
|
133
|
+
if (inspect && inspector) {
|
|
134
|
+
i = inspector(name, node.id);
|
|
135
|
+
}
|
|
131
136
|
v = module.variable(i);
|
|
132
137
|
if (arguments.length > 1) {
|
|
133
138
|
try {
|
|
@@ -137,9 +142,9 @@ function createVariable(node: ohq.Node, inspect: boolean, name?: string, inputs?
|
|
|
137
142
|
}
|
|
138
143
|
}
|
|
139
144
|
if (node.pinned) {
|
|
140
|
-
v = module.variable(inspector(name, node.id));
|
|
145
|
+
v = inspector ? module.variable(inspector(name, node.id)) : module.variable();
|
|
141
146
|
try {
|
|
142
|
-
v.define(undefined, ["md"], md => {
|
|
147
|
+
v.define(undefined, ["md"], (md: any) => {
|
|
143
148
|
return md`\`\`\`js
|
|
144
149
|
${node.value}
|
|
145
150
|
\`\`\``;
|
|
@@ -174,13 +179,17 @@ ${node.value}
|
|
|
174
179
|
}
|
|
175
180
|
type VariableFunc = ReturnType<typeof createVariable>;
|
|
176
181
|
|
|
177
|
-
function createImportVariable(name
|
|
182
|
+
function createImportVariable(name: string, alias?: string) {
|
|
178
183
|
|
|
179
184
|
let v: ohq.Variable;
|
|
180
185
|
|
|
181
186
|
const retVal = (main: ohq.Module, otherModule: ohq.Module) => {
|
|
182
187
|
v = main.variable();
|
|
183
|
-
|
|
188
|
+
if (alias === undefined) {
|
|
189
|
+
v.import(name, otherModule);
|
|
190
|
+
} else {
|
|
191
|
+
v.import(name, alias, otherModule);
|
|
192
|
+
}
|
|
184
193
|
};
|
|
185
194
|
|
|
186
195
|
retVal.delete = () => {
|
|
@@ -198,7 +207,7 @@ async function createCell(node: ohq.Node, options: CompileOptions) {
|
|
|
198
207
|
const text = node.mode && node.mode !== "js" ? `${node.mode}\`${encodeBacktick(node.value)}\`` : node.value;
|
|
199
208
|
const parsedModule = splitModule(text);
|
|
200
209
|
for (const cell of parsedModule) {
|
|
201
|
-
const parsed = parseCell(cell.text, options.baseUrl);
|
|
210
|
+
const parsed = parseCell(cell.text, options.baseUrl ?? "");
|
|
202
211
|
switch (parsed.type) {
|
|
203
212
|
case "import":
|
|
204
213
|
modules.push(await createModule(node, parsed, cell.text, options));
|
|
@@ -217,8 +226,8 @@ async function createCell(node: ohq.Node, options: CompileOptions) {
|
|
|
217
226
|
break;
|
|
218
227
|
}
|
|
219
228
|
}
|
|
220
|
-
} catch (e) {
|
|
221
|
-
variables.push(createVariable(node, true, undefined, [], e.message));
|
|
229
|
+
} catch (e: any) {
|
|
230
|
+
variables.push(createVariable(node, true, undefined, [], e.message ?? "Unkown error"));
|
|
222
231
|
}
|
|
223
232
|
|
|
224
233
|
const retVal = (runtime: ohq.Runtime, main: ohq.Module, inspector?: InspectorFactoryEx) => {
|
|
@@ -242,8 +251,11 @@ export type CellFunc = Awaited<ReturnType<typeof createCell>>;
|
|
|
242
251
|
|
|
243
252
|
// File ---
|
|
244
253
|
function createFile(file: ohq.File, options: CompileOptions): [string, any] {
|
|
245
|
-
function toString() {
|
|
246
|
-
|
|
254
|
+
function toString() {
|
|
255
|
+
// TODO Double check url should not be URL?
|
|
256
|
+
return (globalThis as any).url ?? "";
|
|
257
|
+
}
|
|
258
|
+
return [file.name, { url: new URL(fixRelativeUrl(file.url, options.baseUrl ?? "")), mimeType: file.mime_type, toString }];
|
|
247
259
|
}
|
|
248
260
|
type FileFunc = ReturnType<typeof createFile>;
|
|
249
261
|
|
|
@@ -277,7 +289,7 @@ export function notebook(_files: ohq.File[] = [], _cells: CellFunc[] = [], { bas
|
|
|
277
289
|
cells.set(cell.id, cell);
|
|
278
290
|
return cell;
|
|
279
291
|
};
|
|
280
|
-
retVal.get = (id: string | number): CellFunc => {
|
|
292
|
+
retVal.get = (id: string | number): CellFunc | undefined => {
|
|
281
293
|
return cells.get(id);
|
|
282
294
|
};
|
|
283
295
|
retVal.delete = (id: string | number): boolean => {
|
package/src/cst.ts
CHANGED
|
@@ -1,20 +1,18 @@
|
|
|
1
|
-
import { parseCell as ohqParseCell } from "
|
|
2
|
-
import { acorn, walk } from "@observablehq/parser";
|
|
3
|
-
import { ancestor } from "acorn-walk";
|
|
1
|
+
import { ancestor, parseCell as ohqParseCell, Cell, Node, walk, AncestorVisitors } from "./observable-shim.ts";
|
|
4
2
|
|
|
5
|
-
import { fixRelativeUrl, createFunction, Refs } from "./util";
|
|
3
|
+
import { fixRelativeUrl, createFunction, Refs } from "./util.ts";
|
|
6
4
|
|
|
7
|
-
function calcRefs(cellAst, cellStr): Refs {
|
|
5
|
+
function calcRefs(cellAst: Cell, cellStr: string): Refs {
|
|
8
6
|
if (cellAst.references === undefined) return { inputs: [], args: [], patches: [] };
|
|
9
7
|
|
|
10
|
-
const dedup = {};
|
|
11
|
-
cellAst.references.forEach(r => dedup[cellStr.substring(r.start, r.end)] = true);
|
|
8
|
+
const dedup: { [id: string]: boolean } = {};
|
|
9
|
+
cellAst.references.forEach((r: any) => dedup[cellStr.substring(r.start, r.end)] = true);
|
|
12
10
|
const retVal: Refs = {
|
|
13
11
|
inputs: Object.keys(dedup),
|
|
14
12
|
args: Object.keys(dedup).map(r => r.split(" ").join("_")),
|
|
15
13
|
patches: []
|
|
16
14
|
};
|
|
17
|
-
const pushPatch = (node, newText) => retVal.patches.push({ start: node.start - cellAst.body
|
|
15
|
+
const pushPatch = (node: Node, newText: string) => retVal.patches.push({ start: node.start - (cellAst.body?.start ?? 0), end: node.end - (cellAst.body?.start ?? 0), newText });
|
|
18
16
|
if (cellAst.body) {
|
|
19
17
|
ancestor(cellAst.body, {
|
|
20
18
|
Identifier(node) {
|
|
@@ -22,23 +20,23 @@ function calcRefs(cellAst, cellStr): Refs {
|
|
|
22
20
|
if (dedup[value]) {
|
|
23
21
|
}
|
|
24
22
|
},
|
|
25
|
-
MutableExpression(node) {
|
|
23
|
+
MutableExpression(node: Node) {
|
|
26
24
|
const value = cellStr.substring(node.start, node.end);
|
|
27
25
|
const newText = value.split(" ").join("_") + ".value";
|
|
28
26
|
pushPatch(node, newText);
|
|
29
27
|
},
|
|
30
|
-
ViewExpression(node) {
|
|
28
|
+
ViewExpression(node: Node) {
|
|
31
29
|
const value = cellStr.substring(node.start, node.end);
|
|
32
30
|
const newText = value.split(" ").join("_");
|
|
33
31
|
pushPatch(node, newText);
|
|
34
32
|
},
|
|
35
|
-
ThisExpression(node, ancestors:
|
|
33
|
+
ThisExpression(node: Node, ancestors: Node[]) {
|
|
36
34
|
const value = cellStr.substring(node.start, node.end);
|
|
37
35
|
if (value === "this" && !ancestors.find(n => n.type === "FunctionExpression")) {
|
|
38
36
|
pushPatch(node, "((this === globalThis || this === globalThis.window)? undefined : this?.valueOf())");
|
|
39
37
|
}
|
|
40
38
|
}
|
|
41
|
-
} as
|
|
39
|
+
} as AncestorVisitors<any>, walk);
|
|
42
40
|
}
|
|
43
41
|
return retVal;
|
|
44
42
|
}
|
|
@@ -54,18 +52,18 @@ export interface ParsedImportCell extends ParsedCell {
|
|
|
54
52
|
injections: { name: string, alias: string }[];
|
|
55
53
|
}
|
|
56
54
|
|
|
57
|
-
function parseImportDeclaration(cellAst): ParsedImportCell {
|
|
55
|
+
function parseImportDeclaration(cellAst: any): ParsedImportCell {
|
|
58
56
|
return {
|
|
59
57
|
type: "import",
|
|
60
58
|
src: cellAst.body.source.value,
|
|
61
|
-
specifiers: cellAst.body.specifiers?.map(spec => {
|
|
59
|
+
specifiers: cellAst.body.specifiers?.map((spec: any) => {
|
|
62
60
|
return {
|
|
63
61
|
view: spec.view,
|
|
64
62
|
name: spec.imported.name,
|
|
65
63
|
alias: (spec.local?.name && spec.imported.name !== spec.local.name) ? spec.local.name : spec.imported.name
|
|
66
64
|
};
|
|
67
65
|
}) ?? [],
|
|
68
|
-
injections: cellAst.body.injections?.map(inj => {
|
|
66
|
+
injections: cellAst.body.injections?.map((inj: any) => {
|
|
69
67
|
return {
|
|
70
68
|
name: inj.imported.name,
|
|
71
69
|
alias: inj.local?.name ?? inj.imported.name
|
|
@@ -87,7 +85,7 @@ export interface ParsedViewCell extends ParsedCell {
|
|
|
87
85
|
variableValue: ParsedVariable;
|
|
88
86
|
}
|
|
89
87
|
|
|
90
|
-
function parseViewExpression(cellStr: string, cellAst, refs: Refs, bodyStr?: string): ParsedViewCell {
|
|
88
|
+
function parseViewExpression(cellStr: string, cellAst: any, refs: Refs, bodyStr?: string): ParsedViewCell {
|
|
91
89
|
const id = cellAst.id && cellStr.substring(cellAst.id.start, cellAst.id.end);
|
|
92
90
|
return {
|
|
93
91
|
type: "viewof",
|
|
@@ -101,7 +99,7 @@ function parseViewExpression(cellStr: string, cellAst, refs: Refs, bodyStr?: str
|
|
|
101
99
|
type: "variable",
|
|
102
100
|
id: cellAst?.id?.id?.name,
|
|
103
101
|
inputs: ["Generators", id],
|
|
104
|
-
func: (G, _) => G.input(_)
|
|
102
|
+
func: (G: any, _: any) => G.input(_)
|
|
105
103
|
}
|
|
106
104
|
};
|
|
107
105
|
}
|
|
@@ -113,7 +111,7 @@ interface ParsedMutableCell extends ParsedCell {
|
|
|
113
111
|
variableValue: ParsedVariable;
|
|
114
112
|
}
|
|
115
113
|
|
|
116
|
-
function parseMutableExpression(cellStr: string, cellAst, refs: Refs, bodyStr?: string): ParsedMutableCell {
|
|
114
|
+
function parseMutableExpression(cellStr: string, cellAst: any, refs: Refs, bodyStr?: string): ParsedMutableCell {
|
|
117
115
|
const id = cellAst.id && cellStr.substring(cellAst.id.start, cellAst.id.end);
|
|
118
116
|
const initialValueId = cellAst?.id?.id?.name;
|
|
119
117
|
const initialId = `initial ${initialValueId}`;
|
|
@@ -129,13 +127,13 @@ function parseMutableExpression(cellStr: string, cellAst, refs: Refs, bodyStr?:
|
|
|
129
127
|
type: "variable",
|
|
130
128
|
id,
|
|
131
129
|
inputs: ["Mutable", initialId],
|
|
132
|
-
func: (M, _) => new M(_)
|
|
130
|
+
func: (M: any, _: any) => new M(_)
|
|
133
131
|
},
|
|
134
132
|
variableValue: {
|
|
135
133
|
type: "variable",
|
|
136
134
|
id: initialValueId,
|
|
137
135
|
inputs: [id],
|
|
138
|
-
func: _ => _.generator
|
|
136
|
+
func: (_: any) => _.generator
|
|
139
137
|
}
|
|
140
138
|
};
|
|
141
139
|
}
|
|
@@ -147,7 +145,7 @@ interface ParsedVariableCell extends ParsedCell {
|
|
|
147
145
|
func: any,
|
|
148
146
|
}
|
|
149
147
|
|
|
150
|
-
function parseVariableExpression(cellStr: string, cellAst, refs: Refs, bodyStr?: string): ParsedVariableCell {
|
|
148
|
+
function parseVariableExpression(cellStr: string, cellAst: any, refs: Refs, bodyStr?: string): ParsedVariableCell {
|
|
151
149
|
return {
|
|
152
150
|
type: "variable",
|
|
153
151
|
id: cellAst.id && cellStr.substring(cellAst.id?.start, cellAst.id?.end),
|
|
@@ -163,10 +161,15 @@ export function parseCell(cellStr: string, baseUrl: string): ParsedImportCell |
|
|
|
163
161
|
case "ImportDeclaration":
|
|
164
162
|
return parseImportDeclaration(cellAst);
|
|
165
163
|
case "ImportExpression":
|
|
166
|
-
|
|
164
|
+
switch (cellAst.body.source.type) {
|
|
165
|
+
case "Literal":
|
|
166
|
+
bodyStr = `import("${fixRelativeUrl("" + cellAst.body.source.value, baseUrl)}")`;
|
|
167
|
+
break;
|
|
168
|
+
default:
|
|
169
|
+
console.error("Unexpected import value");
|
|
170
|
+
}
|
|
167
171
|
}
|
|
168
172
|
const refs = calcRefs(cellAst, cellStr);
|
|
169
|
-
|
|
170
173
|
switch (cellAst.id?.type) {
|
|
171
174
|
case "ViewExpression":
|
|
172
175
|
return parseViewExpression(cellStr, cellAst, refs, bodyStr);
|
|
@@ -176,3 +179,4 @@ export function parseCell(cellStr: string, baseUrl: string): ParsedImportCell |
|
|
|
176
179
|
return parseVariableExpression(cellStr, cellAst, refs, bodyStr);
|
|
177
180
|
}
|
|
178
181
|
}
|
|
182
|
+
|
package/src/index.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
export type { ohq } from "
|
|
1
|
+
export type { ohq } from "./observable-shim.ts";
|
|
2
2
|
|
|
3
|
-
export * from "./compiler";
|
|
4
|
-
export { ojs2notebook, omd2notebook, download } from "./util";
|
|
3
|
+
export * from "./compiler.ts";
|
|
4
|
+
export { ojs2notebook, omd2notebook, download } from "./util.ts";
|
|
5
|
+
export * from "./writer.ts";
|
|
5
6
|
|
|
6
7
|
import "../src/index.css";
|
package/src/parse.ts
ADDED
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
// Compare with ../../../node_modules/@observablehq/parser/src/parse.js
|
|
2
|
+
import { getLineInfo, tokTypes, Statement, ModuleDeclaration, Expression as ExpressionBase, Node } from "acorn";
|
|
3
|
+
import { ancestor, RecursiveVisitors, AncestorVisitors } from "acorn-walk";
|
|
4
|
+
import { CellParser, parseCell as ohqParseCell, walk as ohqWalk } from "@observablehq/parser";
|
|
5
|
+
import defaultGlobals from "../../../node_modules/@observablehq/parser/src/globals.js";
|
|
6
|
+
import findReferences from "../../../node_modules/@observablehq/parser/src/references.js";
|
|
7
|
+
import findFeatures from "../../../node_modules/@observablehq/parser/src/features.js";
|
|
8
|
+
|
|
9
|
+
export interface MutableExpression extends Node {
|
|
10
|
+
type: "MutableExpression"
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export interface ViewExpression extends Node {
|
|
14
|
+
type: "ViewExpression"
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export type Expression = ExpressionBase | MutableExpression | ViewExpression;
|
|
18
|
+
|
|
19
|
+
// Find references.
|
|
20
|
+
// Check for illegal references to arguments.
|
|
21
|
+
// Check for illegal assignments to global references.
|
|
22
|
+
function parseReferences(cell, input, globals = defaultGlobals) {
|
|
23
|
+
if (!cell.body) {
|
|
24
|
+
cell.references = [];
|
|
25
|
+
} else if (cell.body.type === "ImportDeclaration") {
|
|
26
|
+
// This is correct?!?
|
|
27
|
+
cell.references = cell.body.specifiers
|
|
28
|
+
? cell.body.specifiers.map(i => i.imported)
|
|
29
|
+
: [];
|
|
30
|
+
} else {
|
|
31
|
+
try {
|
|
32
|
+
cell.references = findReferences(cell, globals);
|
|
33
|
+
} catch (error: any) {
|
|
34
|
+
if (error.node) {
|
|
35
|
+
const loc = getLineInfo(input, error.node.start);
|
|
36
|
+
error.message += ` (${loc.line}:${loc.column})`;
|
|
37
|
+
error.pos = error.node.start;
|
|
38
|
+
error.loc = loc;
|
|
39
|
+
delete error.node;
|
|
40
|
+
}
|
|
41
|
+
throw error;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return cell;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// Find features: file attachments, secrets, database clients.
|
|
48
|
+
// Check for illegal references to arguments.
|
|
49
|
+
// Check for illegal assignments to global references.
|
|
50
|
+
function parseFeatures(cell, input) {
|
|
51
|
+
if (cell.body && cell.body.type !== "ImportDeclaration") {
|
|
52
|
+
try {
|
|
53
|
+
cell.fileAttachments = findFeatures(cell, "FileAttachment");
|
|
54
|
+
cell.databaseClients = findFeatures(cell, "DatabaseClient");
|
|
55
|
+
cell.secrets = findFeatures(cell, "Secret");
|
|
56
|
+
} catch (error: any) {
|
|
57
|
+
if (error.node) {
|
|
58
|
+
const loc = getLineInfo(input, error.node.start);
|
|
59
|
+
error.message += ` (${loc.line}:${loc.column})`;
|
|
60
|
+
error.pos = error.node.start;
|
|
61
|
+
error.loc = loc;
|
|
62
|
+
delete error.node;
|
|
63
|
+
}
|
|
64
|
+
throw error;
|
|
65
|
+
}
|
|
66
|
+
} else {
|
|
67
|
+
cell.fileAttachments = new Map();
|
|
68
|
+
cell.databaseClients = new Map();
|
|
69
|
+
cell.secrets = new Map();
|
|
70
|
+
}
|
|
71
|
+
return cell;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
class ModuleParser extends CellParser {
|
|
75
|
+
|
|
76
|
+
parseTopLevel(node: { cells?: Cell[] }) {
|
|
77
|
+
if (!node.cells) node.cells = [];
|
|
78
|
+
// @ts-ignore
|
|
79
|
+
while (this.type !== tokTypes.eof) {
|
|
80
|
+
// @ts-ignore
|
|
81
|
+
const cell: Cell = this.parseCell(this.startNode());
|
|
82
|
+
// @ts-ignore
|
|
83
|
+
cell.input = this.input;
|
|
84
|
+
node.cells.push(cell);
|
|
85
|
+
}
|
|
86
|
+
// @ts-ignore
|
|
87
|
+
this.next();
|
|
88
|
+
// @ts-ignore
|
|
89
|
+
return this.finishNode(node, "Program");
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// @ts-ignore
|
|
94
|
+
export function parseModule(input, { globals }: { globals: any } = {}) {
|
|
95
|
+
// @ts-ignore
|
|
96
|
+
const program = ModuleParser.parse(input, { ecmaVersion: 2020 });
|
|
97
|
+
for (const cell of program.cells) {
|
|
98
|
+
parseReferences(cell, input, globals);
|
|
99
|
+
parseFeatures(cell, input);
|
|
100
|
+
}
|
|
101
|
+
return program;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
export interface Cell extends Node {
|
|
105
|
+
type: "Cell";
|
|
106
|
+
id: Expression;
|
|
107
|
+
text: string;
|
|
108
|
+
body?: Statement | ModuleDeclaration | Expression;
|
|
109
|
+
references: unknown[];
|
|
110
|
+
async: boolean;
|
|
111
|
+
generator: boolean;
|
|
112
|
+
strict: boolean;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
export function splitModule(input: string): Cell[] {
|
|
116
|
+
return (ModuleParser as any)
|
|
117
|
+
.parse(input, { ecmaVersion: "latest" })
|
|
118
|
+
.cells.map((cell: any) => ({
|
|
119
|
+
type: "Cell",
|
|
120
|
+
text: input.substring(cell.start, cell.end),
|
|
121
|
+
start: cell.start,
|
|
122
|
+
end: cell.end
|
|
123
|
+
}));
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
export {
|
|
127
|
+
Node,
|
|
128
|
+
ancestor,
|
|
129
|
+
AncestorVisitors
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
export function parseCell(input: string): Cell {
|
|
133
|
+
return ohqParseCell(input);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
export const walk: RecursiveVisitors<any> = ohqWalk;
|