@hpcc-js/observablehq-compiler 1.5.0 → 1.5.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/src/index.ts CHANGED
@@ -1,6 +1,6 @@
1
- export type { ohq } from "@hpcc-js/observable-shim";
2
-
3
- export * from "./compiler";
4
- export { ojs2notebook, omd2notebook, download } from "./util";
5
-
6
- import "../src/index.css";
1
+ export type { ohq } from "@hpcc-js/observable-shim";
2
+
3
+ export * from "./compiler";
4
+ export { ojs2notebook, omd2notebook, download } from "./util";
5
+
6
+ import "../src/index.css";
package/src/util.md CHANGED
@@ -1,113 +1,113 @@
1
- # Utilities
2
-
3
- Various utilities and helpers.
4
-
5
- ---
6
-
7
- <a name="download" href="#download">#</a> **download**(_impUrl_) => Promise\<ohq.Module\> · [<>](https://github.com/hpcc-systems/Visualization/blob/trunk/packages/observablehq/compiler/src/util.ts "Source")
8
-
9
- * _impUrl_: Full url to Obaservable HQ notebook as a string.
10
- * _returns_: Returns a Promise of a notebook (a JSON object).
11
-
12
- Downloads a notebook directly from [Observable HQ](https://observablehq.com/) as a JSON object. The following example downloads the [@observablehq/plot](https://observablehq.com/@observablehq/plot) notebook as JSON:
13
-
14
- <ClientOnly>
15
- <hpcc-vitepress style="width:100%;height:600px">
16
- <hpcc-codemirror id="placeholder" mode="json" theme="dark" style="width:100%;height:100%">
17
- </hpcc-codemirror>
18
- <script type="module">
19
- import "@hpcc-js/wc-editor";
20
- import { download } from "@hpcc-js/observablehq-compiler";
21
-
22
- const notebook = await download("https://observablehq.com/@observablehq/plot");
23
- const placeholder = document.getElementById("placeholder");
24
- placeholder.text = JSON.stringify(notebook, undefined, 4);
25
- </script>
26
- </hpcc-vitepress>
27
- </ClientOnly>
28
-
29
- ---
30
-
31
- <a name="ojs2notebook" href="#ojs2notebook">#</a> **ojs2notebook**(_ojs_) => ohq.Module · [<>](https://github.com/hpcc-systems/Visualization/blob/trunk/packages/observablehq/compiler/src/util.ts "Source")
32
-
33
- * _ojs_: String containing Observable JavaScript.
34
- * _returns_: Returns the notebook as a JSON object.
35
-
36
- Transforms Observable JavaScript to a JSON notebook.
37
-
38
- <ClientOnly>
39
- <hpcc-vitepress style="width:100%;height:600px">
40
- <hpcc-codemirror id="placeholder" mode="json" theme="dark" style="width:100%;height:100%">
41
- </hpcc-codemirror>
42
- <script type="module">
43
- import "@hpcc-js/wc-editor";
44
- import { ojs2notebook } from "@hpcc-js/observablehq-compiler";
45
-
46
- const notebook = ojs2notebook(`
47
- md\`# Simple Notebook\`
48
- a = 1
49
- b = 2
50
- c = a + b
51
- d = {
52
- yield 1;
53
- yield 2;
54
- yield 3;
55
- }
56
-
57
- viewof e = {
58
- let output = {};
59
- let listeners = [];
60
- output.value = 10;
61
- output.addEventListener = (listener) => listeners.push(listener);;
62
- output.removeEventListener = (listener) => {
63
- listeners = listeners.filter(l => l !== listener);
64
- };
65
- return output;
66
- }
67
- `);
68
- const placeholder = document.getElementById("placeholder");
69
- placeholder.text = JSON.stringify(notebook, undefined, 4);
70
- </script>
71
- </hpcc-vitepress>
72
- </ClientOnly>
73
-
74
- <a name="omd2notebook" href="#omd2notebook">#</a> **omd2notebook**(_omd_) => ohq.Module · [<>](https://github.com/hpcc-systems/Visualization/blob/trunk/packages/observablehq/compiler/src/util.ts "Source")
75
-
76
- * _omd_: String containing Observable Markdown.
77
- * _returns_: Returns the notebook as a JSON object.
78
-
79
- Transforms Observable Markdown to a JSON notebook.
80
-
81
- <ClientOnly>
82
- <hpcc-vitepress style="width:100%;height:600px">
83
- <hpcc-codemirror id="placeholder" mode="json" theme="dark" style="width:100%;height:100%">
84
- </hpcc-codemirror>
85
- <script type="module">
86
- import "@hpcc-js/wc-editor";
87
- import { omd2notebook } from "@hpcc-js/observablehq-compiler";
88
-
89
- const notebook = omd2notebook(`\
90
- # Simple Notebook
91
-
92
- * Set A
93
- \`\`\`
94
- a = 1
95
- \`\`\`
96
-
97
- * Set B
98
- \`\`\`
99
- b = 2
100
- \`\`\`
101
-
102
- * Calculate c
103
-
104
- \`\`\`
105
- c = a + b
106
- \`\`\`
107
- `);
108
- const placeholder = document.getElementById("placeholder");
109
- placeholder.text = JSON.stringify(notebook, undefined, 4);
110
- </script>
111
- </hpcc-vitepress>
112
- </ClientOnly>
113
-
1
+ # Utilities
2
+
3
+ Various utilities and helpers.
4
+
5
+ ---
6
+
7
+ <a name="download" href="#download">#</a> **download**(_impUrl_) => Promise\<ohq.Module\> · [<>](https://github.com/hpcc-systems/Visualization/blob/trunk/packages/observablehq/compiler/src/util.ts "Source")
8
+
9
+ * _impUrl_: Full url to Obaservable HQ notebook as a string.
10
+ * _returns_: Returns a Promise of a notebook (a JSON object).
11
+
12
+ Downloads a notebook directly from [Observable HQ](https://observablehq.com/) as a JSON object. The following example downloads the [@observablehq/plot](https://observablehq.com/@observablehq/plot) notebook as JSON:
13
+
14
+ <ClientOnly>
15
+ <hpcc-vitepress style="width:100%;height:600px">
16
+ <hpcc-codemirror id="placeholder" mode="json" theme="dark" style="width:100%;height:100%">
17
+ </hpcc-codemirror>
18
+ <script type="module">
19
+ import "@hpcc-js/wc-editor";
20
+ import { download } from "@hpcc-js/observablehq-compiler";
21
+
22
+ const notebook = await download("https://observablehq.com/@observablehq/plot");
23
+ const placeholder = document.getElementById("placeholder");
24
+ placeholder.text = JSON.stringify(notebook, undefined, 4);
25
+ </script>
26
+ </hpcc-vitepress>
27
+ </ClientOnly>
28
+
29
+ ---
30
+
31
+ <a name="ojs2notebook" href="#ojs2notebook">#</a> **ojs2notebook**(_ojs_) => ohq.Module · [<>](https://github.com/hpcc-systems/Visualization/blob/trunk/packages/observablehq/compiler/src/util.ts "Source")
32
+
33
+ * _ojs_: String containing Observable JavaScript.
34
+ * _returns_: Returns the notebook as a JSON object.
35
+
36
+ Transforms Observable JavaScript to a JSON notebook.
37
+
38
+ <ClientOnly>
39
+ <hpcc-vitepress style="width:100%;height:600px">
40
+ <hpcc-codemirror id="placeholder" mode="json" theme="dark" style="width:100%;height:100%">
41
+ </hpcc-codemirror>
42
+ <script type="module">
43
+ import "@hpcc-js/wc-editor";
44
+ import { ojs2notebook } from "@hpcc-js/observablehq-compiler";
45
+
46
+ const notebook = ojs2notebook(`
47
+ md\`# Simple Notebook\`
48
+ a = 1
49
+ b = 2
50
+ c = a + b
51
+ d = {
52
+ yield 1;
53
+ yield 2;
54
+ yield 3;
55
+ }
56
+
57
+ viewof e = {
58
+ let output = {};
59
+ let listeners = [];
60
+ output.value = 10;
61
+ output.addEventListener = (listener) => listeners.push(listener);;
62
+ output.removeEventListener = (listener) => {
63
+ listeners = listeners.filter(l => l !== listener);
64
+ };
65
+ return output;
66
+ }
67
+ `);
68
+ const placeholder = document.getElementById("placeholder");
69
+ placeholder.text = JSON.stringify(notebook, undefined, 4);
70
+ </script>
71
+ </hpcc-vitepress>
72
+ </ClientOnly>
73
+
74
+ <a name="omd2notebook" href="#omd2notebook">#</a> **omd2notebook**(_omd_) => ohq.Module · [<>](https://github.com/hpcc-systems/Visualization/blob/trunk/packages/observablehq/compiler/src/util.ts "Source")
75
+
76
+ * _omd_: String containing Observable Markdown.
77
+ * _returns_: Returns the notebook as a JSON object.
78
+
79
+ Transforms Observable Markdown to a JSON notebook.
80
+
81
+ <ClientOnly>
82
+ <hpcc-vitepress style="width:100%;height:600px">
83
+ <hpcc-codemirror id="placeholder" mode="json" theme="dark" style="width:100%;height:100%">
84
+ </hpcc-codemirror>
85
+ <script type="module">
86
+ import "@hpcc-js/wc-editor";
87
+ import { omd2notebook } from "@hpcc-js/observablehq-compiler";
88
+
89
+ const notebook = omd2notebook(`\
90
+ # Simple Notebook
91
+
92
+ * Set A
93
+ \`\`\`
94
+ a = 1
95
+ \`\`\`
96
+
97
+ * Set B
98
+ \`\`\`
99
+ b = 2
100
+ \`\`\`
101
+
102
+ * Calculate c
103
+
104
+ \`\`\`
105
+ c = a + b
106
+ \`\`\`
107
+ `);
108
+ const placeholder = document.getElementById("placeholder");
109
+ placeholder.text = JSON.stringify(notebook, undefined, 4);
110
+ </script>
111
+ </hpcc-vitepress>
112
+ </ClientOnly>
113
+
package/src/util.ts CHANGED
@@ -1,176 +1,176 @@
1
- import type { ohq } from "@hpcc-js/observable-shim";
2
- import { parseCell, splitModule } from "@hpcc-js/observable-shim";
3
-
4
- const FuncTypes = {
5
- functionType: Object.getPrototypeOf(function () { }).constructor,
6
- asyncFunctionType: Object.getPrototypeOf(async function () { }).constructor,
7
- generatorFunctionType: Object.getPrototypeOf(function* () { }).constructor,
8
- asyncGeneratorFunctionType: Object.getPrototypeOf(async function* () { }).constructor
9
- };
10
-
11
- function funcType(async: boolean = false, generator: boolean = false) {
12
- if (!async && !generator) return FuncTypes.functionType;
13
- if (async && !generator) return FuncTypes.asyncFunctionType;
14
- if (!async && generator) return FuncTypes.generatorFunctionType;
15
- return FuncTypes.asyncGeneratorFunctionType;
16
- }
17
-
18
- interface Ref {
19
- start: number,
20
- end: number,
21
- newText: string
22
- }
23
-
24
- export interface Refs {
25
- inputs: string[];
26
- args: string[];
27
- patches: Ref[];
28
- }
29
-
30
- export function createFunction(refs: Refs, async = false, generator = false, blockStatement = false, body?: string) {
31
- if (body === undefined) {
32
- return undefined;
33
- }
34
-
35
- refs.patches.sort((l, r) => r.start - l.start);
36
- refs.patches.forEach(r => {
37
- body = body!.substring(0, r.start) + r.newText + body!.substring(r.end);
38
- });
39
- return new (funcType(async, generator))(...refs.args, blockStatement ?
40
- body.substring(1, body.length - 1).trim() :
41
- `return (\n${body}\n);`);
42
- }
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
-
58
- // Hide "import" from bundlers as they have a habit of replacing "import" with "require"
59
- export async function obfuscatedImport(url: string) {
60
- return new FuncTypes.asyncFunctionType("url", "return import(url)")(url);
61
- }
62
-
63
- interface ParsedOJS {
64
- ojs: string;
65
- offset: number;
66
- inlineMD: boolean;
67
- cell: any;
68
- error: any;
69
- }
70
-
71
- export function encodeBacktick(str: string) {
72
- return str
73
- .split("`").join("\\`")
74
- ;
75
- }
76
-
77
- function createParsedOJS(ojs: string, offset: number, inlineMD: boolean): ParsedOJS {
78
- let cell;
79
- let error;
80
- try {
81
- cell = parseCell(ojs);
82
- } catch (e) {
83
- error = e;
84
- }
85
- return {
86
- ojs,
87
- offset,
88
- inlineMD,
89
- cell,
90
- error
91
- };
92
- }
93
-
94
- function splitOmd(_: string): ParsedOJS[] {
95
- const retVal: ParsedOJS[] = [];
96
- // Load Markdown ---
97
- const re = /(```(?:\s|\S)[\s\S]*?```)/g;
98
- let prevOffset = 0;
99
- let match = re.exec(_);
100
- while (match !== null) {
101
- if (match.index > prevOffset) {
102
- retVal.push(createParsedOJS(_.substring(prevOffset, match.index), prevOffset, true));
103
- }
104
-
105
- const outer = match[0];
106
- if (outer.indexOf("``` ") === 0 || outer.indexOf("```\n") === 0 || outer.indexOf("```\r\n") === 0) {
107
- const prefixLen = 3;
108
- const inner = outer.substring(prefixLen, outer.length - prefixLen);
109
- retVal.push(createParsedOJS(inner, match.index + prefixLen, false));
110
- } else {
111
- retVal.push(createParsedOJS(outer, match.index, true));
112
- }
113
-
114
- prevOffset = match.index + match[0].length;
115
- match = re.exec(_);
116
- }
117
- if (_.length > prevOffset) {
118
- retVal.push(createParsedOJS(_.substring(prevOffset, _.length), prevOffset, true));
119
- }
120
- return retVal;
121
- }
122
-
123
- export function notebook2ojs(_: string): ParsedOJS[] {
124
- const parsed: ohq.Notebook = JSON.parse(_);
125
- return parsed.nodes.map(node => createParsedOJS(node.value, 0, node.mode === "md"));
126
- }
127
-
128
- export function ojs2notebook(ojs: string): ohq.Notebook {
129
- const cells = splitModule(ojs);
130
- return {
131
- files: [],
132
- nodes: cells.map((cell, idx) => {
133
- return {
134
- id: idx,
135
- mode: "js",
136
- value: cell.text,
137
- start: cell.start,
138
- end: cell.end
139
- };
140
- })
141
- } as ohq.Notebook;
142
- }
143
-
144
- export function omd2notebook(omd: string): ohq.Notebook {
145
- const cells = splitOmd(omd);
146
- return {
147
- files: [],
148
- nodes: cells.map((cell, idx) => {
149
- return {
150
- id: idx,
151
- mode: cell.inlineMD ? "md" : "js",
152
- value: cell.ojs,
153
- start: cell.offset,
154
- end: cell.offset + cell.ojs.length
155
- };
156
- })
157
- } as ohq.Notebook;
158
- }
159
-
160
- export function fetchEx(url: string, proxyPrefix = "https://api.codetabs.com/v1/proxy/?quest=", proxyPostfix = "") {
161
- const matches = url.match(/^(?:https?:\/\/)?(?:[^@\n]+@)?(?:www\.)?([^:\/\n?]+)/img);
162
- return fetch(url, { headers: { origin: matches[0], referer: url } }).then(response => {
163
- if (response.ok) return response;
164
- throw new Error("CORS?");
165
- }).catch(e => {
166
- url = `${proxyPrefix}${url}${proxyPostfix}`;
167
- return fetch(url, { headers: { origin: matches[0], referer: url } });
168
- });
169
- }
170
-
171
- export function download(impUrl: string, proxyPrefix?: string, proxyPostfix?: string): Promise<ohq.Notebook> {
172
- const isShared = impUrl.indexOf("https://observablehq.com/d") === 0;
173
- return fetchEx(impUrl.replace(`https://observablehq.com/${isShared ? "d/" : ""}`, "https://api.observablehq.com/document/"), proxyPrefix, proxyPostfix)
174
- .then(r => r.json())
175
- ;
1
+ import type { ohq } from "@hpcc-js/observable-shim";
2
+ import { parseCell, splitModule } from "@hpcc-js/observable-shim";
3
+
4
+ const FuncTypes = {
5
+ functionType: Object.getPrototypeOf(function () { }).constructor,
6
+ asyncFunctionType: Object.getPrototypeOf(async function () { }).constructor,
7
+ generatorFunctionType: Object.getPrototypeOf(function* () { }).constructor,
8
+ asyncGeneratorFunctionType: Object.getPrototypeOf(async function* () { }).constructor
9
+ };
10
+
11
+ function funcType(async: boolean = false, generator: boolean = false) {
12
+ if (!async && !generator) return FuncTypes.functionType;
13
+ if (async && !generator) return FuncTypes.asyncFunctionType;
14
+ if (!async && generator) return FuncTypes.generatorFunctionType;
15
+ return FuncTypes.asyncGeneratorFunctionType;
16
+ }
17
+
18
+ interface Ref {
19
+ start: number,
20
+ end: number,
21
+ newText: string
22
+ }
23
+
24
+ export interface Refs {
25
+ inputs: string[];
26
+ args: string[];
27
+ patches: Ref[];
28
+ }
29
+
30
+ export function createFunction(refs: Refs, async = false, generator = false, blockStatement = false, body?: string) {
31
+ if (body === undefined) {
32
+ return undefined;
33
+ }
34
+
35
+ refs.patches.sort((l, r) => r.start - l.start);
36
+ refs.patches.forEach(r => {
37
+ body = body!.substring(0, r.start) + r.newText + body!.substring(r.end);
38
+ });
39
+ return new (funcType(async, generator))(...refs.args, blockStatement ?
40
+ body.substring(1, body.length - 1).trim() :
41
+ `return (\n${body}\n);`);
42
+ }
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
+
58
+ // Hide "import" from bundlers as they have a habit of replacing "import" with "require"
59
+ export async function obfuscatedImport(url: string) {
60
+ return new FuncTypes.asyncFunctionType("url", "return import(url)")(url);
61
+ }
62
+
63
+ interface ParsedOJS {
64
+ ojs: string;
65
+ offset: number;
66
+ inlineMD: boolean;
67
+ cell: any;
68
+ error: any;
69
+ }
70
+
71
+ export function encodeBacktick(str: string) {
72
+ return str
73
+ .split("`").join("\\`")
74
+ ;
75
+ }
76
+
77
+ function createParsedOJS(ojs: string, offset: number, inlineMD: boolean): ParsedOJS {
78
+ let cell;
79
+ let error;
80
+ try {
81
+ cell = parseCell(ojs);
82
+ } catch (e) {
83
+ error = e;
84
+ }
85
+ return {
86
+ ojs,
87
+ offset,
88
+ inlineMD,
89
+ cell,
90
+ error
91
+ };
92
+ }
93
+
94
+ function splitOmd(_: string): ParsedOJS[] {
95
+ const retVal: ParsedOJS[] = [];
96
+ // Load Markdown ---
97
+ const re = /(```(?:\s|\S)[\s\S]*?```)/g;
98
+ let prevOffset = 0;
99
+ let match = re.exec(_);
100
+ while (match !== null) {
101
+ if (match.index > prevOffset) {
102
+ retVal.push(createParsedOJS(_.substring(prevOffset, match.index), prevOffset, true));
103
+ }
104
+
105
+ const outer = match[0];
106
+ if (outer.indexOf("``` ") === 0 || outer.indexOf("```\n") === 0 || outer.indexOf("```\r\n") === 0) {
107
+ const prefixLen = 3;
108
+ const inner = outer.substring(prefixLen, outer.length - prefixLen);
109
+ retVal.push(createParsedOJS(inner, match.index + prefixLen, false));
110
+ } else {
111
+ retVal.push(createParsedOJS(outer, match.index, true));
112
+ }
113
+
114
+ prevOffset = match.index + match[0].length;
115
+ match = re.exec(_);
116
+ }
117
+ if (_.length > prevOffset) {
118
+ retVal.push(createParsedOJS(_.substring(prevOffset, _.length), prevOffset, true));
119
+ }
120
+ return retVal;
121
+ }
122
+
123
+ export function notebook2ojs(_: string): ParsedOJS[] {
124
+ const parsed: ohq.Notebook = JSON.parse(_);
125
+ return parsed.nodes.map(node => createParsedOJS(node.value, 0, node.mode === "md"));
126
+ }
127
+
128
+ export function ojs2notebook(ojs: string): ohq.Notebook {
129
+ const cells = splitModule(ojs);
130
+ return {
131
+ files: [],
132
+ nodes: cells.map((cell, idx) => {
133
+ return {
134
+ id: idx,
135
+ mode: "js",
136
+ value: cell.text,
137
+ start: cell.start,
138
+ end: cell.end
139
+ };
140
+ })
141
+ } as ohq.Notebook;
142
+ }
143
+
144
+ export function omd2notebook(omd: string): ohq.Notebook {
145
+ const cells = splitOmd(omd);
146
+ return {
147
+ files: [],
148
+ nodes: cells.map((cell, idx) => {
149
+ return {
150
+ id: idx,
151
+ mode: cell.inlineMD ? "md" : "js",
152
+ value: cell.ojs,
153
+ start: cell.offset,
154
+ end: cell.offset + cell.ojs.length
155
+ };
156
+ })
157
+ } as ohq.Notebook;
158
+ }
159
+
160
+ export function fetchEx(url: string, proxyPrefix = "https://api.codetabs.com/v1/proxy/?quest=", proxyPostfix = "") {
161
+ const matches = url.match(/^(?:https?:\/\/)?(?:[^@\n]+@)?(?:www\.)?([^:\/\n?]+)/img);
162
+ return fetch(url, { headers: { origin: matches[0], referer: url } }).then(response => {
163
+ if (response.ok) return response;
164
+ throw new Error("CORS?");
165
+ }).catch(e => {
166
+ url = `${proxyPrefix}${url}${proxyPostfix}`;
167
+ return fetch(url, { headers: { origin: matches[0], referer: url } });
168
+ });
169
+ }
170
+
171
+ export function download(impUrl: string, proxyPrefix?: string, proxyPostfix?: string): Promise<ohq.Notebook> {
172
+ const isShared = impUrl.indexOf("https://observablehq.com/d") === 0;
173
+ return fetchEx(impUrl.replace(`https://observablehq.com/${isShared ? "d/" : ""}`, "https://api.observablehq.com/document/"), proxyPrefix, proxyPostfix)
174
+ .then(r => r.json())
175
+ ;
176
176
  }