@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.
Files changed (64) hide show
  1. package/bin/ojscc.mjs +13 -19
  2. package/dist/index.css +2 -1
  3. package/dist/index.css.map +7 -0
  4. package/dist/index.js +24 -7999
  5. package/dist/index.js.map +7 -1
  6. package/package.json +42 -52
  7. package/src/__package__.ts +2 -2
  8. package/src/compiler.ts +34 -22
  9. package/src/cst.ts +27 -23
  10. package/src/index.ts +4 -3
  11. package/src/observable-shim.ts +2 -0
  12. package/src/parse.ts +136 -0
  13. package/src/types.ts +180 -0
  14. package/src/util.ts +6 -3
  15. package/src/writer.ts +9 -6
  16. package/types/compiler.d.ts +7 -8
  17. package/types/cst.d.ts +0 -1
  18. package/types/index.d.ts +4 -4
  19. package/types/observable-shim.d.ts +2 -0
  20. package/types/parse.d.ts +26 -0
  21. package/types/types.d.ts +165 -0
  22. package/types/util.d.ts +2 -3
  23. package/types/writer.d.ts +2 -3
  24. package/dist/index.esm.css +0 -1
  25. package/dist/index.esm.js +0 -7999
  26. package/dist/index.esm.js.map +0 -1
  27. package/dist/index.esm.min.js +0 -4
  28. package/dist/index.esm.min.js.map +0 -1
  29. package/dist/index.min.js +0 -4
  30. package/dist/index.min.js.map +0 -1
  31. package/src/__tests__/File Attachments.ts +0 -895
  32. package/src/__tests__/Introduction to Imports.ts +0 -749
  33. package/src/__tests__/Observable TimeChart.ts +0 -772
  34. package/src/__tests__/index.ts +0 -13
  35. package/src/__tests__/m1.mjs +0 -3
  36. package/src/__tests__/node.ts +0 -199
  37. package/types/__package__.d.ts +0 -4
  38. package/types/__package__.d.ts.map +0 -1
  39. package/types/__tests__/File Attachments.d.ts +0 -110
  40. package/types/__tests__/File Attachments.d.ts.map +0 -1
  41. package/types/__tests__/Introduction to Imports.d.ts +0 -120
  42. package/types/__tests__/Introduction to Imports.d.ts.map +0 -1
  43. package/types/__tests__/Observable TimeChart.d.ts +0 -111
  44. package/types/__tests__/Observable TimeChart.d.ts.map +0 -1
  45. package/types/__tests__/index.d.ts +0 -2
  46. package/types/__tests__/index.d.ts.map +0 -1
  47. package/types/__tests__/node.d.ts +0 -2
  48. package/types/__tests__/node.d.ts.map +0 -1
  49. package/types/compiler.d.ts.map +0 -1
  50. package/types/cst.d.ts.map +0 -1
  51. package/types/index.d.ts.map +0 -1
  52. package/types/util.d.ts.map +0 -1
  53. package/types/writer.d.ts.map +0 -1
  54. package/types-3.4/__package__.d.ts +0 -4
  55. package/types-3.4/__tests__/File Attachments.d.ts +0 -110
  56. package/types-3.4/__tests__/Introduction to Imports.d.ts +0 -120
  57. package/types-3.4/__tests__/Observable TimeChart.d.ts +0 -111
  58. package/types-3.4/__tests__/index.d.ts +0 -2
  59. package/types-3.4/__tests__/node.d.ts +0 -2
  60. package/types-3.4/compiler.d.ts +0 -112
  61. package/types-3.4/cst.d.ts +0 -42
  62. package/types-3.4/index.d.ts +0 -5
  63. package/types-3.4/util.d.ts +0 -30
  64. 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": "1.4.0",
3
+ "version": "3.2.0",
4
4
  "description": "hpcc-js - ObservableHQ Compiler (unoffical)",
5
- "keywords": [
6
- "observablehq",
7
- "markdown",
8
- "observable",
9
- "compiler",
10
- "interpreter",
11
- "renderer"
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
- "types/*",
32
- "types-3.4/*",
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* types *.tsbuildinfo",
37
- "compile-es6": "tsc --module es2020 --outDir ./lib-es6",
38
- "compile-es6-watch": "npm run compile-es6 -- -w",
39
- "compile-umd": "tsc --module umd --outDir ./lib-umd",
40
- "compile-umd-watch": "npm run compile-umd -- -w",
41
- "bundle": "rollup -c",
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
- "dev-start": "ws",
53
- "test-cli": "node ./bin/ojscc.mjs --version",
54
- "test-node": "mocha ./dist-test/index.mjs --reporter spec",
55
- "test": "run-s test-cli test-node",
56
- "update": "npx --yes npm-check-updates -u -t minor"
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/bundle": "^2.12.0",
65
- "@observablehq/runtime": "5.9.9",
66
- "tslib": "2.7.0"
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": "fbbef050700b0e9d76ef99714856383d95155149"
69
+ "gitHead": "658c50fd965a7744ba8db675ba6878607c44d5e2"
80
70
  }
@@ -1,3 +1,3 @@
1
1
  export const PKG_NAME = "@hpcc-js/observablehq-compiler";
2
- export const PKG_VERSION = "1.4.0";
3
- export const BUILD_VERSION = "2.107.0";
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 "@hpcc-js/observable-shim";
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
- i = inspect ? inspector(name, node.id) : undefined;
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?: string, alias?: string) {
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
- v.import(name, alias, otherModule);
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() { return globalThis.url; }
246
- return [file.name, { url: new URL(fixRelativeUrl(file.url, options.baseUrl)), mimeType: file.mime_type, toString }];
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 "@hpcc-js/observable-shim";
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.start, end: node.end - cellAst.body.start, newText });
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: acorn.Node[]) {
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 acorn.AncestorVisitors, walk);
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
- bodyStr = `import("${fixRelativeUrl(cellAst.body.source.value, baseUrl)}")`;
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 "@hpcc-js/observable-shim";
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";
@@ -0,0 +1,2 @@
1
+ export type { ohq } from "./types.ts";
2
+ export * from "./parse.ts";
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;