@observablehq/notebook-kit 1.5.0 → 1.5.2
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/dist/package.json +1 -1
- package/dist/src/runtime/index.d.ts +1 -1
- package/dist/src/runtime/stdlib/dot.js +1 -1
- package/dist/src/runtime/stdlib/duckdb.js +5 -5
- package/dist/src/runtime/stdlib/fileAttachment.d.ts +1 -1
- package/dist/src/runtime/stdlib/fileAttachment.js +4 -4
- package/dist/src/runtime/stdlib/generators/input.d.ts +1 -1
- package/dist/src/runtime/stdlib/generators/observe.d.ts +1 -1
- package/dist/src/runtime/stdlib/generators/observe.js +37 -13
- package/dist/src/runtime/stdlib/generators/queue.d.ts +1 -1
- package/dist/src/runtime/stdlib/generators/queue.js +36 -12
- package/dist/src/runtime/stdlib/generators/width.d.ts +1 -1
- package/dist/src/runtime/stdlib/index.d.ts +1 -1
- package/dist/src/runtime/stdlib/inputs.d.ts +1 -1
- package/dist/src/runtime/stdlib/inputs.js +1 -1
- package/dist/src/runtime/stdlib/leaflet.d.ts +1 -1
- package/dist/src/runtime/stdlib/leaflet.js +9 -3
- package/dist/src/runtime/stdlib/mapboxgl.d.ts +1 -1
- package/dist/src/runtime/stdlib/mapboxgl.js +1 -1
- package/dist/src/runtime/stdlib/mermaid.js +1 -1
- package/dist/src/runtime/stdlib/mutable.d.ts +2 -2
- package/dist/src/runtime/stdlib/recommendedLibraries.js +13 -13
- package/dist/src/runtime/stdlib/sampleDatasets.js +1 -1
- package/dist/src/runtime/stdlib/tex.js +1 -1
- package/dist/src/runtime/stdlib/vega-lite.js +3 -3
- package/package.json +1 -1
- package/dist/src/javascript/assignments.test.d.ts +0 -1
- package/dist/src/javascript/assignments.test.js +0 -46
- package/dist/src/javascript/awaits.test.d.ts +0 -1
- package/dist/src/javascript/awaits.test.js +0 -22
- package/dist/src/javascript/imports/npm.test.d.ts +0 -1
- package/dist/src/javascript/imports/npm.test.js +0 -32
- package/dist/src/javascript/imports/observable.test.d.ts +0 -1
- package/dist/src/javascript/imports/observable.test.js +0 -13
- package/dist/src/javascript/references.test.d.ts +0 -1
- package/dist/src/javascript/references.test.js +0 -38
- package/dist/src/javascript/sourcemap.test.d.ts +0 -1
- package/dist/src/javascript/sourcemap.test.js +0 -88
- package/dist/src/javascript/strings.test.d.ts +0 -1
- package/dist/src/javascript/strings.test.js +0 -31
- package/dist/src/javascript/template.test.d.ts +0 -1
- package/dist/src/javascript/template.test.js +0 -60
- package/dist/src/javascript/transpile.test.d.ts +0 -1
- package/dist/src/javascript/transpile.test.js +0 -52
- package/dist/src/javascript/typescript.test.d.ts +0 -1
- package/dist/src/javascript/typescript.test.js +0 -34
- package/dist/src/lib/hash.test.d.ts +0 -1
- package/dist/src/lib/hash.test.js +0 -28
- package/dist/src/lib/notebook.test.d.ts +0 -1
- package/dist/src/lib/notebook.test.js +0 -36
- package/dist/src/lib/serialize.test.d.ts +0 -1
- package/dist/src/lib/serialize.test.js +0 -132
- package/dist/src/lib/sluggify.test.d.ts +0 -1
- package/dist/src/lib/sluggify.test.js +0 -51
- package/dist/src/runtime/stdlib/assets.test.d.ts +0 -1
- package/dist/src/runtime/stdlib/assets.test.js +0 -78
|
@@ -1,88 +0,0 @@
|
|
|
1
|
-
import { assert, test } from "vitest";
|
|
2
|
-
import { Sourcemap } from "./sourcemap.js";
|
|
3
|
-
test("identity", () => {
|
|
4
|
-
const sm = new Sourcemap("");
|
|
5
|
-
assert.strictEqual(sm.toString(), "");
|
|
6
|
-
assert.deepStrictEqual(sm.translate({ line: 1, column: 0 }), { line: 1, column: 0 });
|
|
7
|
-
});
|
|
8
|
-
test("insert at beginning", () => {
|
|
9
|
-
const original = "hello;";
|
|
10
|
-
const sm = new Sourcemap(original);
|
|
11
|
-
sm.insertLeft(0, "return ");
|
|
12
|
-
assert.strictEqual(sm.toString(), "return hello;");
|
|
13
|
-
assert.deepStrictEqual(sm.translate({ line: 1, column: 7 }), { line: 1, column: 0 });
|
|
14
|
-
});
|
|
15
|
-
test("insertLeft at beginning twice", () => {
|
|
16
|
-
const original = "hello;";
|
|
17
|
-
const sm = new Sourcemap(original);
|
|
18
|
-
sm.insertLeft(0, " ");
|
|
19
|
-
sm.insertLeft(0, "return");
|
|
20
|
-
assert.strictEqual(sm.toString(), "return hello;");
|
|
21
|
-
assert.deepStrictEqual(sm.translate({ line: 1, column: 7 }), { line: 1, column: 0 });
|
|
22
|
-
});
|
|
23
|
-
test("insert right at beginning", () => {
|
|
24
|
-
const original = "hello;";
|
|
25
|
-
const sm = new Sourcemap(original);
|
|
26
|
-
sm.insertLeft(0, "return");
|
|
27
|
-
sm.insertRight(0, " ");
|
|
28
|
-
assert.strictEqual(sm.toString(), "return hello;");
|
|
29
|
-
assert.deepStrictEqual(sm.translate({ line: 1, column: 7 }), { line: 1, column: 0 });
|
|
30
|
-
});
|
|
31
|
-
test("insert at end", () => {
|
|
32
|
-
const original = "hello";
|
|
33
|
-
const sm = new Sourcemap(original);
|
|
34
|
-
sm.insertLeft(original.length, "();");
|
|
35
|
-
assert.strictEqual(sm.toString(), "hello();");
|
|
36
|
-
assert.deepStrictEqual(sm.translate({ line: 1, column: 8 }), { line: 1, column: 5 });
|
|
37
|
-
});
|
|
38
|
-
test("insert at end twice is insertLeft", () => {
|
|
39
|
-
const original = "hello";
|
|
40
|
-
const sm = new Sourcemap(original);
|
|
41
|
-
sm.insertLeft(original.length, ";");
|
|
42
|
-
sm.insertLeft(original.length, "()");
|
|
43
|
-
assert.strictEqual(sm.toString(), "hello();");
|
|
44
|
-
assert.deepStrictEqual(sm.translate({ line: 1, column: 8 }), { line: 1, column: 5 });
|
|
45
|
-
});
|
|
46
|
-
test("insert right at end", () => {
|
|
47
|
-
const original = "hello";
|
|
48
|
-
const sm = new Sourcemap(original);
|
|
49
|
-
sm.insertLeft(original.length, "()");
|
|
50
|
-
sm.insertRight(original.length, ";");
|
|
51
|
-
assert.strictEqual(sm.toString(), "hello();");
|
|
52
|
-
assert.deepStrictEqual(sm.translate({ line: 1, column: 8 }), { line: 1, column: 5 });
|
|
53
|
-
});
|
|
54
|
-
test("insert new lines", () => {
|
|
55
|
-
const original = "hello";
|
|
56
|
-
const sm = new Sourcemap(original);
|
|
57
|
-
sm.insertLeft(0, "function() {\n");
|
|
58
|
-
sm.insertRight(original.length, "\n}");
|
|
59
|
-
assert.strictEqual(sm.toString(), "function() {\nhello\n}");
|
|
60
|
-
assert.deepStrictEqual(sm.translate({ line: 1, column: 7 }), { line: 1, column: 0 });
|
|
61
|
-
assert.deepStrictEqual(sm.translate({ line: 2, column: 0 }), { line: 1, column: 0 });
|
|
62
|
-
assert.deepStrictEqual(sm.translate({ line: 3, column: 1 }), { line: 1, column: 5 });
|
|
63
|
-
});
|
|
64
|
-
test("replace new line", () => {
|
|
65
|
-
const original = "\nhello";
|
|
66
|
-
const sm = new Sourcemap(original);
|
|
67
|
-
sm.replaceLeft(0, 1, "function() {\n");
|
|
68
|
-
assert.strictEqual(sm.toString(), "function() {\nhello");
|
|
69
|
-
assert.deepStrictEqual(sm.translate({ line: 2, column: 0 }), { line: 2, column: 0 });
|
|
70
|
-
});
|
|
71
|
-
test("delete", () => {
|
|
72
|
-
const original = "hello;";
|
|
73
|
-
const sm = new Sourcemap(original);
|
|
74
|
-
sm.delete(original.length - 1, original.length);
|
|
75
|
-
assert.strictEqual(sm.toString(), "hello");
|
|
76
|
-
});
|
|
77
|
-
test("complete replace", () => {
|
|
78
|
-
const original = "hello;";
|
|
79
|
-
const sm = new Sourcemap(original);
|
|
80
|
-
sm.replaceRight(0, original.length, "something else");
|
|
81
|
-
assert.strictEqual(sm.toString(), "something else");
|
|
82
|
-
assert.deepStrictEqual(sm.translate({ line: 1, column: 0 }), { line: 1, column: 0 });
|
|
83
|
-
});
|
|
84
|
-
test("line-level granularity", () => {
|
|
85
|
-
const sm = new Sourcemap("ab\ncd");
|
|
86
|
-
sm.insertLeft(0, "foo");
|
|
87
|
-
assert.deepStrictEqual(sm.translate({ line: 1, column: 4 }), { line: 1, column: 1 });
|
|
88
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
import { assert, test } from "vitest";
|
|
2
|
-
import { isStringLiteral, getStringLiteralValue } from "./strings.js";
|
|
3
|
-
import { parseJavaScript } from "./parse.js";
|
|
4
|
-
function get(input) {
|
|
5
|
-
const { body } = parseJavaScript(input);
|
|
6
|
-
if (!isStringLiteral(body))
|
|
7
|
-
throw new Error("input is not a string literal");
|
|
8
|
-
return getStringLiteralValue(body);
|
|
9
|
-
}
|
|
10
|
-
function is(input) {
|
|
11
|
-
const { body } = parseJavaScript(input);
|
|
12
|
-
return isStringLiteral(body);
|
|
13
|
-
}
|
|
14
|
-
test("returns the string literal value for simple string literals", () => {
|
|
15
|
-
assert.strictEqual(get('"hello"'), "hello");
|
|
16
|
-
assert.strictEqual(get('`hello`'), "hello");
|
|
17
|
-
assert.strictEqual(get("'hello'"), "hello");
|
|
18
|
-
});
|
|
19
|
-
test("returns the string literal value for static string binary expressions", () => {
|
|
20
|
-
assert.strictEqual(get('"hel" + "lo"'), "hello");
|
|
21
|
-
assert.strictEqual(get('"hel" + `lo`'), "hello");
|
|
22
|
-
});
|
|
23
|
-
test("returns the string literal value for static string templates", () => {
|
|
24
|
-
assert.strictEqual(get('`he${"ll"}o`'), "hello");
|
|
25
|
-
assert.strictEqual(get('`he${"l" + "l"}o`'), "hello");
|
|
26
|
-
});
|
|
27
|
-
test("does not consider templates with dynamic quasis to be a string literal", () => {
|
|
28
|
-
assert.strictEqual(is('`he${"l" + "1"}o`'), true);
|
|
29
|
-
assert.strictEqual(is('`he${"l" + 1}o`'), false);
|
|
30
|
-
assert.strictEqual(is('`he${ll}o`'), false);
|
|
31
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
import { expect, it } from "vitest";
|
|
2
|
-
import { parseTemplate, transpileTemplate } from "./template.js";
|
|
3
|
-
import { toCell } from "../lib/notebook.js";
|
|
4
|
-
function md(value) {
|
|
5
|
-
return transpileTemplate(toCell({ id: 1, mode: "md", value }));
|
|
6
|
-
}
|
|
7
|
-
function html(value) {
|
|
8
|
-
return transpileTemplate(toCell({ id: 1, mode: "html", value }));
|
|
9
|
-
}
|
|
10
|
-
function node(value) {
|
|
11
|
-
return transpileTemplate(toCell({ id: 1, mode: "node", value }));
|
|
12
|
-
}
|
|
13
|
-
it("parses a simple template", () => {
|
|
14
|
-
expect(parseTemplate(`Hello, world!`)).toMatchSnapshot();
|
|
15
|
-
});
|
|
16
|
-
it("parses an empty template", () => {
|
|
17
|
-
expect(parseTemplate(``)).toMatchSnapshot();
|
|
18
|
-
});
|
|
19
|
-
it("parses a template with an interpolated expression", () => {
|
|
20
|
-
expect(parseTemplate(`Hello, $\{"world"}!`)).toMatchSnapshot();
|
|
21
|
-
});
|
|
22
|
-
it("parses a template with backquotes", () => {
|
|
23
|
-
expect(parseTemplate(`Hello, \`world\`!`)).toMatchSnapshot();
|
|
24
|
-
});
|
|
25
|
-
it("parses a template with backslashes", () => {
|
|
26
|
-
expect(parseTemplate(`Hello, \\world\\!`)).toMatchSnapshot();
|
|
27
|
-
});
|
|
28
|
-
it("transpiles a simple markdown template", () => {
|
|
29
|
-
expect(md(`Hello, world!`)).toMatchSnapshot();
|
|
30
|
-
});
|
|
31
|
-
it("transpiles an empty markdown template", () => {
|
|
32
|
-
expect(md(``)).toMatchSnapshot();
|
|
33
|
-
});
|
|
34
|
-
it("transpiles a markdown template with an interpolated expression", () => {
|
|
35
|
-
expect(md(`Hello, $\{"world"}!`)).toMatchSnapshot();
|
|
36
|
-
});
|
|
37
|
-
it("transpiles a markdown template with backquotes", () => {
|
|
38
|
-
expect(md(`Hello, \`world\`!`)).toMatchSnapshot();
|
|
39
|
-
});
|
|
40
|
-
it("transpiles a markdown template with backslashes", () => {
|
|
41
|
-
expect(md(`Hello, \\world\\!`)).toMatchSnapshot();
|
|
42
|
-
});
|
|
43
|
-
it("transpiles a simple html template", () => {
|
|
44
|
-
expect(html(`Hello, world!`)).toMatchSnapshot();
|
|
45
|
-
});
|
|
46
|
-
it("transpiles an empty html template", () => {
|
|
47
|
-
expect(html(``)).toMatchSnapshot();
|
|
48
|
-
});
|
|
49
|
-
it("transpiles a html template with an interpolated expression", () => {
|
|
50
|
-
expect(html(`Hello, $\{"world"}!`)).toMatchSnapshot();
|
|
51
|
-
});
|
|
52
|
-
it("transpiles a html template with backquotes", () => {
|
|
53
|
-
expect(html(`Hello, \`world\`!`)).toMatchSnapshot();
|
|
54
|
-
});
|
|
55
|
-
it("transpiles a html template with backslashes", () => {
|
|
56
|
-
expect(html(`Hello, \\world\\!`)).toMatchSnapshot();
|
|
57
|
-
});
|
|
58
|
-
it("transpiles a node template with backslashes", () => {
|
|
59
|
-
expect(node(`Hello, \\world\\!`)).toMatchSnapshot();
|
|
60
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
import { expect, it } from "vitest";
|
|
2
|
-
import { transpile } from "./transpile.js";
|
|
3
|
-
it("transpiles JavaScript expressions", () => {
|
|
4
|
-
expect(transpile("1 + 2", "js")).toMatchSnapshot();
|
|
5
|
-
expect(transpile("x + y", "js")).toMatchSnapshot();
|
|
6
|
-
expect(transpile("await z", "js")).toMatchSnapshot();
|
|
7
|
-
expect(transpile("display(1), display(2)", "js")).toMatchSnapshot();
|
|
8
|
-
});
|
|
9
|
-
it("transpiles empty cells", () => {
|
|
10
|
-
expect(transpile("", "js")).toMatchSnapshot();
|
|
11
|
-
expect(transpile("", "md")).toMatchSnapshot();
|
|
12
|
-
expect(transpile("", "html")).toMatchSnapshot();
|
|
13
|
-
expect(transpile("", "tex")).toMatchSnapshot();
|
|
14
|
-
expect(transpile("", "sql")).toMatchSnapshot();
|
|
15
|
-
});
|
|
16
|
-
it("transpiles JavaScript programs", () => {
|
|
17
|
-
expect(transpile("const x = 1, y = 2;", "js")).toMatchSnapshot();
|
|
18
|
-
expect(transpile("x + y;", "js")).toMatchSnapshot();
|
|
19
|
-
expect(transpile("await z;", "js")).toMatchSnapshot();
|
|
20
|
-
});
|
|
21
|
-
it("transpiles static npm: imports", () => {
|
|
22
|
-
expect(transpile('import * as d3 from "npm:d3";', "js")).toMatchSnapshot();
|
|
23
|
-
expect(transpile('import _ from "npm:lodash";', "js")).toMatchSnapshot();
|
|
24
|
-
expect(transpile('import {} from "npm:d3";\nimport "npm:isoformat";', "js")).toMatchSnapshot();
|
|
25
|
-
});
|
|
26
|
-
it("transpiles dynamic npm: imports", () => {
|
|
27
|
-
expect(transpile('const d3 = await import("npm:d3");', "js")).toMatchSnapshot();
|
|
28
|
-
});
|
|
29
|
-
it("transpiles static observable: imports", () => {
|
|
30
|
-
expect(transpile('import {Scrubber} from "observable:@mbostock/scrubber";', "js")).toMatchSnapshot();
|
|
31
|
-
expect(transpile('import {viewof$rotation} from "observable:@rreusser/drawing-3d-objects-with-svg";', "js")).toMatchSnapshot();
|
|
32
|
-
});
|
|
33
|
-
it("transpiles static imports with {type: 'observable'}", () => {
|
|
34
|
-
expect(transpile('import {Scrubber} from "https://api.observablehq.com/@mbostock/scrubber.js?v=4" with {type: "observable"};', "js")).toMatchSnapshot();
|
|
35
|
-
expect(transpile('import {viewof$rotation} from "https://api.observablehq.com/@rreusser/drawing-3d-objects-with-svg.js?v=4" with {type: "observable"};', "js")).toMatchSnapshot();
|
|
36
|
-
});
|
|
37
|
-
it("transpiles Observable JavaScript imports", () => {
|
|
38
|
-
expect(transpile('import {figure, viewof rotation} from "@rreusser/drawing-3d-objects-with-svg"', "ojs")).toMatchSnapshot();
|
|
39
|
-
expect(transpile('import {figure, viewof rotation as rot} from "@rreusser/drawing-3d-objects-with-svg"', "ojs")).toMatchSnapshot();
|
|
40
|
-
});
|
|
41
|
-
it("transpiles import.meta.resolve", () => {
|
|
42
|
-
expect(transpile('import.meta.resolve("npm:d3")', "js")).toMatchSnapshot();
|
|
43
|
-
expect(transpile('import.meta.resolve("./test")', "js", { resolveLocalImports: true })).toMatchSnapshot();
|
|
44
|
-
expect(transpile('import.meta.resolve("./test")', "js", { resolveLocalImports: false })).toMatchSnapshot();
|
|
45
|
-
});
|
|
46
|
-
it("transpiles node cells", () => {
|
|
47
|
-
expect(transpile("process.stdout.write(`Node ${process.version}`);", "node")).toMatchSnapshot();
|
|
48
|
-
expect(transpile("process.stdout.write(`Node \\${process.version}`);", "node")).toMatchSnapshot();
|
|
49
|
-
expect(transpile("process.stdout.write(`Node \\\\${process.version}`);", "node")).toMatchSnapshot();
|
|
50
|
-
expect(transpile("process.stdout.write(`Node $\\{process.version}`);", "node")).toMatchSnapshot();
|
|
51
|
-
expect(transpile("process.stdout.write(`Node \\$\\{process.version}`);", "node")).toMatchSnapshot();
|
|
52
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
import { assert, expect, it } from "vitest";
|
|
2
|
-
import { transpileTypeScript } from "./typescript.js";
|
|
3
|
-
it("transpiles TypeScript expressions", () => {
|
|
4
|
-
expect(transpileTypeScript("1 + 2")).toMatchSnapshot();
|
|
5
|
-
expect(transpileTypeScript("1, 2")).toMatchSnapshot();
|
|
6
|
-
expect(transpileTypeScript("1, 2 // comment")).toMatchSnapshot();
|
|
7
|
-
expect(transpileTypeScript("(1), (2)")).toMatchSnapshot();
|
|
8
|
-
expect(transpileTypeScript("(1 + 2)")).toMatchSnapshot();
|
|
9
|
-
expect(transpileTypeScript("{x: 42}")).toMatchSnapshot();
|
|
10
|
-
expect(transpileTypeScript("({x: 42})")).toMatchSnapshot();
|
|
11
|
-
});
|
|
12
|
-
it("transpiles TypeScript function expressions", () => {
|
|
13
|
-
expect(transpileTypeScript("function foo() {}")).toMatchSnapshot();
|
|
14
|
-
});
|
|
15
|
-
it("transpiles TypeScript class expressions", () => {
|
|
16
|
-
expect(transpileTypeScript("class Foo {}")).toMatchSnapshot();
|
|
17
|
-
});
|
|
18
|
-
it("transpiles TypeScript statements", () => {
|
|
19
|
-
expect(transpileTypeScript("1 + 2;")).toMatchSnapshot();
|
|
20
|
-
expect(transpileTypeScript("1, 2;")).toMatchSnapshot();
|
|
21
|
-
expect(transpileTypeScript("(1), (2);")).toMatchSnapshot();
|
|
22
|
-
expect(transpileTypeScript("(1 + 2);")).toMatchSnapshot();
|
|
23
|
-
expect(transpileTypeScript("{x: 42};")).toMatchSnapshot();
|
|
24
|
-
expect(transpileTypeScript("({x: 42});")).toMatchSnapshot();
|
|
25
|
-
});
|
|
26
|
-
it("transpiles TypeScript imports", () => {
|
|
27
|
-
expect(transpileTypeScript('import {foo} from "npm:bar";')).toMatchSnapshot();
|
|
28
|
-
expect(transpileTypeScript('import type {foo} from "npm:bar";')).toMatchSnapshot();
|
|
29
|
-
});
|
|
30
|
-
it("throws SyntaxError on invalid syntax", () => {
|
|
31
|
-
assert.throws(() => transpileTypeScript("1) + 2"), SyntaxError);
|
|
32
|
-
assert.throws(() => transpileTypeScript("(1 + 2"), SyntaxError);
|
|
33
|
-
assert.throws(() => transpileTypeScript("1 + 2 /* comment"), SyntaxError);
|
|
34
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
import { assert, describe, test } from "vitest";
|
|
2
|
-
import { hash, nameHash } from "./hash.js";
|
|
3
|
-
describe("nameHash", () => {
|
|
4
|
-
test("returns a simple name as-is", async () => {
|
|
5
|
-
assert.strictEqual(await nameHash("foo"), "foo");
|
|
6
|
-
assert.strictEqual(await nameHash("foo-bar"), "foo-bar");
|
|
7
|
-
assert.strictEqual(await nameHash("foo-"), "foo-");
|
|
8
|
-
assert.strictEqual(await nameHash("-foo"), "-foo");
|
|
9
|
-
});
|
|
10
|
-
test("sluggifies and hashes names with special characters", async () => {
|
|
11
|
-
assert.strictEqual(await nameHash("foo.db"), "foo-db.2s9flvsm");
|
|
12
|
-
assert.strictEqual(await nameHash("./foo.db"), "foo-db.3ee6cmxd");
|
|
13
|
-
assert.strictEqual(await nameHash("data/foo.db"), "foo-db.61nrbwb0");
|
|
14
|
-
assert.strictEqual(await nameHash("bar/foo.db"), "foo-db.1jlqjad7");
|
|
15
|
-
assert.strictEqual(await nameHash("foo bar"), "foo-bar.69w36b7f");
|
|
16
|
-
});
|
|
17
|
-
});
|
|
18
|
-
describe("hash", () => {
|
|
19
|
-
test("returns the expected static hash", async () => {
|
|
20
|
-
assert.strictEqual(await hash `foo`, "1n7k0l3ilxvth9al");
|
|
21
|
-
assert.strictEqual(await hash `bar`, "39v7mmkf7sfehxh1");
|
|
22
|
-
assert.strictEqual(await hash ``, "gepym5nmvuej8503");
|
|
23
|
-
});
|
|
24
|
-
test("returns the expected dynamic hash", async () => {
|
|
25
|
-
assert.strictEqual(await hash `SELECT 1 + ${2}`, "64iqby4orqj5tgek");
|
|
26
|
-
assert.strictEqual(await hash `SELECT 1 + ${3}`, "1azi8mazfb39kln7");
|
|
27
|
-
});
|
|
28
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
import { assert, test } from "vitest";
|
|
2
|
-
import { toCell, toNotebook } from "./notebook.js";
|
|
3
|
-
test("converts a notebook spec to a notebook", () => {
|
|
4
|
-
assert.deepStrictEqual(toNotebook({}), {
|
|
5
|
-
title: "Untitled",
|
|
6
|
-
theme: "air",
|
|
7
|
-
cells: [],
|
|
8
|
-
readOnly: false
|
|
9
|
-
});
|
|
10
|
-
});
|
|
11
|
-
test("converts a cell spec to a cell", () => {
|
|
12
|
-
assert.deepStrictEqual(toCell({ id: 1 }), {
|
|
13
|
-
id: 1,
|
|
14
|
-
value: "",
|
|
15
|
-
mode: "js",
|
|
16
|
-
pinned: true,
|
|
17
|
-
hidden: false,
|
|
18
|
-
format: undefined,
|
|
19
|
-
output: undefined,
|
|
20
|
-
database: undefined,
|
|
21
|
-
since: undefined
|
|
22
|
-
});
|
|
23
|
-
});
|
|
24
|
-
test("computes an appropriate default pinned based on the cell mode", () => {
|
|
25
|
-
assert.deepStrictEqual(toCell({ id: 1, mode: "md" }), {
|
|
26
|
-
id: 1,
|
|
27
|
-
value: "",
|
|
28
|
-
mode: "md",
|
|
29
|
-
pinned: false,
|
|
30
|
-
hidden: false,
|
|
31
|
-
format: undefined,
|
|
32
|
-
output: undefined,
|
|
33
|
-
database: undefined,
|
|
34
|
-
since: undefined
|
|
35
|
-
});
|
|
36
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,132 +0,0 @@
|
|
|
1
|
-
import { JSDOM } from "jsdom";
|
|
2
|
-
import { assert, test } from "vitest";
|
|
3
|
-
import { toNotebook } from "./notebook.js";
|
|
4
|
-
import { deserialize as _deserialize, serialize as _serialize } from "./serialize.js";
|
|
5
|
-
const { window } = new JSDOM();
|
|
6
|
-
function serialize(notebook) {
|
|
7
|
-
return _serialize(notebook, { document: window.document });
|
|
8
|
-
}
|
|
9
|
-
function deserialize(data) {
|
|
10
|
-
return _deserialize(data, { parser: new window.DOMParser() });
|
|
11
|
-
}
|
|
12
|
-
test("serializes unpinned cells", () => {
|
|
13
|
-
const notebook1 = toNotebook({
|
|
14
|
-
cells: [
|
|
15
|
-
{ id: 1, mode: "md", pinned: false, value: "# Hello, world!" },
|
|
16
|
-
{ id: 2, pinned: false, value: "1 + 2" }
|
|
17
|
-
]
|
|
18
|
-
});
|
|
19
|
-
const notebook2 = toNotebook({
|
|
20
|
-
cells: [
|
|
21
|
-
{ id: 1, mode: "md", pinned: false, value: "# Hello, world!" },
|
|
22
|
-
{ id: 2, mode: "js", pinned: false, value: "1 + 2" }
|
|
23
|
-
]
|
|
24
|
-
});
|
|
25
|
-
assert.deepStrictEqual(deserialize(serialize(notebook1)), notebook2);
|
|
26
|
-
});
|
|
27
|
-
test("serializes pinned cells", () => {
|
|
28
|
-
const notebook1 = toNotebook({
|
|
29
|
-
cells: [
|
|
30
|
-
{ id: 1, mode: "md", pinned: true, value: "# Hello, world!" },
|
|
31
|
-
{ id: 2, pinned: true, value: "1 + 2" }
|
|
32
|
-
]
|
|
33
|
-
});
|
|
34
|
-
const notebook2 = toNotebook({
|
|
35
|
-
cells: [
|
|
36
|
-
{ id: 1, mode: "md", pinned: true, value: "# Hello, world!" },
|
|
37
|
-
{ id: 2, mode: "js", pinned: true, value: "1 + 2" }
|
|
38
|
-
]
|
|
39
|
-
});
|
|
40
|
-
assert.deepStrictEqual(deserialize(serialize(notebook1)), notebook2);
|
|
41
|
-
});
|
|
42
|
-
test("serializes notebook titles", () => {
|
|
43
|
-
const notebook1 = toNotebook({
|
|
44
|
-
title: "Hello, world!",
|
|
45
|
-
cells: [
|
|
46
|
-
{ id: 1, mode: "md", pinned: false, value: "# Hello, world!" },
|
|
47
|
-
{ id: 2, pinned: true, value: "1 + 2" }
|
|
48
|
-
]
|
|
49
|
-
});
|
|
50
|
-
const notebook2 = toNotebook({
|
|
51
|
-
title: "Hello, world!",
|
|
52
|
-
cells: [
|
|
53
|
-
{ id: 1, mode: "md", pinned: false, value: "# Hello, world!" },
|
|
54
|
-
{ id: 2, mode: "js", pinned: true, value: "1 + 2" }
|
|
55
|
-
]
|
|
56
|
-
});
|
|
57
|
-
assert.deepStrictEqual(deserialize(serialize(notebook1)), notebook2);
|
|
58
|
-
});
|
|
59
|
-
test("serialization preserves indentation", () => {
|
|
60
|
-
const notebook1 = toNotebook({
|
|
61
|
-
title: "Hello, world!",
|
|
62
|
-
cells: [{ id: 2, pinned: true, value: `{\n 1;\n 2;\n}` }]
|
|
63
|
-
});
|
|
64
|
-
const notebook2 = toNotebook({
|
|
65
|
-
title: "Hello, world!",
|
|
66
|
-
cells: [{ id: 2, mode: "js", pinned: true, value: `{\n 1;\n 2;\n}` }]
|
|
67
|
-
});
|
|
68
|
-
assert.deepStrictEqual(deserialize(serialize(notebook1)), notebook2);
|
|
69
|
-
});
|
|
70
|
-
test("serialization escapes </script>, in various forms", () => {
|
|
71
|
-
const notebook1 = toNotebook({
|
|
72
|
-
title: "Hello, world!",
|
|
73
|
-
cells: [
|
|
74
|
-
{ id: 2, pinned: true, value: `'</script>'` },
|
|
75
|
-
{ id: 3, pinned: true, value: `'</script '` },
|
|
76
|
-
{ id: 4, pinned: true, value: `'</SCRIPT '` },
|
|
77
|
-
{ id: 5, pinned: true, value: `'</sCrIpT '` },
|
|
78
|
-
{ id: 6, pinned: true, value: `'<\\/script>'` },
|
|
79
|
-
{ id: 7, pinned: true, value: `'<\\/script '` },
|
|
80
|
-
{ id: 8, pinned: true, value: `'<\\\\/SCRIPT '` },
|
|
81
|
-
{ id: 9, pinned: true, value: `'<\\\\/sCrIpT '` }
|
|
82
|
-
]
|
|
83
|
-
});
|
|
84
|
-
const notebook2 = toNotebook({
|
|
85
|
-
title: "Hello, world!",
|
|
86
|
-
cells: [
|
|
87
|
-
{ id: 2, mode: "js", pinned: true, value: `'</script>'` },
|
|
88
|
-
{ id: 3, mode: "js", pinned: true, value: `'</script '` },
|
|
89
|
-
{ id: 4, mode: "js", pinned: true, value: `'</SCRIPT '` },
|
|
90
|
-
{ id: 5, mode: "js", pinned: true, value: `'</sCrIpT '` },
|
|
91
|
-
{ id: 6, mode: "js", pinned: true, value: `'<\\/script>'` },
|
|
92
|
-
{ id: 7, mode: "js", pinned: true, value: `'<\\/script '` },
|
|
93
|
-
{ id: 8, mode: "js", pinned: true, value: `'<\\\\/SCRIPT '` },
|
|
94
|
-
{ id: 9, mode: "js", pinned: true, value: `'<\\\\/sCrIpT '` }
|
|
95
|
-
]
|
|
96
|
-
});
|
|
97
|
-
const html = serialize(notebook1);
|
|
98
|
-
assert.strictEqual(html.indexOf("'</script"), -1);
|
|
99
|
-
assert.deepStrictEqual(deserialize(html), notebook2);
|
|
100
|
-
});
|
|
101
|
-
test("serialization enforces unique ids", () => {
|
|
102
|
-
const notebook1 = toNotebook({
|
|
103
|
-
cells: [
|
|
104
|
-
{ id: 2, value: "one" },
|
|
105
|
-
{ id: 2, value: "two" }
|
|
106
|
-
]
|
|
107
|
-
});
|
|
108
|
-
const notebook2 = toNotebook({
|
|
109
|
-
cells: [
|
|
110
|
-
{ id: 2, value: "one" },
|
|
111
|
-
{ id: 3, value: "two" }
|
|
112
|
-
]
|
|
113
|
-
});
|
|
114
|
-
assert.deepStrictEqual(deserialize(serialize(notebook1)), notebook2);
|
|
115
|
-
});
|
|
116
|
-
test("deserialization populates missing ids", () => {
|
|
117
|
-
const notebook1 = toNotebook({
|
|
118
|
-
cells: [
|
|
119
|
-
{ value: "one" }, // missing id
|
|
120
|
-
{ id: 3, value: "three" },
|
|
121
|
-
{ value: "four" } // missing id
|
|
122
|
-
]
|
|
123
|
-
});
|
|
124
|
-
const notebook2 = toNotebook({
|
|
125
|
-
cells: [
|
|
126
|
-
{ id: 1, value: "one" },
|
|
127
|
-
{ id: 3, value: "three" },
|
|
128
|
-
{ id: 4, value: "four" }
|
|
129
|
-
]
|
|
130
|
-
});
|
|
131
|
-
assert.deepStrictEqual(deserialize(serialize(notebook1)), notebook2);
|
|
132
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
import { assert, test } from "vitest";
|
|
2
|
-
import { sluggify } from "./sluggify.js";
|
|
3
|
-
test("returns the default fallback for empty slugs", () => {
|
|
4
|
-
assert.strictEqual(sluggify(""), "untitled");
|
|
5
|
-
assert.strictEqual(sluggify(" "), "untitled");
|
|
6
|
-
assert.strictEqual(sluggify("---"), "untitled");
|
|
7
|
-
assert.strictEqual(sluggify("##)!@#(*"), "untitled");
|
|
8
|
-
});
|
|
9
|
-
test("returns the given fallback for empty slugs", () => {
|
|
10
|
-
assert.strictEqual(sluggify("", { fallback: "foo" }), "foo");
|
|
11
|
-
assert.strictEqual(sluggify(" ", { fallback: "foo" }), "foo");
|
|
12
|
-
assert.strictEqual(sluggify("---", { fallback: "foo" }), "foo");
|
|
13
|
-
assert.strictEqual(sluggify("##)!@#(*", { fallback: "foo" }), "foo");
|
|
14
|
-
});
|
|
15
|
-
test("lowercases", () => {
|
|
16
|
-
assert.strictEqual(sluggify("HELLO WORLD"), "hello-world");
|
|
17
|
-
assert.strictEqual(sluggify("HelLo WorlD"), "hello-world");
|
|
18
|
-
});
|
|
19
|
-
test("removes emoji", () => {
|
|
20
|
-
assert.strictEqual(sluggify("HELLO 😎"), "hello");
|
|
21
|
-
assert.strictEqual(sluggify("HELLO 😎 world"), "hello-world");
|
|
22
|
-
assert.strictEqual(sluggify("HELLO 💩 world"), "hello-world");
|
|
23
|
-
});
|
|
24
|
-
test("trims leading and trailing spaces", () => {
|
|
25
|
-
assert.strictEqual(sluggify(" hello world "), "hello-world");
|
|
26
|
-
});
|
|
27
|
-
test("collapses contiguous spaces", () => {
|
|
28
|
-
assert.strictEqual(sluggify(" hello world "), "hello-world");
|
|
29
|
-
});
|
|
30
|
-
test("removes punctuation", () => {
|
|
31
|
-
assert.strictEqual(sluggify("Hello, world!"), "hello-world");
|
|
32
|
-
assert.strictEqual(sluggify("Hello, 'world'!"), "hello-world");
|
|
33
|
-
assert.strictEqual(sluggify('Hello, "world"!'), "hello-world");
|
|
34
|
-
assert.strictEqual(sluggify("Hello, “world”!"), "hello-world");
|
|
35
|
-
assert.strictEqual(sluggify("Hello, ‘world’!"), "hello-world");
|
|
36
|
-
assert.strictEqual(sluggify("Hello, fo'c's'le!"), "hello-focsle");
|
|
37
|
-
assert.strictEqual(sluggify("Hello, fo’c’s’le!"), "hello-focsle");
|
|
38
|
-
});
|
|
39
|
-
test("removes diacritics and combiners", () => {
|
|
40
|
-
assert.strictEqual(sluggify("Héllö, wørld!"), "hello-w-rld");
|
|
41
|
-
assert.strictEqual(sluggify("z̷̢̡̟͍̺͛͆͐̀ą̸̻̰̪͈͒͝ͅl̸͇̘̓g̶̡͈͒̾̉̽̑̅ö̸̧̟́͆"), "zalgo");
|
|
42
|
-
});
|
|
43
|
-
test("allows up to 50 characters after stripping", () => {
|
|
44
|
-
assert.strictEqual(sluggify("‘A‘ohe pu‘u ki‘eki‘e ke ho ‘ā‘o ‘ia e pi‘i"), "aohe-puu-kiekie-ke-ho-ao-ia-e-pii");
|
|
45
|
-
assert.strictEqual(sluggify("0123456789012345678901234567890123456789012345678"), "0123456789012345678901234567890123456789012345678");
|
|
46
|
-
assert.strictEqual(sluggify("01234567890123456789012345678901234567890123456789"), "01234567890123456789012345678901234567890123456789");
|
|
47
|
-
assert.strictEqual(sluggify("012345678901234567890123456789012345678901234567890"), "01234567890123456789012345678901234567890123456789");
|
|
48
|
-
assert.strictEqual(sluggify("01234567890 1234567890 1234567890 1234567890 12345678"), "01234567890-1234567890-1234567890-1234567890-12345");
|
|
49
|
-
assert.strictEqual(sluggify("01234567890 1234567890 1234567890 1234567890 123456789"), "01234567890-1234567890-1234567890-1234567890-12345");
|
|
50
|
-
assert.strictEqual(sluggify("01234567890 1234567890 1234567890 1234567890 1234567890"), "01234567890-1234567890-1234567890-1234567890-12345");
|
|
51
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,78 +0,0 @@
|
|
|
1
|
-
// @vitest-environment jsdom
|
|
2
|
-
import { html } from "htl";
|
|
3
|
-
import { assert, test } from "vitest";
|
|
4
|
-
import { collectAssets } from "./assets.js";
|
|
5
|
-
function getAssets(root) {
|
|
6
|
-
const assets = new Set();
|
|
7
|
-
collectAssets(assets, root);
|
|
8
|
-
return assets;
|
|
9
|
-
}
|
|
10
|
-
test("find asset paths in descendants", () => {
|
|
11
|
-
assert.deepStrictEqual(new Set([
|
|
12
|
-
"./a-href.txt",
|
|
13
|
-
"./audio-source-src.wav",
|
|
14
|
-
"./audio-src.wav",
|
|
15
|
-
"./img-src.png",
|
|
16
|
-
"./img-srcset-src.png",
|
|
17
|
-
"./img-srcset.png",
|
|
18
|
-
"./link.css",
|
|
19
|
-
"./picture-source-src.png",
|
|
20
|
-
"./picture-srcset-src.png",
|
|
21
|
-
"./picture-srcset.png",
|
|
22
|
-
"./video-source-src.mp4",
|
|
23
|
-
"./video-src.mp4"
|
|
24
|
-
]), getAssets(html `<div>
|
|
25
|
-
<a href="./a-href.txt" download>download</a>
|
|
26
|
-
<audio><source src="./audio-source-src.wav"></audio>
|
|
27
|
-
<audio src="./audio-src.wav"></audio>
|
|
28
|
-
<img src="./img-src.png">
|
|
29
|
-
<img src="./img-srcset-src.png" srcset="./img-srcset.png 2x">
|
|
30
|
-
<link href="./link.css" rel="stylesheet">
|
|
31
|
-
<picture><source src="./picture-source-src.png"></picture>
|
|
32
|
-
<picture><source src="./picture-srcset-src.png" srcset="./picture-srcset.png 2x"></picture>
|
|
33
|
-
<video><source src="./video-source-src.mp4"></video>
|
|
34
|
-
<video src="./video-src.mp4"></video>
|
|
35
|
-
</div>`));
|
|
36
|
-
});
|
|
37
|
-
test("decodes paths", () => {
|
|
38
|
-
assert.deepStrictEqual(new Set(["./hello world.png"]), getAssets(html `<div><img src="./hello%20world.png"></div>`));
|
|
39
|
-
});
|
|
40
|
-
test("strips query strings and anchor fragments from the path", () => {
|
|
41
|
-
assert.deepStrictEqual(new Set(["./img1.png", "./img2.png", "./img3.png", "./img4.png"]), getAssets(html `<div>
|
|
42
|
-
<img src="./img1.png?foo=bar">
|
|
43
|
-
<img src="./img2.png#baz">
|
|
44
|
-
<img src="./img3.png?foo#bar">
|
|
45
|
-
<img src="./img4.png#foo?bar">
|
|
46
|
-
</div>`));
|
|
47
|
-
});
|
|
48
|
-
test("adds a leading dot slash to relative paths", () => {
|
|
49
|
-
assert.deepStrictEqual(new Set([
|
|
50
|
-
"./file.png",
|
|
51
|
-
"./path/to/file.png",
|
|
52
|
-
"/root.png",
|
|
53
|
-
"./dot-slash.png",
|
|
54
|
-
"../dot-dot-slash.png"
|
|
55
|
-
]), getAssets(html `<div>
|
|
56
|
-
<img src="file.png">
|
|
57
|
-
<img src="path/to/file.png">
|
|
58
|
-
<img src="/root.png">
|
|
59
|
-
<img src="./dot-slash.png">
|
|
60
|
-
<img src="../dot-dot-slash.png">
|
|
61
|
-
</div>`));
|
|
62
|
-
});
|
|
63
|
-
test("ignores protocol links", () => {
|
|
64
|
-
assert.deepStrictEqual(new Set([]), getAssets(html `<div>
|
|
65
|
-
<img src="https://example.com/test.png">
|
|
66
|
-
</div>`));
|
|
67
|
-
});
|
|
68
|
-
test("ignores fragment links", () => {
|
|
69
|
-
assert.deepStrictEqual(new Set([]), getAssets(html `<div>
|
|
70
|
-
<a href="#test" download>download</a>
|
|
71
|
-
</div>`));
|
|
72
|
-
});
|
|
73
|
-
test("ignores rel=external elements", () => {
|
|
74
|
-
assert.deepStrictEqual(new Set(["./internal.txt"]), getAssets(html `<div>
|
|
75
|
-
<a href="external.txt" rel="external" download>download</a>
|
|
76
|
-
<a href="internal.txt" rel="notexternal" download>download</a>
|
|
77
|
-
</div>`));
|
|
78
|
-
});
|