@observablehq/notebook-kit 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +13 -0
- package/README.md +7 -0
- package/dist/bin/build.d.ts +2 -0
- package/dist/bin/build.js +63 -0
- package/dist/bin/download.d.ts +2 -0
- package/dist/bin/download.js +49 -0
- package/dist/bin/notebooks.d.ts +2 -0
- package/dist/bin/notebooks.js +33 -0
- package/dist/bin/preview.d.ts +2 -0
- package/dist/bin/preview.js +48 -0
- package/dist/package.json +73 -0
- package/dist/src/index.d.ts +5 -0
- package/dist/src/index.js +5 -0
- package/dist/src/javascript/assignments.d.ts +2 -0
- package/dist/src/javascript/assignments.js +37 -0
- package/dist/src/javascript/assignments.test.d.ts +1 -0
- package/dist/src/javascript/assignments.test.js +33 -0
- package/dist/src/javascript/awaits.d.ts +2 -0
- package/dist/src/javascript/awaits.js +23 -0
- package/dist/src/javascript/awaits.test.d.ts +1 -0
- package/dist/src/javascript/awaits.test.js +22 -0
- package/dist/src/javascript/declarations.d.ts +2 -0
- package/dist/src/javascript/declarations.js +45 -0
- package/dist/src/javascript/files.d.ts +3 -0
- package/dist/src/javascript/files.js +18 -0
- package/dist/src/javascript/globals.d.ts +1 -0
- package/dist/src/javascript/globals.js +86 -0
- package/dist/src/javascript/imports/jsr.d.ts +2 -0
- package/dist/src/javascript/imports/jsr.js +6 -0
- package/dist/src/javascript/imports/npm.d.ts +2 -0
- package/dist/src/javascript/imports/npm.js +47 -0
- package/dist/src/javascript/imports/npm.test.d.ts +1 -0
- package/dist/src/javascript/imports/npm.test.js +32 -0
- package/dist/src/javascript/imports/observable.d.ts +8 -0
- package/dist/src/javascript/imports/observable.js +64 -0
- package/dist/src/javascript/imports/observable.test.d.ts +1 -0
- package/dist/src/javascript/imports/observable.test.js +13 -0
- package/dist/src/javascript/imports.d.ts +21 -0
- package/dist/src/javascript/imports.js +146 -0
- package/dist/src/javascript/observable.d.ts +2 -0
- package/dist/src/javascript/observable.js +72 -0
- package/dist/src/javascript/parse.d.ts +11 -0
- package/dist/src/javascript/parse.js +53 -0
- package/dist/src/javascript/references.d.ts +8 -0
- package/dist/src/javascript/references.js +129 -0
- package/dist/src/javascript/references.test.d.ts +1 -0
- package/dist/src/javascript/references.test.js +38 -0
- package/dist/src/javascript/sourcemap.d.ts +21 -0
- package/dist/src/javascript/sourcemap.js +143 -0
- package/dist/src/javascript/sourcemap.test.d.ts +1 -0
- package/dist/src/javascript/sourcemap.test.js +88 -0
- package/dist/src/javascript/strings.d.ts +8 -0
- package/dist/src/javascript/strings.js +42 -0
- package/dist/src/javascript/strings.test.d.ts +1 -0
- package/dist/src/javascript/strings.test.js +31 -0
- package/dist/src/javascript/syntaxError.d.ts +2 -0
- package/dist/src/javascript/syntaxError.js +5 -0
- package/dist/src/javascript/template.d.ts +3 -0
- package/dist/src/javascript/template.js +141 -0
- package/dist/src/javascript/template.test.d.ts +1 -0
- package/dist/src/javascript/template.test.js +32 -0
- package/dist/src/javascript/transpile.d.ts +25 -0
- package/dist/src/javascript/transpile.js +42 -0
- package/dist/src/javascript/transpile.test.d.ts +1 -0
- package/dist/src/javascript/transpile.test.js +29 -0
- package/dist/src/javascript/walk.d.ts +5 -0
- package/dist/src/javascript/walk.js +13 -0
- package/dist/src/lib/notebook.d.ts +35 -0
- package/dist/src/lib/notebook.js +19 -0
- package/dist/src/lib/notebook.test.d.ts +1 -0
- package/dist/src/lib/notebook.test.js +26 -0
- package/dist/src/lib/serialize.d.ts +5 -0
- package/dist/src/lib/serialize.js +97 -0
- package/dist/src/lib/serialize.test.d.ts +1 -0
- package/dist/src/lib/serialize.test.js +125 -0
- package/dist/src/lib/text.d.ts +1 -0
- package/dist/src/lib/text.js +3 -0
- package/dist/src/runtime/define.d.ts +28 -0
- package/dist/src/runtime/define.js +62 -0
- package/dist/src/runtime/display.d.ts +16 -0
- package/dist/src/runtime/display.js +60 -0
- package/dist/src/runtime/index.d.ts +11 -0
- package/dist/src/runtime/index.js +14 -0
- package/dist/src/runtime/inspect.d.ts +3 -0
- package/dist/src/runtime/inspect.js +43 -0
- package/dist/src/runtime/stdlib/assets.d.ts +4 -0
- package/dist/src/runtime/stdlib/assets.js +110 -0
- package/dist/src/runtime/stdlib/assets.test.d.ts +1 -0
- package/dist/src/runtime/stdlib/assets.test.js +78 -0
- package/dist/src/runtime/stdlib/dom/canvas.d.ts +1 -0
- package/dist/src/runtime/stdlib/dom/canvas.js +6 -0
- package/dist/src/runtime/stdlib/dom/context2d.d.ts +1 -0
- package/dist/src/runtime/stdlib/dom/context2d.js +9 -0
- package/dist/src/runtime/stdlib/dom/index.d.ts +5 -0
- package/dist/src/runtime/stdlib/dom/index.js +5 -0
- package/dist/src/runtime/stdlib/dom/svg.d.ts +1 -0
- package/dist/src/runtime/stdlib/dom/svg.js +7 -0
- package/dist/src/runtime/stdlib/dom/text.d.ts +1 -0
- package/dist/src/runtime/stdlib/dom/text.js +3 -0
- package/dist/src/runtime/stdlib/dom/uid.d.ts +8 -0
- package/dist/src/runtime/stdlib/dom/uid.js +25 -0
- package/dist/src/runtime/stdlib/dot.d.ts +2 -0
- package/dist/src/runtime/stdlib/dot.js +34 -0
- package/dist/src/runtime/stdlib/duckdb.d.ts +24 -0
- package/dist/src/runtime/stdlib/duckdb.js +379 -0
- package/dist/src/runtime/stdlib/fileAttachment.d.ts +71 -0
- package/dist/src/runtime/stdlib/fileAttachment.js +199 -0
- package/dist/src/runtime/stdlib/generators/index.d.ts +5 -0
- package/dist/src/runtime/stdlib/generators/index.js +5 -0
- package/dist/src/runtime/stdlib/generators/input.d.ts +1 -0
- package/dist/src/runtime/stdlib/generators/input.js +45 -0
- package/dist/src/runtime/stdlib/generators/now.d.ts +1 -0
- package/dist/src/runtime/stdlib/generators/now.js +5 -0
- package/dist/src/runtime/stdlib/generators/observe.d.ts +1 -0
- package/dist/src/runtime/stdlib/generators/observe.js +31 -0
- package/dist/src/runtime/stdlib/generators/queue.d.ts +1 -0
- package/dist/src/runtime/stdlib/generators/queue.js +27 -0
- package/dist/src/runtime/stdlib/generators/width.d.ts +1 -0
- package/dist/src/runtime/stdlib/generators/width.js +13 -0
- package/dist/src/runtime/stdlib/highlight.d.ts +2 -0
- package/dist/src/runtime/stdlib/highlight.js +76 -0
- package/dist/src/runtime/stdlib/index.d.ts +56 -0
- package/dist/src/runtime/stdlib/index.js +23 -0
- package/dist/src/runtime/stdlib/inputs.css +15 -0
- package/dist/src/runtime/stdlib/inputs.d.ts +2 -0
- package/dist/src/runtime/stdlib/inputs.js +2 -0
- package/dist/src/runtime/stdlib/leaflet.d.ts +1 -0
- package/dist/src/runtime/stdlib/leaflet.js +7 -0
- package/dist/src/runtime/stdlib/mapboxgl.d.ts +1 -0
- package/dist/src/runtime/stdlib/mapboxgl.js +5 -0
- package/dist/src/runtime/stdlib/md.d.ts +5 -0
- package/dist/src/runtime/stdlib/md.js +72 -0
- package/dist/src/runtime/stdlib/mermaid.d.ts +2 -0
- package/dist/src/runtime/stdlib/mermaid.js +11 -0
- package/dist/src/runtime/stdlib/mutable.d.ts +8 -0
- package/dist/src/runtime/stdlib/mutable.js +30 -0
- package/dist/src/runtime/stdlib/observer.d.ts +16 -0
- package/dist/src/runtime/stdlib/observer.js +42 -0
- package/dist/src/runtime/stdlib/recommendedLibraries.d.ts +25 -0
- package/dist/src/runtime/stdlib/recommendedLibraries.js +26 -0
- package/dist/src/runtime/stdlib/require.d.ts +4 -0
- package/dist/src/runtime/stdlib/require.js +40 -0
- package/dist/src/runtime/stdlib/sampleDatasets.d.ts +12 -0
- package/dist/src/runtime/stdlib/sampleDatasets.js +31 -0
- package/dist/src/runtime/stdlib/sql.d.ts +5 -0
- package/dist/src/runtime/stdlib/sql.js +5 -0
- package/dist/src/runtime/stdlib/template.d.ts +7 -0
- package/dist/src/runtime/stdlib/template.js +2 -0
- package/dist/src/runtime/stdlib/tex.d.ts +7 -0
- package/dist/src/runtime/stdlib/tex.js +18 -0
- package/dist/src/runtime/stdlib/vega-lite.d.ts +1 -0
- package/dist/src/runtime/stdlib/vega-lite.js +4 -0
- package/dist/src/styles/abstract-dark.css +14 -0
- package/dist/src/styles/abstract-light.css +14 -0
- package/dist/src/styles/global.css +266 -0
- package/dist/src/styles/highlight.css +47 -0
- package/dist/src/styles/index.css +14 -0
- package/dist/src/styles/inspector.css +89 -0
- package/dist/src/styles/plot.css +7 -0
- package/dist/src/styles/syntax-dark.css +12 -0
- package/dist/src/styles/syntax-light.css +12 -0
- package/dist/src/styles/theme-air.css +7 -0
- package/dist/src/styles/theme-coffee.css +7 -0
- package/dist/src/styles/theme-cotton.css +7 -0
- package/dist/src/styles/theme-deep-space.css +16 -0
- package/dist/src/styles/theme-glacier.css +7 -0
- package/dist/src/styles/theme-ink.css +7 -0
- package/dist/src/styles/theme-midnight.css +7 -0
- package/dist/src/styles/theme-near-midnight.css +7 -0
- package/dist/src/styles/theme-ocean-floor.css +7 -0
- package/dist/src/styles/theme-parchment.css +7 -0
- package/dist/src/styles/theme-slate.css +7 -0
- package/dist/src/styles/theme-stark.css +16 -0
- package/dist/src/styles/theme-sun-faded.css +7 -0
- package/dist/src/templates/default.html +31 -0
- package/dist/src/vite/config.d.ts +2 -0
- package/dist/src/vite/config.js +30 -0
- package/dist/src/vite/index.d.ts +2 -0
- package/dist/src/vite/index.js +2 -0
- package/dist/src/vite/observable.d.ts +12 -0
- package/dist/src/vite/observable.js +176 -0
- package/package.json +73 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
Copyright 2025 Observable, Inc.
|
|
2
|
+
|
|
3
|
+
Permission to use, copy, modify, and/or distribute this software for any purpose
|
|
4
|
+
with or without fee is hereby granted, provided that the above copyright notice
|
|
5
|
+
and this permission notice appear in all copies.
|
|
6
|
+
|
|
7
|
+
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
|
8
|
+
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
|
9
|
+
FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
|
10
|
+
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
|
|
11
|
+
OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
|
12
|
+
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
|
|
13
|
+
THIS SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
# Observable Notebook Kit
|
|
2
|
+
|
|
3
|
+
**Observable Notebook Kit** is an open-source command-line tool for building static sites from Observable Notebooks based on an open file format. Notebook Kit also includes a Vite plugin and a low-level JavaScript interface for deep integration of Observable Notebooks with custom web applications.
|
|
4
|
+
|
|
5
|
+
Notebook Kit is available as part of [Notebooks 2.0 Technology Preview](https://observablehq.com/notebook-kit/), which includes [Observable Desktop](https://observablehq.com/notebook-kit/desktop), a notebook editor for macOS.
|
|
6
|
+
|
|
7
|
+
For more, [see the documentation](https://observablehq.com/notebook-kit/kit).
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { parseArgs } from "node:util";
|
|
3
|
+
import { build } from "vite";
|
|
4
|
+
import { config, observable } from "../src/vite/index.js";
|
|
5
|
+
if (process.argv[1] === import.meta.filename)
|
|
6
|
+
run();
|
|
7
|
+
export default async function run(args) {
|
|
8
|
+
const { values, positionals } = parseArgs({
|
|
9
|
+
args,
|
|
10
|
+
allowNegative: true,
|
|
11
|
+
allowPositionals: true,
|
|
12
|
+
options: {
|
|
13
|
+
out: {
|
|
14
|
+
type: "string",
|
|
15
|
+
short: "o",
|
|
16
|
+
default: ".observable/dist"
|
|
17
|
+
},
|
|
18
|
+
root: {
|
|
19
|
+
type: "string",
|
|
20
|
+
default: "."
|
|
21
|
+
},
|
|
22
|
+
base: {
|
|
23
|
+
type: "string",
|
|
24
|
+
default: "./"
|
|
25
|
+
},
|
|
26
|
+
template: {
|
|
27
|
+
type: "string"
|
|
28
|
+
},
|
|
29
|
+
empty: {
|
|
30
|
+
type: "boolean"
|
|
31
|
+
},
|
|
32
|
+
help: {
|
|
33
|
+
type: "boolean",
|
|
34
|
+
short: "h"
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
});
|
|
38
|
+
if (values.help) {
|
|
39
|
+
console.log(`usage: notebooks build [files]
|
|
40
|
+
|
|
41
|
+
--root <dir> path to the root directory; defaults to cwd
|
|
42
|
+
--template <path> path to the HTML template
|
|
43
|
+
-o, --out <dir> path to the output directory (relative to root)
|
|
44
|
+
--base <path> serving base path; defaults to ./
|
|
45
|
+
--empty whether to empty the output directory before building
|
|
46
|
+
-h, --help show this message
|
|
47
|
+
`);
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
await build({
|
|
51
|
+
...config(),
|
|
52
|
+
plugins: [observable({ template: values.template })],
|
|
53
|
+
root: values.root,
|
|
54
|
+
base: values.base,
|
|
55
|
+
build: {
|
|
56
|
+
outDir: values.out,
|
|
57
|
+
emptyOutDir: values.empty,
|
|
58
|
+
rollupOptions: {
|
|
59
|
+
input: positionals
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { parseArgs } from "node:util";
|
|
3
|
+
import { JSDOM } from "jsdom";
|
|
4
|
+
import { toNotebook } from "../src/lib/notebook.js";
|
|
5
|
+
import { serialize } from "../src/lib/serialize.js";
|
|
6
|
+
if (process.argv[1] === import.meta.filename)
|
|
7
|
+
run();
|
|
8
|
+
export default async function run(args) {
|
|
9
|
+
const { values, positionals } = parseArgs({
|
|
10
|
+
args,
|
|
11
|
+
allowPositionals: true,
|
|
12
|
+
options: {
|
|
13
|
+
help: {
|
|
14
|
+
type: "boolean",
|
|
15
|
+
short: "h"
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
});
|
|
19
|
+
if (positionals.length !== 1 && !values.help)
|
|
20
|
+
throw new Error("missing <url>");
|
|
21
|
+
if (values.help) {
|
|
22
|
+
console.log(`usage: notebooks download <url>
|
|
23
|
+
|
|
24
|
+
-h, --help show this message
|
|
25
|
+
`);
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
const globalDocument = globalThis.document;
|
|
29
|
+
globalThis.document = new JSDOM().window.document;
|
|
30
|
+
try {
|
|
31
|
+
for (const positional of positionals) {
|
|
32
|
+
let url = new URL(positional, "https://observablehq.com");
|
|
33
|
+
if (url.origin === "https://observablehq.com") {
|
|
34
|
+
url = new URL(`/document${url.pathname.replace(/^\/d\//, "/")}`, "https://api.observablehq.com");
|
|
35
|
+
}
|
|
36
|
+
const response = await fetch(url);
|
|
37
|
+
if (!response.ok)
|
|
38
|
+
throw new Error(`unable to fetch: ${url}`);
|
|
39
|
+
const { title, nodes } = await response.json();
|
|
40
|
+
for (const node of nodes)
|
|
41
|
+
if (node.mode === "js")
|
|
42
|
+
node.mode = "ojs";
|
|
43
|
+
process.stdout.write(serialize(toNotebook({ title, cells: nodes })));
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
finally {
|
|
47
|
+
globalThis.document = globalDocument;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
const [, , command] = process.argv;
|
|
3
|
+
switch (command) {
|
|
4
|
+
case "build": {
|
|
5
|
+
const { default: run } = await import("./build.js");
|
|
6
|
+
await run(process.argv.slice(3));
|
|
7
|
+
break;
|
|
8
|
+
}
|
|
9
|
+
case "download": {
|
|
10
|
+
const { default: run } = await import("./download.js");
|
|
11
|
+
await run(process.argv.slice(3));
|
|
12
|
+
break;
|
|
13
|
+
}
|
|
14
|
+
case "preview": {
|
|
15
|
+
const { default: run } = await import("./preview.js");
|
|
16
|
+
await run(process.argv.slice(3));
|
|
17
|
+
break;
|
|
18
|
+
}
|
|
19
|
+
default: {
|
|
20
|
+
console.log(`usage: notebooks <command>
|
|
21
|
+
|
|
22
|
+
preview start the preview server
|
|
23
|
+
build generate a static site
|
|
24
|
+
download download an Observable Notebook as HTML
|
|
25
|
+
help print usage information
|
|
26
|
+
version print the version
|
|
27
|
+
`);
|
|
28
|
+
if (command !== "help")
|
|
29
|
+
process.exit(1);
|
|
30
|
+
break;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
export {};
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { parseArgs } from "node:util";
|
|
3
|
+
import { createServer } from "vite";
|
|
4
|
+
import { config, observable } from "../src/vite/index.js";
|
|
5
|
+
if (process.argv[1] === import.meta.filename)
|
|
6
|
+
run();
|
|
7
|
+
export default async function run(args) {
|
|
8
|
+
const { values } = parseArgs({
|
|
9
|
+
args,
|
|
10
|
+
allowNegative: true,
|
|
11
|
+
options: {
|
|
12
|
+
root: {
|
|
13
|
+
type: "string",
|
|
14
|
+
default: "."
|
|
15
|
+
},
|
|
16
|
+
base: {
|
|
17
|
+
type: "string",
|
|
18
|
+
default: "/"
|
|
19
|
+
},
|
|
20
|
+
template: {
|
|
21
|
+
type: "string"
|
|
22
|
+
},
|
|
23
|
+
help: {
|
|
24
|
+
type: "boolean",
|
|
25
|
+
short: "h"
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
if (values.help) {
|
|
30
|
+
console.log(`usage: notebooks preview
|
|
31
|
+
|
|
32
|
+
--root <dir> path to the root directory; defaults to cwd
|
|
33
|
+
--template <path> path to the HTML template
|
|
34
|
+
--base <path> serving base path; defaults to /
|
|
35
|
+
-h, --help show this message
|
|
36
|
+
`);
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
const server = await createServer({
|
|
40
|
+
...config(),
|
|
41
|
+
plugins: [observable({ template: values.template })],
|
|
42
|
+
root: values.root,
|
|
43
|
+
base: values.base
|
|
44
|
+
});
|
|
45
|
+
await server.listen();
|
|
46
|
+
server.printUrls();
|
|
47
|
+
server.bindCLIShortcuts({ print: true });
|
|
48
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@observablehq/notebook-kit",
|
|
3
|
+
"license": "ISC",
|
|
4
|
+
"repository": {
|
|
5
|
+
"type": "git",
|
|
6
|
+
"url": "git+https://github.com/observablehq/notebook-kit.git"
|
|
7
|
+
},
|
|
8
|
+
"version": "1.0.0",
|
|
9
|
+
"type": "module",
|
|
10
|
+
"scripts": {
|
|
11
|
+
"test": "vitest",
|
|
12
|
+
"prepublishOnly": "rm -rf dist && tsc && chmod +x dist/bin/*.js && cp -r src/styles src/templates dist/src && cp src/runtime/stdlib/*.css dist/src/runtime/stdlib",
|
|
13
|
+
"lint": "tsc --noEmit && eslint bin src types",
|
|
14
|
+
"notebooks": "tsx bin/notebooks.ts",
|
|
15
|
+
"download": "tsx bin/notebooks.ts download",
|
|
16
|
+
"docs:preview": "tsx --watch bin/notebooks.ts preview --root docs --template docs/observable.tmpl",
|
|
17
|
+
"docs:build": "tsx bin/notebooks.ts build --root docs --template docs/observable.tmpl -- $(find docs -path 'docs/.observable' -prune -o -name '*.html' -print)"
|
|
18
|
+
},
|
|
19
|
+
"bin": {
|
|
20
|
+
"notebooks": "dist/bin/notebooks.js"
|
|
21
|
+
},
|
|
22
|
+
"files": [
|
|
23
|
+
"dist"
|
|
24
|
+
],
|
|
25
|
+
"exports": {
|
|
26
|
+
".": {
|
|
27
|
+
"types": "./dist/src/index.d.ts",
|
|
28
|
+
"import": "./dist/src/index.js"
|
|
29
|
+
},
|
|
30
|
+
"./runtime": {
|
|
31
|
+
"types": "./dist/src/runtime/index.d.ts",
|
|
32
|
+
"import": "./dist/src/runtime/index.js"
|
|
33
|
+
},
|
|
34
|
+
"./vite": {
|
|
35
|
+
"types": "./dist/src/vite/index.d.ts",
|
|
36
|
+
"import": "./dist/src/vite/index.js"
|
|
37
|
+
},
|
|
38
|
+
"./*.css": "./dist/src/styles/*.css"
|
|
39
|
+
},
|
|
40
|
+
"dependencies": {
|
|
41
|
+
"@fontsource/inter": "^5.2.6",
|
|
42
|
+
"@fontsource/source-serif-4": "^5.2.8",
|
|
43
|
+
"@fontsource/spline-sans-mono": "^5.2.6",
|
|
44
|
+
"@lezer/common": "^1.2.3",
|
|
45
|
+
"@lezer/css": "^1.2.1",
|
|
46
|
+
"@lezer/highlight": "^1.2.1",
|
|
47
|
+
"@lezer/html": "^1.3.10",
|
|
48
|
+
"@lezer/javascript": "^1.5.1",
|
|
49
|
+
"@lezer/markdown": "^1.4.3",
|
|
50
|
+
"@observablehq/inspector": "^5.0.1",
|
|
51
|
+
"@observablehq/parser": "^6.1.0",
|
|
52
|
+
"@observablehq/runtime": "^6.0.0",
|
|
53
|
+
"@sindresorhus/slugify": "^2.2.1",
|
|
54
|
+
"acorn": "^8.15.0",
|
|
55
|
+
"acorn-walk": "^8.3.4",
|
|
56
|
+
"markdown-it": "^14.1.0",
|
|
57
|
+
"markdown-it-anchor": "^9.2.0",
|
|
58
|
+
"vite": "^7.0.0"
|
|
59
|
+
},
|
|
60
|
+
"devDependencies": {
|
|
61
|
+
"@eslint/js": "^9.29.0",
|
|
62
|
+
"@types/jsdom": "^21.1.7",
|
|
63
|
+
"@types/markdown-it": "^14.1.2",
|
|
64
|
+
"eslint": "^9.29.0",
|
|
65
|
+
"globals": "^16.2.0",
|
|
66
|
+
"htl": "^0.3.1",
|
|
67
|
+
"jsdom": "^26.1.0",
|
|
68
|
+
"tsx": "^4.20.3",
|
|
69
|
+
"typescript": "^5.8.3",
|
|
70
|
+
"typescript-eslint": "^8.35.0",
|
|
71
|
+
"vitest": "^3.2.4"
|
|
72
|
+
}
|
|
73
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { defaultGlobals } from "./globals.js";
|
|
2
|
+
import { syntaxError } from "./syntaxError.js";
|
|
3
|
+
import { simple } from "./walk.js";
|
|
4
|
+
export function checkAssignments(node, references, input) {
|
|
5
|
+
function checkConst(node) {
|
|
6
|
+
switch (node.type) {
|
|
7
|
+
case "Identifier":
|
|
8
|
+
if (references.includes(node))
|
|
9
|
+
throw syntaxError(`Assignment to external variable '${node.name}'`, node, input);
|
|
10
|
+
if (defaultGlobals.has(node.name))
|
|
11
|
+
throw syntaxError(`Assignment to global '${node.name}'`, node, input);
|
|
12
|
+
break;
|
|
13
|
+
case "ObjectPattern":
|
|
14
|
+
node.properties.forEach((node) => checkConst(node.type === "Property" ? node.value : node));
|
|
15
|
+
break;
|
|
16
|
+
case "ArrayPattern":
|
|
17
|
+
node.elements.forEach((node) => node && checkConst(node));
|
|
18
|
+
break;
|
|
19
|
+
case "RestElement":
|
|
20
|
+
checkConst(node.argument);
|
|
21
|
+
break;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
function checkConstLeft({ left }) {
|
|
25
|
+
checkConst(left);
|
|
26
|
+
}
|
|
27
|
+
function checkConstArgument({ argument }) {
|
|
28
|
+
checkConst(argument);
|
|
29
|
+
}
|
|
30
|
+
simple(node, {
|
|
31
|
+
AssignmentExpression: checkConstLeft,
|
|
32
|
+
AssignmentPattern: checkConstLeft,
|
|
33
|
+
UpdateExpression: checkConstArgument,
|
|
34
|
+
ForOfStatement: checkConstLeft,
|
|
35
|
+
ForInStatement: checkConstLeft
|
|
36
|
+
});
|
|
37
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { assert, test } from "vitest";
|
|
2
|
+
import { checkAssignments } from "./assignments.js";
|
|
3
|
+
import { parseJavaScript } from "./parse.js";
|
|
4
|
+
function check(input) {
|
|
5
|
+
const cell = parseJavaScript(input);
|
|
6
|
+
checkAssignments(cell.body, cell.references, input);
|
|
7
|
+
}
|
|
8
|
+
test("allows non-external assignments", () => {
|
|
9
|
+
assert.doesNotThrow(() => check("let foo = 1;\nfoo = 2;"));
|
|
10
|
+
assert.doesNotThrow(() => check("let foo = 1;\nfor (foo of []);"));
|
|
11
|
+
});
|
|
12
|
+
test("allows external references", () => {
|
|
13
|
+
assert.doesNotThrow(() => check("foo + 1;"));
|
|
14
|
+
});
|
|
15
|
+
test("does not allow external assignments", () => {
|
|
16
|
+
assert.throws(() => check("foo = 1;"), /external variable 'foo'/);
|
|
17
|
+
assert.throws(() => check("foo++;"), /external variable 'foo'/);
|
|
18
|
+
assert.throws(() => check("++foo;"), /external variable 'foo'/);
|
|
19
|
+
assert.throws(() => check("({foo} = {});"), /external variable 'foo'/);
|
|
20
|
+
assert.throws(() => check("({foo: bar} = {});"), /external variable 'bar'/);
|
|
21
|
+
assert.throws(() => check("([foo] = []);"), /external variable 'foo'/);
|
|
22
|
+
assert.throws(() => check("let foo = 1;\n({...bar} = {});"), /external variable 'bar'/);
|
|
23
|
+
assert.throws(() => check("let foo = 1;\n([...bar] = []);"), /external variable 'bar'/);
|
|
24
|
+
assert.throws(() => check("let foo = 1;\nbar = 1;"), /external variable 'bar'/);
|
|
25
|
+
assert.throws(() => check("function f() { foo = 1; }"), /external variable 'foo'/);
|
|
26
|
+
});
|
|
27
|
+
test("does not allow external assignments via for…of or for…in", () => {
|
|
28
|
+
assert.throws(() => check("for (foo of []);"), /external variable 'foo'/);
|
|
29
|
+
assert.throws(() => check("for (foo in {});"), /external variable 'foo'/);
|
|
30
|
+
});
|
|
31
|
+
test("does not allow global assignments", () => {
|
|
32
|
+
assert.throws(() => check("window = 1;"), /global 'window'/);
|
|
33
|
+
});
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { recursive } from "./walk.js";
|
|
2
|
+
export function findAwaits(node) {
|
|
3
|
+
const nodes = [];
|
|
4
|
+
recursive(node, null, {
|
|
5
|
+
FunctionDeclaration() { },
|
|
6
|
+
FunctionExpression() { },
|
|
7
|
+
ArrowFunctionExpression() { },
|
|
8
|
+
ForOfStatement(node, state, callback) {
|
|
9
|
+
if (node.await)
|
|
10
|
+
nodes.push(node);
|
|
11
|
+
if (node.left)
|
|
12
|
+
callback(node.left, state);
|
|
13
|
+
if (node.right)
|
|
14
|
+
callback(node.right, state);
|
|
15
|
+
if (node.body)
|
|
16
|
+
callback(node.body, state);
|
|
17
|
+
},
|
|
18
|
+
AwaitExpression(node) {
|
|
19
|
+
nodes.push(node);
|
|
20
|
+
}
|
|
21
|
+
});
|
|
22
|
+
return nodes;
|
|
23
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { assert, expect, test } from "vitest";
|
|
2
|
+
import { findAwaits } from "./awaits.js";
|
|
3
|
+
import { parseJavaScript } from "./parse.js";
|
|
4
|
+
function find(input) {
|
|
5
|
+
return findAwaits(parseJavaScript(input).body);
|
|
6
|
+
}
|
|
7
|
+
test("finds top-level awaits", () => {
|
|
8
|
+
expect(find("await 1;")).toMatchSnapshot();
|
|
9
|
+
expect(find("(1, await 2);")).toMatchSnapshot();
|
|
10
|
+
expect(find("1 + await 2;")).toMatchSnapshot();
|
|
11
|
+
expect(find("if (true) { await 3; }")).toMatchSnapshot();
|
|
12
|
+
expect(find("for await (const f of []);")).toMatchSnapshot();
|
|
13
|
+
expect(find("for (const f of await []);")).toMatchSnapshot();
|
|
14
|
+
expect(find("let f, g; for ({[await f]: g} of await []);")).toMatchSnapshot();
|
|
15
|
+
expect(find("for (const f of []) await f;")).toMatchSnapshot();
|
|
16
|
+
expect(find("for (const f in await {});")).toMatchSnapshot();
|
|
17
|
+
});
|
|
18
|
+
test("ignores awaits within functions", () => {
|
|
19
|
+
assert.deepStrictEqual(find("async function f() { await 1; }"), []);
|
|
20
|
+
assert.deepStrictEqual(find("let f = (async function () { await 1; });"), []);
|
|
21
|
+
assert.deepStrictEqual(find("let f = (async () => { await 1; });"), []);
|
|
22
|
+
});
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { defaultGlobals } from "./globals.js";
|
|
2
|
+
import { syntaxError } from "./syntaxError.js";
|
|
3
|
+
export function findDeclarations(node, input) {
|
|
4
|
+
const declarations = [];
|
|
5
|
+
function declareLocal(node) {
|
|
6
|
+
if (defaultGlobals.has(node.name) || node.name === "arguments") {
|
|
7
|
+
throw syntaxError(`Global '${node.name}' cannot be redefined`, node, input);
|
|
8
|
+
}
|
|
9
|
+
declarations.push(node);
|
|
10
|
+
}
|
|
11
|
+
function declarePattern(node) {
|
|
12
|
+
switch (node.type) {
|
|
13
|
+
case "Identifier":
|
|
14
|
+
declareLocal(node);
|
|
15
|
+
break;
|
|
16
|
+
case "ObjectPattern":
|
|
17
|
+
node.properties.forEach((node) => declarePattern(node.type === "Property" ? node.value : node));
|
|
18
|
+
break;
|
|
19
|
+
case "ArrayPattern":
|
|
20
|
+
node.elements.forEach((node) => node && declarePattern(node));
|
|
21
|
+
break;
|
|
22
|
+
case "RestElement":
|
|
23
|
+
declarePattern(node.argument);
|
|
24
|
+
break;
|
|
25
|
+
case "AssignmentPattern":
|
|
26
|
+
declarePattern(node.left);
|
|
27
|
+
break;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
for (const child of node.body) {
|
|
31
|
+
switch (child.type) {
|
|
32
|
+
case "VariableDeclaration":
|
|
33
|
+
child.declarations.forEach((node) => declarePattern(node.id));
|
|
34
|
+
break;
|
|
35
|
+
case "ClassDeclaration":
|
|
36
|
+
case "FunctionDeclaration":
|
|
37
|
+
declareLocal(child.id);
|
|
38
|
+
break;
|
|
39
|
+
case "ImportDeclaration":
|
|
40
|
+
child.specifiers.forEach((node) => declareLocal(node.local));
|
|
41
|
+
break;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return declarations;
|
|
45
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { findReferences } from "./references.js";
|
|
2
|
+
import { simple } from "./walk.js";
|
|
3
|
+
export function rewriteFileExpressions(output, body) {
|
|
4
|
+
const files = new Set(findReferences(body, { filterReference: ({ name }) => name === "FileAttachment" }));
|
|
5
|
+
simple(body, {
|
|
6
|
+
CallExpression(node) {
|
|
7
|
+
const { callee } = node;
|
|
8
|
+
if (callee.type !== "Identifier" || !files.has(callee))
|
|
9
|
+
return;
|
|
10
|
+
const args = node.arguments;
|
|
11
|
+
if (args.length === 0)
|
|
12
|
+
return;
|
|
13
|
+
const [arg] = args;
|
|
14
|
+
output.insertLeft(arg.start, "new URL(");
|
|
15
|
+
output.insertRight(arg.end, ", import.meta.url).href");
|
|
16
|
+
}
|
|
17
|
+
});
|
|
18
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const defaultGlobals: Set<string>;
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
export const defaultGlobals = new Set([
|
|
2
|
+
"Array",
|
|
3
|
+
"ArrayBuffer",
|
|
4
|
+
"atob",
|
|
5
|
+
"AudioContext",
|
|
6
|
+
"Blob",
|
|
7
|
+
"Boolean",
|
|
8
|
+
"BigInt",
|
|
9
|
+
"btoa",
|
|
10
|
+
"clearInterval",
|
|
11
|
+
"clearTimeout",
|
|
12
|
+
"console",
|
|
13
|
+
"crypto",
|
|
14
|
+
"CustomEvent",
|
|
15
|
+
"DataView",
|
|
16
|
+
"Date",
|
|
17
|
+
"decodeURI",
|
|
18
|
+
"decodeURIComponent",
|
|
19
|
+
"devicePixelRatio",
|
|
20
|
+
"document",
|
|
21
|
+
"encodeURI",
|
|
22
|
+
"encodeURIComponent",
|
|
23
|
+
"Error",
|
|
24
|
+
"escape",
|
|
25
|
+
"eval",
|
|
26
|
+
"fetch",
|
|
27
|
+
"File",
|
|
28
|
+
"FileList",
|
|
29
|
+
"FileReader",
|
|
30
|
+
"Float32Array",
|
|
31
|
+
"Float64Array",
|
|
32
|
+
"Function",
|
|
33
|
+
"Headers",
|
|
34
|
+
"Image",
|
|
35
|
+
"ImageData",
|
|
36
|
+
"Infinity",
|
|
37
|
+
"Int16Array",
|
|
38
|
+
"Int32Array",
|
|
39
|
+
"Int8Array",
|
|
40
|
+
"Intl",
|
|
41
|
+
"isFinite",
|
|
42
|
+
"isNaN",
|
|
43
|
+
"JSON",
|
|
44
|
+
"Map",
|
|
45
|
+
"Math",
|
|
46
|
+
"NaN",
|
|
47
|
+
"Number",
|
|
48
|
+
"navigator",
|
|
49
|
+
"Object",
|
|
50
|
+
"observable", // for observable.params.foo
|
|
51
|
+
"parseFloat",
|
|
52
|
+
"parseInt",
|
|
53
|
+
"performance",
|
|
54
|
+
"Path2D",
|
|
55
|
+
"Promise",
|
|
56
|
+
"Proxy",
|
|
57
|
+
"RangeError",
|
|
58
|
+
"ReferenceError",
|
|
59
|
+
"Reflect",
|
|
60
|
+
"RegExp",
|
|
61
|
+
"cancelAnimationFrame",
|
|
62
|
+
"requestAnimationFrame",
|
|
63
|
+
"Set",
|
|
64
|
+
"setInterval",
|
|
65
|
+
"setTimeout",
|
|
66
|
+
"String",
|
|
67
|
+
"Symbol",
|
|
68
|
+
"SyntaxError",
|
|
69
|
+
"TextDecoder",
|
|
70
|
+
"TextEncoder",
|
|
71
|
+
"this",
|
|
72
|
+
"TypeError",
|
|
73
|
+
"Uint16Array",
|
|
74
|
+
"Uint32Array",
|
|
75
|
+
"Uint8Array",
|
|
76
|
+
"Uint8ClampedArray",
|
|
77
|
+
"undefined",
|
|
78
|
+
"unescape",
|
|
79
|
+
"URIError",
|
|
80
|
+
"URL",
|
|
81
|
+
"WeakMap",
|
|
82
|
+
"WeakSet",
|
|
83
|
+
"WebSocket",
|
|
84
|
+
"Worker",
|
|
85
|
+
"window"
|
|
86
|
+
]);
|