├── .prettierrc
├── .surgeignore
├── src
├── index.js
├── utils.js
└── compiler.js
├── test
├── executable_attachment.js
├── test_cell.html
├── compiler-test.js
├── test_notebook_json.html
├── test.html
├── test_ES_module.html
└── compileESModule-test.js
├── rollup.config.js
├── .github
└── workflows
│ ├── main.yml
│ └── pull_request.yml
├── .circleci
└── config.yml
├── package.json
├── .gitignore
├── index.html
├── README.md
└── yarn.lock
/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | }
3 |
--------------------------------------------------------------------------------
/.surgeignore:
--------------------------------------------------------------------------------
1 | src/
2 | node_modules/
3 | yarn.lock
4 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | export { Compiler } from "./compiler.js";
2 |
--------------------------------------------------------------------------------
/test/executable_attachment.js:
--------------------------------------------------------------------------------
1 | // https://observablehq.com/@jashkenas/executable-js-fileattachment-test
2 | export const html = document.createElement("H1");
3 |
4 | html.innerHTML = "";
5 |
--------------------------------------------------------------------------------
/rollup.config.js:
--------------------------------------------------------------------------------
1 | import node from "rollup-plugin-node-resolve";
2 | import commonjs from "rollup-plugin-commonjs";
3 |
4 | export default {
5 | input: "src/index.js",
6 | output: [
7 | {
8 | compact: true,
9 | file: "dist/index.js",
10 | format: "umd",
11 | name: "index.js"
12 | },
13 | {
14 | compact: true,
15 | file: "dist/index-esm.js",
16 | format: "esm",
17 | name: "esm"
18 | }
19 | ],
20 | plugins: [node(), commonjs()]
21 | };
22 |
--------------------------------------------------------------------------------
/.github/workflows/main.yml:
--------------------------------------------------------------------------------
1 | name: Deploy Demo Site
2 |
3 | on:
4 | push:
5 | branches:
6 | - master
7 |
8 | jobs:
9 | build:
10 | runs-on: ubuntu-latest
11 |
12 | steps:
13 | - uses: actions/checkout@v1
14 | - uses: actions/setup-node@v1.1.0
15 | - run: npm install
16 | - run: npm run build
17 | - run: npm install -g surge
18 | - run: surge --domain unofficial-observablehq-compiler-demo.surge.sh --project .
19 | env:
20 | SURGE_TOKEN: ${{ secrets.SURGE_TOKEN }}
21 |
--------------------------------------------------------------------------------
/src/utils.js:
--------------------------------------------------------------------------------
1 | export const extractPath = path => {
2 | let source = path;
3 | let m;
4 |
5 | // "https://api.observablehq.com/@jashkenas/inputs.js?v=3" => strip off ".js"
6 | if ((m = /\.js(\?|$)/i.exec(source))) source = source.slice(0, m.index);
7 |
8 | // "74f872c4fde62e35" => "d/..."
9 | if ((m = /^[0-9a-f]{16}$/i.test(source))) source = `d/${source}`;
10 |
11 | // link of notebook
12 | if ((m = /^https:\/\/(api\.|beta\.|)observablehq\.com\//i.exec(source)))
13 | source = source.slice(m[0].length);
14 | return source;
15 | };
16 |
--------------------------------------------------------------------------------
/.circleci/config.yml:
--------------------------------------------------------------------------------
1 | # Javascript Node CircleCI 2.0 configuration file
2 | #
3 | # Check https://circleci.com/docs/2.0/language-javascript/ for more details
4 | #
5 | version: 2
6 | jobs:
7 | build:
8 | docker:
9 | # specify the version you desire here
10 | - image: circleci/node:10.16.0
11 |
12 | # Specify service dependencies here if necessary
13 | # CircleCI maintains a library of pre-built images
14 | # documented at https://circleci.com/docs/2.0/circleci-images/
15 | # - image: circleci/mongo:3.4.4
16 |
17 | working_directory: ~/repo
18 |
19 | steps:
20 | - checkout
21 |
22 | # Download and cache dependencies
23 | - restore_cache:
24 | keys:
25 | - v1-dependencies-{{ checksum "package.json" }}
26 | # fallback to using the latest cache if no exact match is found
27 | - v1-dependencies-
28 |
29 | - run: yarn install
30 |
31 | - save_cache:
32 | paths:
33 | - node_modules
34 | key: v1-dependencies-{{ checksum "package.json" }}
35 |
36 | # run tests!
37 | - run: yarn test
38 |
--------------------------------------------------------------------------------
/.github/workflows/pull_request.yml:
--------------------------------------------------------------------------------
1 | name: Pull Request Demos
2 |
3 | on:
4 | pull_request:
5 | types: [opened, reopened, synchronize]
6 |
7 | jobs:
8 | build:
9 | runs-on: ubuntu-latest
10 |
11 | steps:
12 | - uses: actions/checkout@v1
13 | - uses: actions/setup-node@v1.1.0
14 | - run: npm install
15 | - run: npm run build
16 | - run: npm install -g surge
17 | - run: surge --domain unofficial-observablehq-compiler-demo-${{ github.event.number }}.surge.sh --project .
18 | env:
19 | SURGE_TOKEN: ${{ secrets.SURGE_TOKEN }}
20 | - uses: actions/github-script@0.2.0
21 | with:
22 | github-token: ${{github.token}}
23 | script: |
24 | await github.issues.createComment({
25 | issue_number: context.issue.number,
26 | owner: context.repo.owner,
27 | repo: context.repo.repo,
28 | body: 'New demo site for this PR deployed to [unofficial-observablehq-compiler-demo-${{ github.event.number }}.surge.sh](https://unofficial-observablehq-compiler-demo-${{ github.event.number }}.surge.sh) !'
29 | })
30 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@alex.garcia/unofficial-observablehq-compiler",
3 | "version": "0.5.0",
4 | "description": "An unofficial compiler to bind @observablehq/parser and @observablehq/runtime",
5 | "main": "dist/index.js",
6 | "author": "Alex Garcia ",
7 | "repository": {
8 | "type": "git",
9 | "url": "https://github.com/asg017/unofficial-observablehq-compiler.git"
10 | },
11 | "license": "ISC",
12 | "publishConfig": {
13 | "access": "public"
14 | },
15 | "files": [
16 | "dist/**/*.js"
17 | ],
18 | "scripts": {
19 | "build": "rollup -c",
20 | "format": "prettier --write src/**/*.js",
21 | "test": "npm run build && tape 'test/**/*-test.js' && npm run test-format",
22 | "test-format": "prettier --check src/**/*.js",
23 | "test-html": "http-server",
24 | "prepublishOnly": "npm run build",
25 | "postpublish": "git push && git push --tags"
26 | },
27 | "keywords": [
28 | "observable",
29 | "observablehq",
30 | "observable-notebooks",
31 | "notebooks",
32 | "parser",
33 | "compiler"
34 | ],
35 | "dependencies": {
36 | "@observablehq/parser": "^3.0.0",
37 | "acorn-walk": "^7.0.0"
38 | },
39 | "devDependencies": {
40 | "@observablehq/runtime": "^4.6.4",
41 | "http-server": "^0.11.1",
42 | "prettier": "1.19.1",
43 | "rollup": "^1.26.4",
44 | "rollup-plugin-commonjs": "^10.1.0",
45 | "rollup-plugin-node-resolve": "^5.2.0",
46 | "tape": "^4.11.0"
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | lerna-debug.log*
8 |
9 | # Diagnostic reports (https://nodejs.org/api/report.html)
10 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
11 |
12 | # Runtime data
13 | pids
14 | *.pid
15 | *.seed
16 | *.pid.lock
17 |
18 | # Directory for instrumented libs generated by jscoverage/JSCover
19 | lib-cov
20 |
21 | # Coverage directory used by tools like istanbul
22 | coverage
23 | *.lcov
24 |
25 | # nyc test coverage
26 | .nyc_output
27 |
28 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
29 | .grunt
30 |
31 | # Bower dependency directory (https://bower.io/)
32 | bower_components
33 |
34 | # node-waf configuration
35 | .lock-wscript
36 |
37 | # Compiled binary addons (https://nodejs.org/api/addons.html)
38 | build/Release
39 |
40 | # Dependency directories
41 | node_modules/
42 | jspm_packages/
43 |
44 | # TypeScript v1 declaration files
45 | typings/
46 |
47 | # TypeScript cache
48 | *.tsbuildinfo
49 |
50 | # Optional npm cache directory
51 | .npm
52 |
53 | # Optional eslint cache
54 | .eslintcache
55 |
56 | # Optional REPL history
57 | .node_repl_history
58 |
59 | # Output of 'npm pack'
60 | *.tgz
61 |
62 | # Yarn Integrity file
63 | .yarn-integrity
64 |
65 | # dotenv environment variables file
66 | .env
67 | .env.test
68 |
69 | # parcel-bundler cache (https://parceljs.org/)
70 | .cache
71 |
72 | # next.js build output
73 | .next
74 |
75 | # nuxt.js build output
76 | .nuxt
77 |
78 | # vuepress build output
79 | .vuepress/dist
80 |
81 | # Serverless directories
82 | .serverless/
83 |
84 | # FuseBox cache
85 | .fusebox/
86 |
87 | # DynamoDB Local files
88 | .dynamodb/
89 |
90 | dist/
91 |
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
10 |
18 |
19 |
20 |
21 |
58 |
59 |
--------------------------------------------------------------------------------
/test/test_cell.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
10 |
11 |
12 |
13 |
76 |
77 |
--------------------------------------------------------------------------------
/test/compiler-test.js:
--------------------------------------------------------------------------------
1 | const test = require("tape");
2 | const runtime = require("@observablehq/runtime");
3 | const compiler = require("../dist/index");
4 |
5 | test("compiler", async t => {
6 | const rt = new runtime.Runtime();
7 | const compile = new compiler.Compiler();
8 | const define = await compile.module(`
9 | a = 1
10 |
11 | b = 2
12 |
13 | c = a + b
14 |
15 | d = {
16 | yield 1;
17 | yield 2;
18 | yield 3;
19 | }
20 |
21 | viewof e = {
22 | let output = {};
23 | let listeners = [];
24 | output.value = 10;
25 | output.addEventListener = (listener) => listeners.push(listener);;
26 | output.removeEventListener = (listener) => {
27 | listeners = listeners.filter(l => l !== listener);
28 | };
29 | return output;
30 | }
31 | `);
32 | const main = rt.module(define);
33 | await rt._compute();
34 |
35 | t.equal(await main.value("a"), 1);
36 | t.equal(await main.value("b"), 2);
37 | t.equal(await main.value("c"), 3);
38 |
39 | t.equal(await main.value("d"), 1);
40 | t.equal(await main.value("d"), 2);
41 | t.equal(await main.value("d"), 3);
42 |
43 | t.equal(await main.value("e"), 10);
44 | t.deepEqual(Object.keys(await main.value("viewof e")), [
45 | "value",
46 | "addEventListener",
47 | "removeEventListener"
48 | ]);
49 |
50 | const { redefine: aRedefine } = await compile.cell(`a = 10`);
51 | aRedefine(main);
52 | await rt._compute();
53 | t.equal(await main.value("a"), 10);
54 | t.equal(await main.value("c"), 12);
55 |
56 | const { define: xDefine } = await compile.cell(`x = y - 1`);
57 | xDefine(main, () => true);
58 | await rt._compute();
59 |
60 | try {
61 | await main.value("x");
62 | t.fail();
63 | } catch (error) {
64 | t.equal(error.constructor, runtime.RuntimeError);
65 | }
66 |
67 | const { define: yDefine } = await compile.cell(`y = 101`);
68 | yDefine(main, () => true);
69 | await rt._compute();
70 |
71 | t.equal(await main.value("y"), 101);
72 | t.equal(await main.value("x"), 100);
73 |
74 | const { redefine: eRedefine } = await compile.cell(`viewof e = {
75 | let output = {};
76 | let listeners = [];
77 | output.value = 20;
78 | output.addEventListener = (listener) => listeners.push(listener);;
79 | output.removeEventListener = (listener) => {
80 | listeners = listeners.filter(l => l !== listener);
81 | };
82 | return output;
83 | }`);
84 | eRedefine(main);
85 | await rt._compute();
86 |
87 | t.equal(await main.value("e"), 20);
88 |
89 | rt.dispose();
90 | t.end();
91 | });
92 |
--------------------------------------------------------------------------------
/test/test_notebook_json.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
10 |
11 |
12 |
13 |
120 |
121 |
--------------------------------------------------------------------------------
/test/test.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
10 |
11 |
12 |
13 |
144 |
145 |
--------------------------------------------------------------------------------
/test/test_ES_module.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
10 |
11 |
12 |
13 |
154 |
155 |
--------------------------------------------------------------------------------
/test/compileESModule-test.js:
--------------------------------------------------------------------------------
1 | const test = require("tape");
2 | const compiler = require("../dist/index");
3 |
4 | test("ES module: simple", async t => {
5 | const compile = new compiler.Compiler();
6 | const src = compile.moduleToESModule(`
7 | a = 1
8 |
9 | b = 2
10 |
11 | c = a + b
12 |
13 | d = {
14 | yield 1;
15 | yield 2;
16 | yield 3;
17 | }
18 |
19 | {
20 | await d;
21 | }
22 |
23 | viewof e = {
24 | let output = {};
25 | let listeners = [];
26 | output.value = 10;
27 | output.addEventListener = (listener) => listeners.push(listener);;
28 | output.removeEventListener = (listener) => {
29 | listeners = listeners.filter(l => l !== listener);
30 | };
31 | return output;
32 | }
33 | `);
34 | t.equal(src, `export default function define(runtime, observer) {
35 | const main = runtime.module();
36 |
37 | main.variable(observer("a")).define("a", function(){return(
38 | 1
39 | )});
40 | main.variable(observer("b")).define("b", function(){return(
41 | 2
42 | )});
43 | main.variable(observer("c")).define("c", ["a","b"], function(a,b){return(
44 | a + b
45 | )});
46 | main.variable(observer("d")).define("d", function*()
47 | {
48 | yield 1;
49 | yield 2;
50 | yield 3;
51 | }
52 | );
53 | main.variable(observer()).define(["d"], async function(d)
54 | {
55 | await d;
56 | }
57 | );
58 | main.variable(observer("viewof e")).define("viewof e", function()
59 | {
60 | let output = {};
61 | let listeners = [];
62 | output.value = 10;
63 | output.addEventListener = (listener) => listeners.push(listener);;
64 | output.removeEventListener = (listener) => {
65 | listeners = listeners.filter(l => l !== listener);
66 | };
67 | return output;
68 | }
69 | );
70 | main.variable(observer("e")).define("e", ["Generators", "viewof e"], (G, _) => G.input(_));
71 | return main;
72 | }`);
73 |
74 | t.end();
75 | });
76 |
77 | test("ES module: imports", async t => {
78 | const compile = new compiler.Compiler();
79 | const src = compile.moduleToESModule(`import {a} from "b"
80 | b = {
81 | return 3*a
82 | }
83 | import {c as bc} from "b"
84 | import {d} with {b as cb} from "c"
85 | `);
86 |
87 | t.equal(src, `import define1 from "https://api.observablehq.com/b.js?v=3";
88 | import define2 from "https://api.observablehq.com/c.js?v=3";
89 |
90 | export default function define(runtime, observer) {
91 | const main = runtime.module();
92 |
93 | main.variable(observer()).define(
94 | null,
95 | ["md"],
96 | md => md\`~~~javascript
97 | import {a as a} from "b"
98 | ~~~\`
99 | );
100 | const child1 = runtime.module(define1);
101 | main.import("a", "a", child1);
102 | main.variable(observer("b")).define("b", ["a"], function(a)
103 | {
104 | return 3*a
105 | }
106 | );
107 | main.variable(observer()).define(
108 | null,
109 | ["md"],
110 | md => md\`~~~javascript
111 | import {c as bc} from "b"
112 | ~~~\`
113 | );
114 | const child2 = runtime.module(define1);
115 | main.import("c", "bc", child2);
116 | main.variable(observer()).define(
117 | null,
118 | ["md"],
119 | md => md\`~~~javascript
120 | import {d as d} with {b as cb} from "c"
121 | ~~~\`
122 | );
123 | const child3 = runtime.module(define2).derive([{"name":"b","alias":"cb"}], main);
124 | main.import("d", "d", child3);
125 | return main;
126 | }`);
127 |
128 | t.end();
129 | });
130 |
131 |
132 | test("ES module: custom resolvePath function", async t => {
133 | const resolvePath = name => `https://gist.github.com/${name}`;
134 | const compile = new compiler.Compiler(undefined, undefined, resolvePath);
135 | const src = compile.moduleToESModule(`import {a} from "b"
136 | b = {
137 | return 3*a
138 | }
139 | import {c as bc} from "b"
140 | import {d} with {b as cb} from "c"
141 | `);
142 |
143 | t.equal(src, `import define1 from "https://gist.github.com/b";
144 | import define2 from "https://gist.github.com/c";
145 |
146 | export default function define(runtime, observer) {
147 | const main = runtime.module();
148 |
149 | main.variable(observer()).define(
150 | null,
151 | ["md"],
152 | md => md\`~~~javascript
153 | import {a as a} from "b"
154 | ~~~\`
155 | );
156 | const child1 = runtime.module(define1);
157 | main.import("a", "a", child1);
158 | main.variable(observer("b")).define("b", ["a"], function(a)
159 | {
160 | return 3*a
161 | }
162 | );
163 | main.variable(observer()).define(
164 | null,
165 | ["md"],
166 | md => md\`~~~javascript
167 | import {c as bc} from "b"
168 | ~~~\`
169 | );
170 | const child2 = runtime.module(define1);
171 | main.import("c", "bc", child2);
172 | main.variable(observer()).define(
173 | null,
174 | ["md"],
175 | md => md\`~~~javascript
176 | import {d as d} with {b as cb} from "c"
177 | ~~~\`
178 | );
179 | const child3 = runtime.module(define2).derive([{"name":"b","alias":"cb"}], main);
180 | main.import("d", "d", child3);
181 | return main;
182 | }`);
183 |
184 | t.end();
185 | });
186 |
187 | test("ES module: viewof + mutable", async t => {
188 | const compile = new compiler.Compiler();
189 | const src = compile.moduleToESModule(`viewof a = {
190 | const div = html\`\`;
191 | div.value = 3;
192 | return div;
193 | }
194 | mutable b = 3
195 | {
196 | return b*b
197 | }
198 | d = {
199 | mutable b++;
200 | return a + b;
201 | }
202 | import {viewof v as w, mutable m} from "notebook"`);
203 |
204 | t.equal(src, `import define1 from "https://api.observablehq.com/notebook.js?v=3";
205 |
206 | export default function define(runtime, observer) {
207 | const main = runtime.module();
208 |
209 | main.variable(observer("viewof a")).define("viewof a", ["html"], function(html)
210 | {
211 | const div = html\`\`;
212 | div.value = 3;
213 | return div;
214 | }
215 | );
216 | main.variable(observer("a")).define("a", ["Generators", "viewof a"], (G, _) => G.input(_));
217 | main.define("initial b", function(){return(
218 | 3
219 | )});
220 | main.variable(observer("mutable b")).define("mutable b", ["Mutable", "initial b"], (M, _) => new M(_));
221 | main.variable(observer("b")).define("b", ["mutable b"], _ => _.generator);
222 | main.variable(observer()).define(["b"], function(b)
223 | {
224 | return b*b
225 | }
226 | );
227 | main.variable(observer("d")).define("d", ["mutable b","a","b"], function($0,a,b)
228 | {
229 | $0.value++;
230 | return a + b;
231 | }
232 | );
233 | main.variable(observer()).define(
234 | null,
235 | ["md"],
236 | md => md\`~~~javascript
237 | import {viewof v as viewof w, v as w, mutable m as mutable m, m as m} from "notebook"
238 | ~~~\`
239 | );
240 | const child1 = runtime.module(define1);
241 | main.import("viewof v", "viewof w", child1);
242 | main.import("v", "w", child1);
243 | main.import("mutable m", "mutable m", child1);
244 | main.import("m", "m", child1);
245 | return main;
246 | }`);
247 |
248 | t.end();
249 | });
250 |
251 | test("ES module: FileAttachment", async t => {
252 | const compile = new compiler.Compiler();
253 | const src = compile.moduleToESModule(`md\`Here's a cell with a file attachment!
\``);
254 |
255 | t.equal(src, `export default function define(runtime, observer) {
256 | const main = runtime.module();
257 | const fileAttachments = new Map([["image.png","image.png"]]);
258 | main.builtin("FileAttachment", runtime.fileAttachments(name => fileAttachments.get(name)));
259 | main.variable(observer()).define(["md","FileAttachment"], async function(md,FileAttachment){return(
260 | md\`Here's a cell with a file attachment!
\`
261 | )});
262 | return main;
263 | }`);
264 |
265 | t.end();
266 | });
267 |
268 | test("ES module: custom fileAttachmentsResolve", async t => {
269 | const fileAttachmentsResolve = name => `https://example.com/${name}`;
270 | const compile = new compiler.Compiler(undefined, fileAttachmentsResolve);
271 | const src = compile.moduleToESModule(`md\`Here's a cell with a file attachment!
\``);
272 |
273 | t.equal(src, `export default function define(runtime, observer) {
274 | const main = runtime.module();
275 | const fileAttachments = new Map([["image.png","https://example.com/image.png"]]);
276 | main.builtin("FileAttachment", runtime.fileAttachments(name => fileAttachments.get(name)));
277 | main.variable(observer()).define(["md","FileAttachment"], async function(md,FileAttachment){return(
278 | md\`Here's a cell with a file attachment!
\`
279 | )});
280 | return main;
281 | }`);
282 |
283 | t.end();
284 | });
285 |
286 |
287 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # @alex.garcia/unofficial-observablehq-compiler [](https://circleci.com/gh/asg017/unofficial-observablehq-compiler)
2 |
3 |
4 |
5 |
6 | An unoffical compiler for Observable notebooks (glue between the Observable parser and runtime)
7 |
8 | ## ⚠️This library is currently under construction!⚠️
9 |
10 | The README below is for `v0.5.0`, but `v0.6.0` is currently in alpha and has several improvements to this library + API that you probably care about. Check out [#29](https://github.com/asg017/unofficial-observablehq-compiler/pull/29) to stay in the loop, and check out [that version's README](https://github.com/asg017/unofficial-observablehq-compiler/tree/beta) for docs on the soon-to-be-released `v0.6.0`.
11 |
12 | ---
13 |
14 |
15 | This compiler will compile "observable syntax" into "javascript syntax".
16 | For example -
17 |
18 | ```javascript
19 | import compiler from "@alex.garcia/unofficial-observablehq-compiler";
20 | import { Inspector, Runtime } from "@observablehq/runtime";
21 |
22 | const compile = new compiler.Compiler();
23 |
24 | compile.module(`
25 | import {text} from '@jashkenas/inputs'
26 |
27 | viewof name = text({
28 | title: "what's your name?",
29 | value: ''
30 | })
31 |
32 | md\`Hello **\${name}**, it's nice to meet you!\`
33 |
34 | `).then(define => {
35 | const runtime = new Runtime();
36 |
37 | const module = runtime.module(define, Inpsector.into(document.body));
38 | });
39 | ```
40 |
41 | For more live examples and functionality, take a look at the [announcement notebook](https://observablehq.com/d/74f872c4fde62e35)
42 | and this [test page](https://github.com/asg017/unofficial-observablehq-compiler/blob/master/test/test.html).
43 |
44 | ## API Reference
45 |
46 | ### Compiler
47 |
48 | # new Compiler(resolve = defaultResolver, fileAttachmentsResolve = name => name, resolvePath = defaultResolvePath) [<>](https://github.com/asg017/unofficial-observablehq-compiler/blob/master/src/compiler.js#L119 "Source")
49 |
50 | Returns a new compiler. `resolve` is an optional function that, given a `path`
51 | string, will resolve a new define function for a new module. This is used when
52 | the compiler comes across an import statement - for example:
53 |
54 | ```javascript
55 | import {chart} from "@d3/bar-chart"
56 | ```
57 |
58 | In this case, `resolve` gets called with `path="@d3/bar-chart"`. The `defaultResolver`
59 | function will lookup the given path on observablehq.com and return the define
60 | function to define that notebook.
61 |
62 | For example, if you have your own set of notebooks on some other server, you
63 | could use something like:
64 |
65 | ```javascript
66 | const resolve = path =>
67 | import(`other.server.com/notebooks/${path}.js`).then(
68 | module => module.default
69 | );
70 |
71 | const compile = new Compiler(resolve);
72 | ```
73 |
74 | `fileAttachmentsResolve` is an optional function from strings to URLs which is used as a resolve function in the standard library's FileAttachments function. For example, if you wanted to reference `example.com/my_file.png` in a cell which reads:
75 |
76 | ```javascript
77 | await FileAttachment("my_file.png").url();
78 | ```
79 |
80 | Then you could compile this cell with:
81 |
82 | ```javascript
83 | const fileAttachmentsResolve = name => `example.com/${name}`;
84 |
85 | const compile = new Compiler(, fileAttachmentsResolve);
86 | ```
87 |
88 | By default, `fileAtachmentsResolve` simply returns the same string, so you would have to use valid absolute or relative URLs in your `FileAttachment`s.
89 |
90 | `resolvePath` is an optional function from strings to URLs which is used to turn the strings in `import` cells to URLs in [`compile.moduleToESModule`](#compile_moduleToESModule) and [`compile.notebookToESModule`](#compile_notebookToESModule). For instance, if those functions encounter this cell:
91 | ```javascript
92 | import {chart} from "@d3/bar-chart"
93 | ```
94 | then `resolvePath` is called with `path="@d3/bar-chart"` and the resulting URL is included in the static `import` statements at the beginning of the generated ES module source.
95 |
96 | #compile.module(contents)
97 |
98 | Returns a define function. `contents` is a string that defines a "module", which
99 | is a list of "cells" (both defintions from [@observablehq/parser](https://github.com/observablehq/parser)).
100 | It must be compatible with [`parseModule`](https://github.com/observablehq/parser#parseModule). This fetches all imports so it is asynchronous.
101 |
102 | For example:
103 |
104 | ```javascript
105 | const define = await compile.module(`a = 1
106 | b = 2
107 | c = a + b`);
108 | ```
109 |
110 | You can now use `define` with the Observable [runtime](https://github.com/observablehq/runtime):
111 |
112 | ```javascript
113 | const runtime = new Runtime();
114 | const main = runtime.module(define, Inspector.into(document.body));
115 | ```
116 |
117 | #compile.notebook(object)
118 |
119 | Returns a define function. `object` is a "notebook JSON object" as used by the
120 | ObservableHQ notebook app to display notebooks. Such JSON files are served by
121 | the API endpoint at `https://api.observablehq.com/document/:slug` (see the
122 | [`observable-client`](https://github.com/mootari/observable-client) for a
123 | convenient way to authenticate and make requests).
124 |
125 | `compile.notebook` requires that `object` has a field named `"nodes"`
126 | consisting of an array of cell objects. Each of the cell objects must have a
127 | field `"value"` consisting of a string with the source code for that cell.
128 |
129 | The notebook JSON objects also ordinarily contain some other metadata fields,
130 | e.g. `"id"`, `"slug"`, `"owner"`, etc. which are currently ignored by the
131 | compiler. Similarly, the cell objects in `"nodes"` ordinarily contain `"id"` and
132 | `"pinned"` fields which are also unused here.
133 |
134 | This fetches all imports so it is asynchronous.
135 |
136 | For example:
137 |
138 | ```javascript
139 | const define = await compile.notebook({
140 | nodes: [{ value: "a = 1" }, { value: "b = 2" }, { value: "c = a + b" }]
141 | });
142 | ```
143 |
144 | You can now use `define` with the Observable [runtime](https://github.com/observablehq/runtime):
145 |
146 | ```javascript
147 | const runtime = new Runtime();
148 | const main = runtime.module(define, Inspector.into(document.body));
149 | ```
150 |
151 | #compile.cell(contents)
152 |
153 | Returns an object that has `define` and `redefine` functions that would define or redefine variables in the given cell to a specified module. `contents` is input for the [`parseCell`](https://github.com/observablehq/parser#parseCell) function. If the cell is not an ImportDeclaration, then the `redefine` functions can be used to redefine previously existing variables in a module. This is an asynchronous function because if the cell is an import, the imported notebook is fetched.
154 |
155 | ```javascript
156 | let define, redefine;
157 |
158 | define = await compile.module(`a = 1;
159 | b = 2;
160 |
161 | c = a + b`);
162 |
163 | const runtime = new Runtime();
164 | const main = runtime.module(define, Inspector.into(document.body));
165 |
166 | await main.value("a") // 1
167 |
168 | {define, redefine} = await compile.cell(`a = 20`);
169 |
170 | redefine(main);
171 |
172 | await main.value("a"); // 20
173 | await main.value("c"); // 22
174 |
175 | define(main); // would throw an error, since a is already defined in main
176 |
177 | {define} = await compile.cell(`x = 2`);
178 | define(main);
179 | {define} = await compile.cell(`y = x * 4`);
180 | define(main);
181 |
182 | await main.value("y") // 8
183 |
184 | ```
185 |
186 | Keep in mind, if you want to use `define` from `compile.cell`, you'll have to provide an `observer` function, which will most likely be the same observer that was used when defining the module. For example:
187 |
188 | ```javascript
189 |
190 | let define, redefine;
191 |
192 | define = await compile.module(`a = 1;
193 | b = 2;`);
194 |
195 | const runtime = new Runtime();
196 | const observer = Inspector.into(document.body);
197 | const main = runtime.module(define, observer);
198 |
199 | {define} = await compile.cell(`c = a + b`);
200 |
201 | define(main, observer);
202 |
203 | ```
204 |
205 | Since `redefine` is done on a module level, an observer is not required.
206 |
207 | #compile.moduleToESModule(contents)
208 |
209 | Returns a string containing the source code of an ES module. This ES module is compiled from the Observable runtime module in the string `contents`.
210 |
211 | For example:
212 |
213 | ```javascript
214 | const src = compile.moduleToESModule(`a = 1
215 | b = 2
216 | c = a + b`);
217 | ```
218 |
219 | Now `src` contains the following:
220 |
221 | ```javascript
222 | export default function define(runtime, observer) {
223 | const main = runtime.module();
224 |
225 | main.variable(observer("a")).define("a", function(){return(
226 | 1
227 | )});
228 | main.variable(observer("b")).define("b", function(){return(
229 | 2
230 | )});
231 | main.variable(observer("c")).define("c", ["a","b"], function(a,b){return(
232 | a + b
233 | )});
234 | return main;
235 | }
236 | ```
237 |
238 | #compile.notebookToESModule(object)
239 |
240 | Returns a string containing the source code of an ES module. This ES module is compiled from the Observable runtime module in the notebok object `object`. (See [compile.notebook](#compile_notebook)).
241 |
242 | For example:
243 |
244 | ```javascript
245 | const src = compile.notebookToESModule({
246 | nodes: [{ value: "a = 1" }, { value: "b = 2" }, { value: "c = a + b" }]
247 | });
248 | ```
249 |
250 | Now `src` contains the following:
251 |
252 | ```javascript
253 | export default function define(runtime, observer) {
254 | const main = runtime.module();
255 |
256 | main.variable(observer("a")).define("a", function(){return(
257 | 1
258 | )});
259 | main.variable(observer("b")).define("b", function(){return(
260 | 2
261 | )});
262 | main.variable(observer("c")).define("c", ["a","b"], function(a,b){return(
263 | a + b
264 | )});
265 | return main;
266 | }
267 | ```
268 |
269 | ## License
270 |
271 | This library is MIT, but it relies and gets heavy inspiration from the following
272 | libraries licensed under ISC:
273 |
274 | - [@observablehq/runtime](https://github.com/observablehq/runtime)
275 | - [@observablehq/stdlib](https://github.com/observablehq/stdlib)
276 | - [@observablehq/inspector](https://github.com/observablehq/inspector)
277 | - [@observablehq/parser](https://github.com/observablehq/parser)
278 |
279 | ## Contributing
280 |
281 | Feel free to send in PR's as you wish! Take a look at the [issues](https://github.com/asg017/unofficial-observablehq-compiler/issues)
282 | to find something to work on. Just please follow the [Contributor Covenant](https://www.contributor-covenant.org/)
283 | in all your interactions :smile:
284 |
--------------------------------------------------------------------------------
/src/compiler.js:
--------------------------------------------------------------------------------
1 | import { parseCell, parseModule, walk } from "@observablehq/parser";
2 | import { simple } from "acorn-walk";
3 | import { extractPath } from "./utils";
4 |
5 | const AsyncFunction = Object.getPrototypeOf(async function() {}).constructor;
6 | const GeneratorFunction = Object.getPrototypeOf(function*() {}).constructor;
7 | const AsyncGeneratorFunction = Object.getPrototypeOf(async function*() {})
8 | .constructor;
9 |
10 | const setupRegularCell = cell => {
11 | let name = null;
12 | if (cell.id && cell.id.name) name = cell.id.name;
13 | else if (cell.id && cell.id.id && cell.id.id.name) name = cell.id.id.name;
14 | let bodyText = cell.input.substring(cell.body.start, cell.body.end);
15 | const cellReferences = (cell.references || []).map(ref => {
16 | if (ref.type === "ViewExpression") {
17 | return "viewof " + ref.id.name;
18 | } else if (ref.type === "MutableExpression") {
19 | return "mutable " + ref.id.name;
20 | } else return ref.name;
21 | });
22 | let $count = 0;
23 | let indexShift = 0;
24 | const references = (cell.references || []).map(ref => {
25 | if (ref.type === "ViewExpression") {
26 | const $string = "$" + $count;
27 | $count++;
28 | // replace "viewof X" in bodyText with "$($count)"
29 | simple(
30 | cell.body,
31 | {
32 | ViewExpression(node) {
33 | const start = node.start - cell.body.start;
34 | const end = node.end - cell.body.start;
35 | bodyText =
36 | bodyText.slice(0, start + indexShift) +
37 | $string +
38 | bodyText.slice(end + indexShift);
39 | indexShift += $string.length - (end - start);
40 | }
41 | },
42 | walk
43 | );
44 | return $string;
45 | } else if (ref.type === "MutableExpression") {
46 | const $string = "$" + $count;
47 | const $stringValue = $string + ".value";
48 | $count++;
49 | // replace "mutable Y" in bodyText with "$($count).value"
50 | simple(
51 | cell.body,
52 | {
53 | MutableExpression(node) {
54 | const start = node.start - cell.body.start;
55 | const end = node.end - cell.body.start;
56 | bodyText =
57 | bodyText.slice(0, start + indexShift) +
58 | $stringValue +
59 | bodyText.slice(end + indexShift);
60 | indexShift += $stringValue.length - (end - start);
61 | }
62 | },
63 | walk
64 | );
65 | return $string;
66 | } else return ref.name;
67 | });
68 | return { cellName: name, references, bodyText, cellReferences };
69 | };
70 |
71 | const createRegularCellDefintion = cell => {
72 | const { cellName, references, bodyText, cellReferences } = setupRegularCell(
73 | cell
74 | );
75 |
76 | let code;
77 | if (cell.body.type !== "BlockStatement") {
78 | if (cell.async)
79 | code = `return (async function(){ return (${bodyText});})()`;
80 | else code = `return (function(){ return (${bodyText});})()`;
81 | } else code = bodyText;
82 |
83 | let f;
84 | if (cell.generator && cell.async)
85 | f = new AsyncGeneratorFunction(...references, code);
86 | else if (cell.async) f = new AsyncFunction(...references, code);
87 | else if (cell.generator) f = new GeneratorFunction(...references, code);
88 | else f = new Function(...references, code);
89 | return {
90 | cellName,
91 | cellFunction: f,
92 | cellReferences
93 | };
94 | };
95 |
96 | const setupImportCell = cell => {
97 | const specifiers = [];
98 | if (cell.body.specifiers)
99 | for (const specifier of cell.body.specifiers) {
100 | if (specifier.view) {
101 | specifiers.push({
102 | name: "viewof " + specifier.imported.name,
103 | alias: "viewof " + specifier.local.name
104 | });
105 | } else if (specifier.mutable) {
106 | specifiers.push({
107 | name: "mutable " + specifier.imported.name,
108 | alias: "mutable " + specifier.local.name
109 | });
110 | }
111 | specifiers.push({
112 | name: specifier.imported.name,
113 | alias: specifier.local.name
114 | });
115 | }
116 | // If injections is undefined, do not derive!
117 | const hasInjections = cell.body.injections !== undefined;
118 | const injections = [];
119 | if (hasInjections)
120 | for (const injection of cell.body.injections) {
121 | // This currently behaves like notebooks on observablehq.com
122 | // Commenting out the if & else if blocks result in behavior like Example 3 here: https://observablehq.com/d/7ccad009e4d89969
123 | if (injection.view) {
124 | injections.push({
125 | name: "viewof " + injection.imported.name,
126 | alias: "viewof " + injection.local.name
127 | });
128 | } else if (injection.mutable) {
129 | injections.push({
130 | name: "mutable " + injection.imported.name,
131 | alias: "mutable " + injection.local.name
132 | });
133 | }
134 | injections.push({
135 | name: injection.imported.name,
136 | alias: injection.local.name
137 | });
138 | }
139 | const importString = `import {${specifiers
140 | .map(specifier => `${specifier.name} as ${specifier.alias}`)
141 | .join(", ")}} ${
142 | hasInjections
143 | ? `with {${injections
144 | .map(injection => `${injection.name} as ${injection.alias}`)
145 | .join(", ")}} `
146 | : ``
147 | }from "${cell.body.source.value}"`;
148 |
149 | return { specifiers, hasInjections, injections, importString };
150 | };
151 |
152 | const createCellDefinition = (
153 | cell,
154 | main,
155 | observer,
156 | dependencyMap,
157 | define = true
158 | ) => {
159 | if (cell.body.type === "ImportDeclaration") {
160 | const {
161 | specifiers,
162 | hasInjections,
163 | injections,
164 | importString
165 | } = setupImportCell(cell);
166 | // this will display extra names for viewof / mutable imports (for now?)
167 | main.variable(observer()).define(
168 | null,
169 | ["md"],
170 | md => md`~~~javascript
171 | ${importString}
172 | ~~~`
173 | );
174 |
175 | const other = main._runtime.module(
176 | dependencyMap.get(cell.body.source.value)
177 | );
178 |
179 | if (hasInjections) {
180 | const child = other.derive(injections, main);
181 | for (const { name, alias } of specifiers) main.import(name, alias, child);
182 | } else {
183 | for (const { name, alias } of specifiers) main.import(name, alias, other);
184 | }
185 | } else {
186 | const {
187 | cellName,
188 | cellFunction,
189 | cellReferences
190 | } = createRegularCellDefintion(cell);
191 | if (cell.id && cell.id.type === "ViewExpression") {
192 | const reference = `viewof ${cellName}`;
193 | if (define) {
194 | main
195 | .variable(observer(reference))
196 | .define(reference, cellReferences, cellFunction);
197 | main
198 | .variable(observer(cellName))
199 | .define(cellName, ["Generators", reference], (G, _) => G.input(_));
200 | } else {
201 | main.redefine(reference, cellReferences, cellFunction);
202 | main.redefine(cellName, ["Generators", reference], (G, _) =>
203 | G.input(_)
204 | );
205 | }
206 | } else if (cell.id && cell.id.type === "MutableExpression") {
207 | const initialName = `initial ${cellName}`;
208 | const mutableName = `mutable ${cellName}`;
209 | if (define) {
210 | main.variable(null).define(initialName, cellReferences, cellFunction);
211 | main
212 | .variable(observer(mutableName))
213 | .define(mutableName, ["Mutable", initialName], (M, _) => new M(_));
214 | main
215 | .variable(observer(cellName))
216 | .define(cellName, [mutableName], _ => _.generator);
217 | } else {
218 | main.redefine(initialName, cellReferences, cellFunction);
219 | main.redefine(
220 | mutableName,
221 | ["Mutable", initialName],
222 | (M, _) => new M(_)
223 | );
224 | main.redefine(cellName, [mutableName], _ => _.generator);
225 | }
226 | } else {
227 | if (define)
228 | main
229 | .variable(observer(cellName))
230 | .define(cellName, cellReferences, cellFunction);
231 | else main.redefine(cellName, cellReferences, cellFunction);
232 | }
233 | }
234 | };
235 | const createModuleDefintion = async (
236 | moduleObject,
237 | resolveModule,
238 | resolveFileAttachments
239 | ) => {
240 | const filteredImportCells = new Set();
241 | const importCells = moduleObject.cells.filter(({ body }) => {
242 | if (
243 | body.type !== "ImportDeclaration" ||
244 | filteredImportCells.has(body.source.value)
245 | )
246 | return false;
247 | filteredImportCells.add(body.source.value);
248 | return true;
249 | });
250 |
251 | const dependencyMap = new Map();
252 | const importCellsPromise = importCells.map(async ({ body }) => {
253 | const fromModule = await resolveModule(body.source.value);
254 | dependencyMap.set(body.source.value, fromModule);
255 | });
256 | await Promise.all(importCellsPromise);
257 |
258 | return function define(runtime, observer) {
259 | const main = runtime.module();
260 | main.builtin(
261 | "FileAttachment",
262 | runtime.fileAttachments(resolveFileAttachments)
263 | );
264 | for (const cell of moduleObject.cells)
265 | createCellDefinition(cell, main, observer, dependencyMap);
266 | };
267 | };
268 |
269 | const ESMImports = (moduleObject, resolvePath) => {
270 | const importMap = new Map();
271 | let importSrc = "";
272 | let j = 0;
273 |
274 | for (const { body } of moduleObject.cells) {
275 | if (body.type !== "ImportDeclaration" || importMap.has(body.source.value))
276 | continue;
277 |
278 | const defineName = `define${++j}`;
279 | const fromPath = resolvePath(body.source.value);
280 | importMap.set(body.source.value, { defineName, fromPath });
281 | importSrc += `import ${defineName} from "${fromPath}";\n`;
282 | }
283 |
284 | if (importSrc.length) importSrc += "\n";
285 | return { importSrc, importMap };
286 | };
287 |
288 | const ESMAttachments = (moduleObject, resolveFileAttachments) => {
289 | const attachmentMapEntries = [];
290 | // loop over cells with fileAttachments
291 | for (const cell of moduleObject.cells) {
292 | if (cell.fileAttachments.size === 0) continue;
293 | // add filenames and resolved URLs to array
294 | for (const file of cell.fileAttachments.keys())
295 | attachmentMapEntries.push([file, resolveFileAttachments(file)]);
296 | }
297 |
298 | return attachmentMapEntries.length === 0
299 | ? ""
300 | : ` const fileAttachments = new Map(${JSON.stringify(
301 | attachmentMapEntries
302 | )});
303 | main.builtin("FileAttachment", runtime.fileAttachments(name => fileAttachments.get(name)));`;
304 | };
305 |
306 | const ESMVariables = (moduleObject, importMap) => {
307 | let childJ = 0;
308 | return moduleObject.cells
309 | .map(cell => {
310 | let src = "";
311 |
312 | if (cell.body.type === "ImportDeclaration") {
313 | const {
314 | specifiers,
315 | hasInjections,
316 | injections,
317 | importString
318 | } = setupImportCell(cell);
319 | // this will display extra names for viewof / mutable imports (for now?)
320 | src +=
321 | ` main.variable(observer()).define(
322 | null,
323 | ["md"],
324 | md => md\`~~~javascript
325 | ${importString}
326 | ~~~\`
327 | );` + "\n";
328 | // name imported notebook define functions
329 | const childName = `child${++childJ}`;
330 | src += ` const ${childName} = runtime.module(${
331 | importMap.get(cell.body.source.value).defineName
332 | })${
333 | hasInjections ? `.derive(${JSON.stringify(injections)}, main)` : ""
334 | };
335 | ${specifiers
336 | .map(
337 | specifier =>
338 | ` main.import("${specifier.name}", "${specifier.alias}", ${childName});`
339 | )
340 | .join("\n")}`;
341 | } else {
342 | const {
343 | cellName,
344 | references,
345 | bodyText,
346 | cellReferences
347 | } = setupRegularCell(cell);
348 |
349 | const cellNameString = cellName ? `"${cellName}"` : "";
350 | const referenceString = references.join(",");
351 | let code = "";
352 | if (cell.body.type !== "BlockStatement")
353 | code = `{return(
354 | ${bodyText}
355 | )}`;
356 | else code = "\n" + bodyText + "\n";
357 | const cellReferencesString = cellReferences.length
358 | ? JSON.stringify(cellReferences) + ", "
359 | : "";
360 | let cellFunction = "";
361 | if (cell.generator && cell.async)
362 | cellFunction = `async function*(${referenceString})${code}`;
363 | else if (cell.async)
364 | cellFunction = `async function(${referenceString})${code}`;
365 | else if (cell.generator)
366 | cellFunction = `function*(${referenceString})${code}`;
367 | else cellFunction = `function(${referenceString})${code}`;
368 |
369 | if (cell.id && cell.id.type === "ViewExpression") {
370 | const reference = `"viewof ${cellName}"`;
371 | src += ` main.variable(observer(${reference})).define(${reference}, ${cellReferencesString}${cellFunction});
372 | main.variable(observer("${cellName}")).define("${cellName}", ["Generators", ${reference}], (G, _) => G.input(_));`;
373 | } else if (cell.id && cell.id.type === "MutableExpression") {
374 | const initialName = `"initial ${cellName}"`;
375 | const mutableName = `"mutable ${cellName}"`;
376 | src += ` main.define(${initialName}, ${cellReferencesString}${cellFunction});
377 | main.variable(observer(${mutableName})).define(${mutableName}, ["Mutable", ${initialName}], (M, _) => new M(_));
378 | main.variable(observer("${cellName}")).define("${cellName}", [${mutableName}], _ => _.generator);`;
379 | } else {
380 | src += ` main.variable(observer(${cellNameString})).define(${
381 | cellName ? cellNameString + ", " : ""
382 | }${cellReferencesString}${cellFunction});`;
383 | }
384 | }
385 | return src;
386 | })
387 | .join("\n");
388 | };
389 | const createESModule = (moduleObject, resolvePath, resolveFileAttachments) => {
390 | const { importSrc, importMap } = ESMImports(moduleObject, resolvePath);
391 | return `${importSrc}export default function define(runtime, observer) {
392 | const main = runtime.module();
393 | ${ESMAttachments(moduleObject, resolveFileAttachments)}
394 | ${ESMVariables(moduleObject, importMap) || ""}
395 | return main;
396 | }`;
397 | };
398 |
399 | const defaultResolver = async path => {
400 | const source = extractPath(path);
401 | return import(`https://api.observablehq.com/${source}.js?v=3`).then(
402 | m => m.default
403 | );
404 | };
405 | const defaultResolvePath = path => {
406 | const source = extractPath(path);
407 | return `https://api.observablehq.com/${source}.js?v=3`;
408 | };
409 |
410 | export class Compiler {
411 | constructor(
412 | resolve = defaultResolver,
413 | resolveFileAttachments = name => name,
414 | resolvePath = defaultResolvePath
415 | ) {
416 | this.resolve = resolve;
417 | this.resolveFileAttachments = resolveFileAttachments;
418 | this.resolvePath = resolvePath;
419 | }
420 | async cell(text) {
421 | const cell = parseCell(text);
422 | cell.input = text;
423 | const dependencyMap = new Map();
424 | if (cell.body.type === "ImportDeclaration") {
425 | const fromModule = await this.resolve(cell.body.source.value);
426 | dependencyMap.set(cell.body.source.value, fromModule);
427 | }
428 | return {
429 | define(module, observer) {
430 | createCellDefinition(cell, module, observer, dependencyMap, true);
431 | },
432 | redefine(module, observer) {
433 | createCellDefinition(cell, module, observer, dependencyMap, false);
434 | }
435 | };
436 | }
437 |
438 | async module(text) {
439 | const m1 = parseModule(text);
440 | return await createModuleDefintion(
441 | m1,
442 | this.resolve,
443 | this.resolveFileAttachments
444 | );
445 | }
446 | async notebook(obj) {
447 | const cells = obj.nodes.map(({ value }) => {
448 | const cell = parseCell(value);
449 | cell.input = value;
450 | return cell;
451 | });
452 | return await createModuleDefintion(
453 | { cells },
454 | this.resolve,
455 | this.resolveFileAttachments
456 | );
457 | }
458 |
459 | moduleToESModule(text) {
460 | const m1 = parseModule(text);
461 | return createESModule(m1, this.resolvePath, this.resolveFileAttachments);
462 | }
463 | notebookToESModule(obj) {
464 | const cells = obj.nodes.map(({ value }) => {
465 | const cell = parseCell(value);
466 | cell.input = value;
467 | return cell;
468 | });
469 | return createESModule(
470 | { cells },
471 | this.resolvePath,
472 | this.resolveFileAttachments
473 | );
474 | }
475 | }
476 |
--------------------------------------------------------------------------------
/yarn.lock:
--------------------------------------------------------------------------------
1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
2 | # yarn lockfile v1
3 |
4 |
5 | "@observablehq/inspector@^3.2.0":
6 | version "3.2.1"
7 | resolved "https://registry.yarnpkg.com/@observablehq/inspector/-/inspector-3.2.1.tgz#c953fd95f1b90fac6f39e41965a72cc079d3e465"
8 | integrity sha512-U8EASUAUYCQmCprOF9HafRMnU4yyD0IXjRuDwAjBMjVpm36KXPzXWxHcdzlt/3CbIEu8GOhKQqHBAX9pv6OyUQ==
9 | dependencies:
10 | esm "^3.2.25"
11 |
12 | "@observablehq/parser@^3.0.0":
13 | version "3.0.0"
14 | resolved "https://registry.yarnpkg.com/@observablehq/parser/-/parser-3.0.0.tgz#6332909fcff5680d994a581b77cadaba765a0d4a"
15 | integrity sha512-BuIfvay+INd2kmUnXNbxYwZ/MnMTYjPEIhns7NuJ9YVIAV+TmxAkZlZdUeCkDpC2XET81BJM8hpOnIzJrqx+1w==
16 | dependencies:
17 | acorn "^7.0.0"
18 | acorn-walk "^7.0.0"
19 |
20 | "@observablehq/runtime@^4.6.4":
21 | version "4.6.4"
22 | resolved "https://registry.yarnpkg.com/@observablehq/runtime/-/runtime-4.6.4.tgz#d90ded08bd9c10110f76d79eb1c4e12ea7fb974d"
23 | integrity sha512-aPiADs8aQfa2ktlZh25ElvRhEZ1WBQ0S/rSfc+aEHCyrtvk+lJ9OMo+FCa01IK4doi6Vkp3xJd2RakbJ6o1hEg==
24 | dependencies:
25 | "@observablehq/inspector" "^3.2.0"
26 | "@observablehq/stdlib" "^3.2.0"
27 | esm "^3.0.84"
28 |
29 | "@observablehq/stdlib@^3.2.0":
30 | version "3.2.1"
31 | resolved "https://registry.yarnpkg.com/@observablehq/stdlib/-/stdlib-3.2.1.tgz#770a5c2a85d4cb281267a07c6a1e8732ec71b374"
32 | integrity sha512-Zsk6C2zccu+71alrv1hyrEfeSaesQ+27KHoDvuuPEdNH9XVC17sHo4HVsBZAroIMBsBjiuFUzuSuiqvD72WX1A==
33 | dependencies:
34 | d3-require "^1.2.4"
35 | marked "https://github.com/observablehq/marked.git#94c6b946f462fd25db4465d71a6859183f86c57f"
36 |
37 | "@types/estree@*", "@types/estree@0.0.39":
38 | version "0.0.39"
39 | resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.39.tgz#e177e699ee1b8c22d23174caaa7422644389509f"
40 | integrity sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==
41 |
42 | "@types/node@*":
43 | version "12.7.5"
44 | resolved "https://registry.yarnpkg.com/@types/node/-/node-12.7.5.tgz#e19436e7f8e9b4601005d73673b6dc4784ffcc2f"
45 | integrity sha512-9fq4jZVhPNW8r+UYKnxF1e2HkDWOWKM5bC2/7c9wPV835I0aOrVbS/Hw/pWPk2uKrNXQqg9Z959Kz+IYDd5p3w==
46 |
47 | "@types/resolve@0.0.8":
48 | version "0.0.8"
49 | resolved "https://registry.yarnpkg.com/@types/resolve/-/resolve-0.0.8.tgz#f26074d238e02659e323ce1a13d041eee280e194"
50 | integrity sha512-auApPaJf3NPfe18hSoJkp8EbZzer2ISk7o8mCC3M9he/a04+gbMF97NkpD2S8riMGvm4BMRI59/SZQSaLTKpsQ==
51 | dependencies:
52 | "@types/node" "*"
53 |
54 | acorn-walk@^7.0.0:
55 | version "7.0.0"
56 | resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-7.0.0.tgz#c8ba6f0f1aac4b0a9e32d1f0af12be769528f36b"
57 | integrity sha512-7Bv1We7ZGuU79zZbb6rRqcpxo3OY+zrdtloZWoyD8fmGX+FeXRjE+iuGkZjSXLVovLzrsvMGMy0EkwA0E0umxg==
58 |
59 | acorn@^7.0.0:
60 | version "7.0.0"
61 | resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.0.0.tgz#26b8d1cd9a9b700350b71c0905546f64d1284e7a"
62 | integrity sha512-PaF/MduxijYYt7unVGRuds1vBC9bFxbNf+VWqhOClfdgy7RlVkQqt610ig1/yxTgsDIfW1cWDel5EBbOy3jdtQ==
63 |
64 | acorn@^7.1.0:
65 | version "7.1.0"
66 | resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.1.0.tgz#949d36f2c292535da602283586c2477c57eb2d6c"
67 | integrity sha512-kL5CuoXA/dgxlBbVrflsflzQ3PAas7RYZB52NOm/6839iVYJgKMJ3cQJD+t2i5+qFa8h3MDpEOJiS64E8JLnSQ==
68 |
69 | async@^1.5.2:
70 | version "1.5.2"
71 | resolved "https://registry.yarnpkg.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a"
72 | integrity sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=
73 |
74 | balanced-match@^1.0.0:
75 | version "1.0.0"
76 | resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767"
77 | integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c=
78 |
79 | brace-expansion@^1.1.7:
80 | version "1.1.11"
81 | resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd"
82 | integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==
83 | dependencies:
84 | balanced-match "^1.0.0"
85 | concat-map "0.0.1"
86 |
87 | builtin-modules@^3.1.0:
88 | version "3.1.0"
89 | resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-3.1.0.tgz#aad97c15131eb76b65b50ef208e7584cd76a7484"
90 | integrity sha512-k0KL0aWZuBt2lrxrcASWDfwOLMnodeQjodT/1SxEQAXsHANgo6ZC/VEaSEHCXt7aSTZ4/4H5LKa+tBXmW7Vtvw==
91 |
92 | colors@1.0.3:
93 | version "1.0.3"
94 | resolved "https://registry.yarnpkg.com/colors/-/colors-1.0.3.tgz#0433f44d809680fdeb60ed260f1b0c262e82a40b"
95 | integrity sha1-BDP0TYCWgP3rYO0mDxsMJi6CpAs=
96 |
97 | concat-map@0.0.1:
98 | version "0.0.1"
99 | resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
100 | integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=
101 |
102 | corser@~2.0.0:
103 | version "2.0.1"
104 | resolved "https://registry.yarnpkg.com/corser/-/corser-2.0.1.tgz#8eda252ecaab5840dcd975ceb90d9370c819ff87"
105 | integrity sha1-jtolLsqrWEDc2XXOuQ2TcMgZ/4c=
106 |
107 | d3-require@^1.2.4:
108 | version "1.2.4"
109 | resolved "https://registry.yarnpkg.com/d3-require/-/d3-require-1.2.4.tgz#59afc591d5089f99fecd8c45ef7539e1fee112b3"
110 | integrity sha512-8UseEGCkBkBxIMouLMPONUBmU8DUPC1q12LARV1Lk/2Jwa32SVgmRfX8GdIeR06ZP+CG85YD3N13K2s14qCNyA==
111 |
112 | debug@^2.2.0:
113 | version "2.6.9"
114 | resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f"
115 | integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==
116 | dependencies:
117 | ms "2.0.0"
118 |
119 | debug@^3.0.0:
120 | version "3.2.6"
121 | resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b"
122 | integrity sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==
123 | dependencies:
124 | ms "^2.1.1"
125 |
126 | deep-equal@~1.0.1:
127 | version "1.0.1"
128 | resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-1.0.1.tgz#f5d260292b660e084eff4cdbc9f08ad3247448b5"
129 | integrity sha1-9dJgKStmDghO/0zbyfCK0yR0SLU=
130 |
131 | define-properties@^1.1.2, define-properties@^1.1.3:
132 | version "1.1.3"
133 | resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1"
134 | integrity sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==
135 | dependencies:
136 | object-keys "^1.0.12"
137 |
138 | defined@~1.0.0:
139 | version "1.0.0"
140 | resolved "https://registry.yarnpkg.com/defined/-/defined-1.0.0.tgz#c98d9bcef75674188e110969151199e39b1fa693"
141 | integrity sha1-yY2bzvdWdBiOEQlpFRGZ45sfppM=
142 |
143 | ecstatic@^3.0.0:
144 | version "3.3.2"
145 | resolved "https://registry.yarnpkg.com/ecstatic/-/ecstatic-3.3.2.tgz#6d1dd49814d00594682c652adb66076a69d46c48"
146 | integrity sha512-fLf9l1hnwrHI2xn9mEDT7KIi22UDqA2jaCwyCbSUJh9a1V+LEUSL/JO/6TIz/QyuBURWUHrFL5Kg2TtO1bkkog==
147 | dependencies:
148 | he "^1.1.1"
149 | mime "^1.6.0"
150 | minimist "^1.1.0"
151 | url-join "^2.0.5"
152 |
153 | es-abstract@^1.5.0:
154 | version "1.14.2"
155 | resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.14.2.tgz#7ce108fad83068c8783c3cdf62e504e084d8c497"
156 | integrity sha512-DgoQmbpFNOofkjJtKwr87Ma5EW4Dc8fWhD0R+ndq7Oc456ivUfGOOP6oAZTTKl5/CcNMP+EN+e3/iUzgE0veZg==
157 | dependencies:
158 | es-to-primitive "^1.2.0"
159 | function-bind "^1.1.1"
160 | has "^1.0.3"
161 | has-symbols "^1.0.0"
162 | is-callable "^1.1.4"
163 | is-regex "^1.0.4"
164 | object-inspect "^1.6.0"
165 | object-keys "^1.1.1"
166 | string.prototype.trimleft "^2.0.0"
167 | string.prototype.trimright "^2.0.0"
168 |
169 | es-to-primitive@^1.2.0:
170 | version "1.2.0"
171 | resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.0.tgz#edf72478033456e8dda8ef09e00ad9650707f377"
172 | integrity sha512-qZryBOJjV//LaxLTV6UC//WewneB3LcXOL9NP++ozKVXsIIIpm/2c13UDiD9Jp2eThsecw9m3jPqDwTyobcdbg==
173 | dependencies:
174 | is-callable "^1.1.4"
175 | is-date-object "^1.0.1"
176 | is-symbol "^1.0.2"
177 |
178 | esm@^3.0.84, esm@^3.2.25:
179 | version "3.2.25"
180 | resolved "https://registry.yarnpkg.com/esm/-/esm-3.2.25.tgz#342c18c29d56157688ba5ce31f8431fbb795cc10"
181 | integrity sha512-U1suiZ2oDVWv4zPO56S0NcR5QriEahGtdN2OR6FiOG4WJvcjBVFB0qI4+eKoWFH483PKGuLuu6V8Z4T5g63UVA==
182 |
183 | estree-walker@^0.6.1:
184 | version "0.6.1"
185 | resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-0.6.1.tgz#53049143f40c6eb918b23671d1fe3219f3a1b362"
186 | integrity sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w==
187 |
188 | eventemitter3@^3.0.0:
189 | version "3.1.2"
190 | resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-3.1.2.tgz#2d3d48f9c346698fce83a85d7d664e98535df6e7"
191 | integrity sha512-tvtQIeLVHjDkJYnzf2dgVMxfuSGJeM/7UCG17TT4EumTfNtF+0nebF/4zWOIkCreAbtNqhGEboB6BWrwqNaw4Q==
192 |
193 | follow-redirects@^1.0.0:
194 | version "1.9.0"
195 | resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.9.0.tgz#8d5bcdc65b7108fe1508649c79c12d732dcedb4f"
196 | integrity sha512-CRcPzsSIbXyVDl0QI01muNDu69S8trU4jArW9LpOt2WtC6LyUJetcIrmfHsRBx7/Jb6GHJUiuqyYxPooFfNt6A==
197 | dependencies:
198 | debug "^3.0.0"
199 |
200 | for-each@~0.3.3:
201 | version "0.3.3"
202 | resolved "https://registry.yarnpkg.com/for-each/-/for-each-0.3.3.tgz#69b447e88a0a5d32c3e7084f3f1710034b21376e"
203 | integrity sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==
204 | dependencies:
205 | is-callable "^1.1.3"
206 |
207 | fs.realpath@^1.0.0:
208 | version "1.0.0"
209 | resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
210 | integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8=
211 |
212 | function-bind@^1.0.2, function-bind@^1.1.1, function-bind@~1.1.1:
213 | version "1.1.1"
214 | resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d"
215 | integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==
216 |
217 | glob@~7.1.4:
218 | version "7.1.4"
219 | resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.4.tgz#aa608a2f6c577ad357e1ae5a5c26d9a8d1969255"
220 | integrity sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==
221 | dependencies:
222 | fs.realpath "^1.0.0"
223 | inflight "^1.0.4"
224 | inherits "2"
225 | minimatch "^3.0.4"
226 | once "^1.3.0"
227 | path-is-absolute "^1.0.0"
228 |
229 | has-symbols@^1.0.0:
230 | version "1.0.0"
231 | resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.0.tgz#ba1a8f1af2a0fc39650f5c850367704122063b44"
232 | integrity sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q=
233 |
234 | has@^1.0.1, has@^1.0.3, has@~1.0.3:
235 | version "1.0.3"
236 | resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796"
237 | integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==
238 | dependencies:
239 | function-bind "^1.1.1"
240 |
241 | he@^1.1.1:
242 | version "1.2.0"
243 | resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f"
244 | integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==
245 |
246 | http-proxy@^1.8.1:
247 | version "1.17.0"
248 | resolved "https://registry.yarnpkg.com/http-proxy/-/http-proxy-1.17.0.tgz#7ad38494658f84605e2f6db4436df410f4e5be9a"
249 | integrity sha512-Taqn+3nNvYRfJ3bGvKfBSRwy1v6eePlm3oc/aWVxZp57DQr5Eq3xhKJi7Z4hZpS8PC3H4qI+Yly5EmFacGuA/g==
250 | dependencies:
251 | eventemitter3 "^3.0.0"
252 | follow-redirects "^1.0.0"
253 | requires-port "^1.0.0"
254 |
255 | http-server@^0.11.1:
256 | version "0.11.1"
257 | resolved "https://registry.yarnpkg.com/http-server/-/http-server-0.11.1.tgz#2302a56a6ffef7f9abea0147d838a5e9b6b6a79b"
258 | integrity sha512-6JeGDGoujJLmhjiRGlt8yK8Z9Kl0vnl/dQoQZlc4oeqaUoAKQg94NILLfrY3oWzSyFaQCVNTcKE5PZ3cH8VP9w==
259 | dependencies:
260 | colors "1.0.3"
261 | corser "~2.0.0"
262 | ecstatic "^3.0.0"
263 | http-proxy "^1.8.1"
264 | opener "~1.4.0"
265 | optimist "0.6.x"
266 | portfinder "^1.0.13"
267 | union "~0.4.3"
268 |
269 | inflight@^1.0.4:
270 | version "1.0.6"
271 | resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9"
272 | integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=
273 | dependencies:
274 | once "^1.3.0"
275 | wrappy "1"
276 |
277 | inherits@2, inherits@~2.0.4:
278 | version "2.0.4"
279 | resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
280 | integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
281 |
282 | is-callable@^1.1.3, is-callable@^1.1.4:
283 | version "1.1.4"
284 | resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.1.4.tgz#1e1adf219e1eeb684d691f9d6a05ff0d30a24d75"
285 | integrity sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA==
286 |
287 | is-date-object@^1.0.1:
288 | version "1.0.1"
289 | resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.1.tgz#9aa20eb6aeebbff77fbd33e74ca01b33581d3a16"
290 | integrity sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY=
291 |
292 | is-module@^1.0.0:
293 | version "1.0.0"
294 | resolved "https://registry.yarnpkg.com/is-module/-/is-module-1.0.0.tgz#3258fb69f78c14d5b815d664336b4cffb6441591"
295 | integrity sha1-Mlj7afeMFNW4FdZkM2tM/7ZEFZE=
296 |
297 | is-reference@^1.1.2:
298 | version "1.1.3"
299 | resolved "https://registry.yarnpkg.com/is-reference/-/is-reference-1.1.3.tgz#e99059204b66fdbe09305cfca715a29caa5c8a51"
300 | integrity sha512-W1iHHv/oyBb2pPxkBxtaewxa1BC58Pn5J0hogyCdefwUIvb6R+TGbAcIa4qPNYLqLhb3EnOgUf2MQkkF76BcKw==
301 | dependencies:
302 | "@types/estree" "0.0.39"
303 |
304 | is-regex@^1.0.4:
305 | version "1.0.4"
306 | resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.0.4.tgz#5517489b547091b0930e095654ced25ee97e9491"
307 | integrity sha1-VRdIm1RwkbCTDglWVM7SXul+lJE=
308 | dependencies:
309 | has "^1.0.1"
310 |
311 | is-symbol@^1.0.2:
312 | version "1.0.2"
313 | resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.2.tgz#a055f6ae57192caee329e7a860118b497a950f38"
314 | integrity sha512-HS8bZ9ox60yCJLH9snBpIwv9pYUAkcuLhSA1oero1UB5y9aiQpRA8y2ex945AOtCZL1lJDeIk3G5LthswI46Lw==
315 | dependencies:
316 | has-symbols "^1.0.0"
317 |
318 | magic-string@^0.25.2:
319 | version "0.25.3"
320 | resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.25.3.tgz#34b8d2a2c7fec9d9bdf9929a3fd81d271ef35be9"
321 | integrity sha512-6QK0OpF/phMz0Q2AxILkX2mFhi7m+WMwTRg0LQKq/WBB0cDP4rYH3Wp4/d3OTXlrPLVJT/RFqj8tFeAR4nk8AA==
322 | dependencies:
323 | sourcemap-codec "^1.4.4"
324 |
325 | "marked@https://github.com/observablehq/marked.git#94c6b946f462fd25db4465d71a6859183f86c57f":
326 | version "0.3.12"
327 | resolved "https://github.com/observablehq/marked.git#94c6b946f462fd25db4465d71a6859183f86c57f"
328 |
329 | mime@^1.6.0:
330 | version "1.6.0"
331 | resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1"
332 | integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==
333 |
334 | minimatch@^3.0.4:
335 | version "3.0.4"
336 | resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083"
337 | integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==
338 | dependencies:
339 | brace-expansion "^1.1.7"
340 |
341 | minimist@0.0.8:
342 | version "0.0.8"
343 | resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d"
344 | integrity sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=
345 |
346 | minimist@^1.1.0, minimist@~1.2.0:
347 | version "1.2.0"
348 | resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284"
349 | integrity sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=
350 |
351 | minimist@~0.0.1:
352 | version "0.0.10"
353 | resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.10.tgz#de3f98543dbf96082be48ad1a0c7cda836301dcf"
354 | integrity sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8=
355 |
356 | mkdirp@0.5.x:
357 | version "0.5.1"
358 | resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903"
359 | integrity sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=
360 | dependencies:
361 | minimist "0.0.8"
362 |
363 | ms@2.0.0:
364 | version "2.0.0"
365 | resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
366 | integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=
367 |
368 | ms@^2.1.1:
369 | version "2.1.2"
370 | resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"
371 | integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==
372 |
373 | object-inspect@^1.6.0, object-inspect@~1.6.0:
374 | version "1.6.0"
375 | resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.6.0.tgz#c70b6cbf72f274aab4c34c0c82f5167bf82cf15b"
376 | integrity sha512-GJzfBZ6DgDAmnuaM3104jR4s1Myxr3Y3zfIyN4z3UdqN69oSRacNK8UhnobDdC+7J2AHCjGwxQubNJfE70SXXQ==
377 |
378 | object-keys@^1.0.12, object-keys@^1.1.1:
379 | version "1.1.1"
380 | resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e"
381 | integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==
382 |
383 | once@^1.3.0:
384 | version "1.4.0"
385 | resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
386 | integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E=
387 | dependencies:
388 | wrappy "1"
389 |
390 | opener@~1.4.0:
391 | version "1.4.3"
392 | resolved "https://registry.yarnpkg.com/opener/-/opener-1.4.3.tgz#5c6da2c5d7e5831e8ffa3964950f8d6674ac90b8"
393 | integrity sha1-XG2ixdflgx6P+jlklQ+NZnSskLg=
394 |
395 | optimist@0.6.x:
396 | version "0.6.1"
397 | resolved "https://registry.yarnpkg.com/optimist/-/optimist-0.6.1.tgz#da3ea74686fa21a19a111c326e90eb15a0196686"
398 | integrity sha1-2j6nRob6IaGaERwybpDrFaAZZoY=
399 | dependencies:
400 | minimist "~0.0.1"
401 | wordwrap "~0.0.2"
402 |
403 | path-is-absolute@^1.0.0:
404 | version "1.0.1"
405 | resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f"
406 | integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18=
407 |
408 | path-parse@^1.0.6:
409 | version "1.0.6"
410 | resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c"
411 | integrity sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==
412 |
413 | portfinder@^1.0.13:
414 | version "1.0.24"
415 | resolved "https://registry.yarnpkg.com/portfinder/-/portfinder-1.0.24.tgz#11efbc6865f12f37624b6531ead1d809ed965cfa"
416 | integrity sha512-ekRl7zD2qxYndYflwiryJwMioBI7LI7rVXg3EnLK3sjkouT5eOuhS3gS255XxBksa30VG8UPZYZCdgfGOfkSUg==
417 | dependencies:
418 | async "^1.5.2"
419 | debug "^2.2.0"
420 | mkdirp "0.5.x"
421 |
422 | prettier@1.19.1:
423 | version "1.19.1"
424 | resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.19.1.tgz#f7d7f5ff8a9cd872a7be4ca142095956a60797cb"
425 | integrity sha512-s7PoyDv/II1ObgQunCbB9PdLmUcBZcnWOcxDh7O0N/UwDEsHyqkW+Qh28jW+mVuCdx7gLB0BotYI1Y6uI9iyew==
426 |
427 | qs@~2.3.3:
428 | version "2.3.3"
429 | resolved "https://registry.yarnpkg.com/qs/-/qs-2.3.3.tgz#e9e85adbe75da0bbe4c8e0476a086290f863b404"
430 | integrity sha1-6eha2+ddoLvkyOBHaghikPhjtAQ=
431 |
432 | requires-port@^1.0.0:
433 | version "1.0.0"
434 | resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff"
435 | integrity sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=
436 |
437 | resolve@^1.11.0, resolve@^1.11.1:
438 | version "1.12.0"
439 | resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.12.0.tgz#3fc644a35c84a48554609ff26ec52b66fa577df6"
440 | integrity sha512-B/dOmuoAik5bKcD6s6nXDCjzUKnaDvdkRyAk6rsmsKLipWj4797iothd7jmmUhWTfinVMU+wc56rYKsit2Qy4w==
441 | dependencies:
442 | path-parse "^1.0.6"
443 |
444 | resolve@~1.11.1:
445 | version "1.11.1"
446 | resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.11.1.tgz#ea10d8110376982fef578df8fc30b9ac30a07a3e"
447 | integrity sha512-vIpgF6wfuJOZI7KKKSP+HmiKggadPQAdsp5HiC1mvqnfp0gF1vdwgBWZIdrVft9pgqoMFQN+R7BSWZiBxx+BBw==
448 | dependencies:
449 | path-parse "^1.0.6"
450 |
451 | resumer@~0.0.0:
452 | version "0.0.0"
453 | resolved "https://registry.yarnpkg.com/resumer/-/resumer-0.0.0.tgz#f1e8f461e4064ba39e82af3cdc2a8c893d076759"
454 | integrity sha1-8ej0YeQGS6Oegq883CqMiT0HZ1k=
455 | dependencies:
456 | through "~2.3.4"
457 |
458 | rollup-plugin-commonjs@^10.1.0:
459 | version "10.1.0"
460 | resolved "https://registry.yarnpkg.com/rollup-plugin-commonjs/-/rollup-plugin-commonjs-10.1.0.tgz#417af3b54503878e084d127adf4d1caf8beb86fb"
461 | integrity sha512-jlXbjZSQg8EIeAAvepNwhJj++qJWNJw1Cl0YnOqKtP5Djx+fFGkp3WRh+W0ASCaFG5w1jhmzDxgu3SJuVxPF4Q==
462 | dependencies:
463 | estree-walker "^0.6.1"
464 | is-reference "^1.1.2"
465 | magic-string "^0.25.2"
466 | resolve "^1.11.0"
467 | rollup-pluginutils "^2.8.1"
468 |
469 | rollup-plugin-node-resolve@^5.2.0:
470 | version "5.2.0"
471 | resolved "https://registry.yarnpkg.com/rollup-plugin-node-resolve/-/rollup-plugin-node-resolve-5.2.0.tgz#730f93d10ed202473b1fb54a5997a7db8c6d8523"
472 | integrity sha512-jUlyaDXts7TW2CqQ4GaO5VJ4PwwaV8VUGA7+km3n6k6xtOEacf61u0VXwN80phY/evMcaS+9eIeJ9MOyDxt5Zw==
473 | dependencies:
474 | "@types/resolve" "0.0.8"
475 | builtin-modules "^3.1.0"
476 | is-module "^1.0.0"
477 | resolve "^1.11.1"
478 | rollup-pluginutils "^2.8.1"
479 |
480 | rollup-pluginutils@^2.8.1:
481 | version "2.8.1"
482 | resolved "https://registry.yarnpkg.com/rollup-pluginutils/-/rollup-pluginutils-2.8.1.tgz#8fa6dd0697344938ef26c2c09d2488ce9e33ce97"
483 | integrity sha512-J5oAoysWar6GuZo0s+3bZ6sVZAC0pfqKz68De7ZgDi5z63jOVZn1uJL/+z1jeKHNbGII8kAyHF5q8LnxSX5lQg==
484 | dependencies:
485 | estree-walker "^0.6.1"
486 |
487 | rollup@^1.26.4:
488 | version "1.27.0"
489 | resolved "https://registry.yarnpkg.com/rollup/-/rollup-1.27.0.tgz#7afe0da89c967cec5ccea7e919da6c89a1a68666"
490 | integrity sha512-yaMna4MJ8LLEHhHl1ilgHakylf0LKeQctDxhngZLQ+W57GnXa5vtH7XKaK8zlAhNEhlWiH5YFVFt+QCDPUmNkw==
491 | dependencies:
492 | "@types/estree" "*"
493 | "@types/node" "*"
494 | acorn "^7.1.0"
495 |
496 | sourcemap-codec@^1.4.4:
497 | version "1.4.6"
498 | resolved "https://registry.yarnpkg.com/sourcemap-codec/-/sourcemap-codec-1.4.6.tgz#e30a74f0402bad09807640d39e971090a08ce1e9"
499 | integrity sha512-1ZooVLYFxC448piVLBbtOxFcXwnymH9oUF8nRd3CuYDVvkRBxRl6pB4Mtas5a4drtL+E8LDgFkQNcgIw6tc8Hg==
500 |
501 | string.prototype.trim@~1.1.2:
502 | version "1.1.2"
503 | resolved "https://registry.yarnpkg.com/string.prototype.trim/-/string.prototype.trim-1.1.2.tgz#d04de2c89e137f4d7d206f086b5ed2fae6be8cea"
504 | integrity sha1-0E3iyJ4Tf019IG8Ia17S+ua+jOo=
505 | dependencies:
506 | define-properties "^1.1.2"
507 | es-abstract "^1.5.0"
508 | function-bind "^1.0.2"
509 |
510 | string.prototype.trimleft@^2.0.0:
511 | version "2.1.0"
512 | resolved "https://registry.yarnpkg.com/string.prototype.trimleft/-/string.prototype.trimleft-2.1.0.tgz#6cc47f0d7eb8d62b0f3701611715a3954591d634"
513 | integrity sha512-FJ6b7EgdKxxbDxc79cOlok6Afd++TTs5szo+zJTUyow3ycrRfJVE2pq3vcN53XexvKZu/DJMDfeI/qMiZTrjTw==
514 | dependencies:
515 | define-properties "^1.1.3"
516 | function-bind "^1.1.1"
517 |
518 | string.prototype.trimright@^2.0.0:
519 | version "2.1.0"
520 | resolved "https://registry.yarnpkg.com/string.prototype.trimright/-/string.prototype.trimright-2.1.0.tgz#669d164be9df9b6f7559fa8e89945b168a5a6c58"
521 | integrity sha512-fXZTSV55dNBwv16uw+hh5jkghxSnc5oHq+5K/gXgizHwAvMetdAJlHqqoFC1FSDVPYWLkAKl2cxpUT41sV7nSg==
522 | dependencies:
523 | define-properties "^1.1.3"
524 | function-bind "^1.1.1"
525 |
526 | tape@^4.11.0:
527 | version "4.11.0"
528 | resolved "https://registry.yarnpkg.com/tape/-/tape-4.11.0.tgz#63d41accd95e45a23a874473051c57fdbc58edc1"
529 | integrity sha512-yixvDMX7q7JIs/omJSzSZrqulOV51EC9dK8dM0TzImTIkHWfe2/kFyL5v+d9C+SrCMaICk59ujsqFAVidDqDaA==
530 | dependencies:
531 | deep-equal "~1.0.1"
532 | defined "~1.0.0"
533 | for-each "~0.3.3"
534 | function-bind "~1.1.1"
535 | glob "~7.1.4"
536 | has "~1.0.3"
537 | inherits "~2.0.4"
538 | minimist "~1.2.0"
539 | object-inspect "~1.6.0"
540 | resolve "~1.11.1"
541 | resumer "~0.0.0"
542 | string.prototype.trim "~1.1.2"
543 | through "~2.3.8"
544 |
545 | through@~2.3.4, through@~2.3.8:
546 | version "2.3.8"
547 | resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5"
548 | integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=
549 |
550 | union@~0.4.3:
551 | version "0.4.6"
552 | resolved "https://registry.yarnpkg.com/union/-/union-0.4.6.tgz#198fbdaeba254e788b0efcb630bc11f24a2959e0"
553 | integrity sha1-GY+9rrolTniLDvy2MLwR8kopWeA=
554 | dependencies:
555 | qs "~2.3.3"
556 |
557 | url-join@^2.0.5:
558 | version "2.0.5"
559 | resolved "https://registry.yarnpkg.com/url-join/-/url-join-2.0.5.tgz#5af22f18c052a000a48d7b82c5e9c2e2feeda728"
560 | integrity sha1-WvIvGMBSoACkjXuCxenC4v7tpyg=
561 |
562 | wordwrap@~0.0.2:
563 | version "0.0.3"
564 | resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.3.tgz#a3d5da6cd5c0bc0008d37234bbaf1bed63059107"
565 | integrity sha1-o9XabNXAvAAI03I0u68b7WMFkQc=
566 |
567 | wrappy@1:
568 | version "1.0.2"
569 | resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
570 | integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=
571 |
--------------------------------------------------------------------------------