@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.
Files changed (182) hide show
  1. package/LICENSE +13 -0
  2. package/README.md +7 -0
  3. package/dist/bin/build.d.ts +2 -0
  4. package/dist/bin/build.js +63 -0
  5. package/dist/bin/download.d.ts +2 -0
  6. package/dist/bin/download.js +49 -0
  7. package/dist/bin/notebooks.d.ts +2 -0
  8. package/dist/bin/notebooks.js +33 -0
  9. package/dist/bin/preview.d.ts +2 -0
  10. package/dist/bin/preview.js +48 -0
  11. package/dist/package.json +73 -0
  12. package/dist/src/index.d.ts +5 -0
  13. package/dist/src/index.js +5 -0
  14. package/dist/src/javascript/assignments.d.ts +2 -0
  15. package/dist/src/javascript/assignments.js +37 -0
  16. package/dist/src/javascript/assignments.test.d.ts +1 -0
  17. package/dist/src/javascript/assignments.test.js +33 -0
  18. package/dist/src/javascript/awaits.d.ts +2 -0
  19. package/dist/src/javascript/awaits.js +23 -0
  20. package/dist/src/javascript/awaits.test.d.ts +1 -0
  21. package/dist/src/javascript/awaits.test.js +22 -0
  22. package/dist/src/javascript/declarations.d.ts +2 -0
  23. package/dist/src/javascript/declarations.js +45 -0
  24. package/dist/src/javascript/files.d.ts +3 -0
  25. package/dist/src/javascript/files.js +18 -0
  26. package/dist/src/javascript/globals.d.ts +1 -0
  27. package/dist/src/javascript/globals.js +86 -0
  28. package/dist/src/javascript/imports/jsr.d.ts +2 -0
  29. package/dist/src/javascript/imports/jsr.js +6 -0
  30. package/dist/src/javascript/imports/npm.d.ts +2 -0
  31. package/dist/src/javascript/imports/npm.js +47 -0
  32. package/dist/src/javascript/imports/npm.test.d.ts +1 -0
  33. package/dist/src/javascript/imports/npm.test.js +32 -0
  34. package/dist/src/javascript/imports/observable.d.ts +8 -0
  35. package/dist/src/javascript/imports/observable.js +64 -0
  36. package/dist/src/javascript/imports/observable.test.d.ts +1 -0
  37. package/dist/src/javascript/imports/observable.test.js +13 -0
  38. package/dist/src/javascript/imports.d.ts +21 -0
  39. package/dist/src/javascript/imports.js +146 -0
  40. package/dist/src/javascript/observable.d.ts +2 -0
  41. package/dist/src/javascript/observable.js +72 -0
  42. package/dist/src/javascript/parse.d.ts +11 -0
  43. package/dist/src/javascript/parse.js +53 -0
  44. package/dist/src/javascript/references.d.ts +8 -0
  45. package/dist/src/javascript/references.js +129 -0
  46. package/dist/src/javascript/references.test.d.ts +1 -0
  47. package/dist/src/javascript/references.test.js +38 -0
  48. package/dist/src/javascript/sourcemap.d.ts +21 -0
  49. package/dist/src/javascript/sourcemap.js +143 -0
  50. package/dist/src/javascript/sourcemap.test.d.ts +1 -0
  51. package/dist/src/javascript/sourcemap.test.js +88 -0
  52. package/dist/src/javascript/strings.d.ts +8 -0
  53. package/dist/src/javascript/strings.js +42 -0
  54. package/dist/src/javascript/strings.test.d.ts +1 -0
  55. package/dist/src/javascript/strings.test.js +31 -0
  56. package/dist/src/javascript/syntaxError.d.ts +2 -0
  57. package/dist/src/javascript/syntaxError.js +5 -0
  58. package/dist/src/javascript/template.d.ts +3 -0
  59. package/dist/src/javascript/template.js +141 -0
  60. package/dist/src/javascript/template.test.d.ts +1 -0
  61. package/dist/src/javascript/template.test.js +32 -0
  62. package/dist/src/javascript/transpile.d.ts +25 -0
  63. package/dist/src/javascript/transpile.js +42 -0
  64. package/dist/src/javascript/transpile.test.d.ts +1 -0
  65. package/dist/src/javascript/transpile.test.js +29 -0
  66. package/dist/src/javascript/walk.d.ts +5 -0
  67. package/dist/src/javascript/walk.js +13 -0
  68. package/dist/src/lib/notebook.d.ts +35 -0
  69. package/dist/src/lib/notebook.js +19 -0
  70. package/dist/src/lib/notebook.test.d.ts +1 -0
  71. package/dist/src/lib/notebook.test.js +26 -0
  72. package/dist/src/lib/serialize.d.ts +5 -0
  73. package/dist/src/lib/serialize.js +97 -0
  74. package/dist/src/lib/serialize.test.d.ts +1 -0
  75. package/dist/src/lib/serialize.test.js +125 -0
  76. package/dist/src/lib/text.d.ts +1 -0
  77. package/dist/src/lib/text.js +3 -0
  78. package/dist/src/runtime/define.d.ts +28 -0
  79. package/dist/src/runtime/define.js +62 -0
  80. package/dist/src/runtime/display.d.ts +16 -0
  81. package/dist/src/runtime/display.js +60 -0
  82. package/dist/src/runtime/index.d.ts +11 -0
  83. package/dist/src/runtime/index.js +14 -0
  84. package/dist/src/runtime/inspect.d.ts +3 -0
  85. package/dist/src/runtime/inspect.js +43 -0
  86. package/dist/src/runtime/stdlib/assets.d.ts +4 -0
  87. package/dist/src/runtime/stdlib/assets.js +110 -0
  88. package/dist/src/runtime/stdlib/assets.test.d.ts +1 -0
  89. package/dist/src/runtime/stdlib/assets.test.js +78 -0
  90. package/dist/src/runtime/stdlib/dom/canvas.d.ts +1 -0
  91. package/dist/src/runtime/stdlib/dom/canvas.js +6 -0
  92. package/dist/src/runtime/stdlib/dom/context2d.d.ts +1 -0
  93. package/dist/src/runtime/stdlib/dom/context2d.js +9 -0
  94. package/dist/src/runtime/stdlib/dom/index.d.ts +5 -0
  95. package/dist/src/runtime/stdlib/dom/index.js +5 -0
  96. package/dist/src/runtime/stdlib/dom/svg.d.ts +1 -0
  97. package/dist/src/runtime/stdlib/dom/svg.js +7 -0
  98. package/dist/src/runtime/stdlib/dom/text.d.ts +1 -0
  99. package/dist/src/runtime/stdlib/dom/text.js +3 -0
  100. package/dist/src/runtime/stdlib/dom/uid.d.ts +8 -0
  101. package/dist/src/runtime/stdlib/dom/uid.js +25 -0
  102. package/dist/src/runtime/stdlib/dot.d.ts +2 -0
  103. package/dist/src/runtime/stdlib/dot.js +34 -0
  104. package/dist/src/runtime/stdlib/duckdb.d.ts +24 -0
  105. package/dist/src/runtime/stdlib/duckdb.js +379 -0
  106. package/dist/src/runtime/stdlib/fileAttachment.d.ts +71 -0
  107. package/dist/src/runtime/stdlib/fileAttachment.js +199 -0
  108. package/dist/src/runtime/stdlib/generators/index.d.ts +5 -0
  109. package/dist/src/runtime/stdlib/generators/index.js +5 -0
  110. package/dist/src/runtime/stdlib/generators/input.d.ts +1 -0
  111. package/dist/src/runtime/stdlib/generators/input.js +45 -0
  112. package/dist/src/runtime/stdlib/generators/now.d.ts +1 -0
  113. package/dist/src/runtime/stdlib/generators/now.js +5 -0
  114. package/dist/src/runtime/stdlib/generators/observe.d.ts +1 -0
  115. package/dist/src/runtime/stdlib/generators/observe.js +31 -0
  116. package/dist/src/runtime/stdlib/generators/queue.d.ts +1 -0
  117. package/dist/src/runtime/stdlib/generators/queue.js +27 -0
  118. package/dist/src/runtime/stdlib/generators/width.d.ts +1 -0
  119. package/dist/src/runtime/stdlib/generators/width.js +13 -0
  120. package/dist/src/runtime/stdlib/highlight.d.ts +2 -0
  121. package/dist/src/runtime/stdlib/highlight.js +76 -0
  122. package/dist/src/runtime/stdlib/index.d.ts +56 -0
  123. package/dist/src/runtime/stdlib/index.js +23 -0
  124. package/dist/src/runtime/stdlib/inputs.css +15 -0
  125. package/dist/src/runtime/stdlib/inputs.d.ts +2 -0
  126. package/dist/src/runtime/stdlib/inputs.js +2 -0
  127. package/dist/src/runtime/stdlib/leaflet.d.ts +1 -0
  128. package/dist/src/runtime/stdlib/leaflet.js +7 -0
  129. package/dist/src/runtime/stdlib/mapboxgl.d.ts +1 -0
  130. package/dist/src/runtime/stdlib/mapboxgl.js +5 -0
  131. package/dist/src/runtime/stdlib/md.d.ts +5 -0
  132. package/dist/src/runtime/stdlib/md.js +72 -0
  133. package/dist/src/runtime/stdlib/mermaid.d.ts +2 -0
  134. package/dist/src/runtime/stdlib/mermaid.js +11 -0
  135. package/dist/src/runtime/stdlib/mutable.d.ts +8 -0
  136. package/dist/src/runtime/stdlib/mutable.js +30 -0
  137. package/dist/src/runtime/stdlib/observer.d.ts +16 -0
  138. package/dist/src/runtime/stdlib/observer.js +42 -0
  139. package/dist/src/runtime/stdlib/recommendedLibraries.d.ts +25 -0
  140. package/dist/src/runtime/stdlib/recommendedLibraries.js +26 -0
  141. package/dist/src/runtime/stdlib/require.d.ts +4 -0
  142. package/dist/src/runtime/stdlib/require.js +40 -0
  143. package/dist/src/runtime/stdlib/sampleDatasets.d.ts +12 -0
  144. package/dist/src/runtime/stdlib/sampleDatasets.js +31 -0
  145. package/dist/src/runtime/stdlib/sql.d.ts +5 -0
  146. package/dist/src/runtime/stdlib/sql.js +5 -0
  147. package/dist/src/runtime/stdlib/template.d.ts +7 -0
  148. package/dist/src/runtime/stdlib/template.js +2 -0
  149. package/dist/src/runtime/stdlib/tex.d.ts +7 -0
  150. package/dist/src/runtime/stdlib/tex.js +18 -0
  151. package/dist/src/runtime/stdlib/vega-lite.d.ts +1 -0
  152. package/dist/src/runtime/stdlib/vega-lite.js +4 -0
  153. package/dist/src/styles/abstract-dark.css +14 -0
  154. package/dist/src/styles/abstract-light.css +14 -0
  155. package/dist/src/styles/global.css +266 -0
  156. package/dist/src/styles/highlight.css +47 -0
  157. package/dist/src/styles/index.css +14 -0
  158. package/dist/src/styles/inspector.css +89 -0
  159. package/dist/src/styles/plot.css +7 -0
  160. package/dist/src/styles/syntax-dark.css +12 -0
  161. package/dist/src/styles/syntax-light.css +12 -0
  162. package/dist/src/styles/theme-air.css +7 -0
  163. package/dist/src/styles/theme-coffee.css +7 -0
  164. package/dist/src/styles/theme-cotton.css +7 -0
  165. package/dist/src/styles/theme-deep-space.css +16 -0
  166. package/dist/src/styles/theme-glacier.css +7 -0
  167. package/dist/src/styles/theme-ink.css +7 -0
  168. package/dist/src/styles/theme-midnight.css +7 -0
  169. package/dist/src/styles/theme-near-midnight.css +7 -0
  170. package/dist/src/styles/theme-ocean-floor.css +7 -0
  171. package/dist/src/styles/theme-parchment.css +7 -0
  172. package/dist/src/styles/theme-slate.css +7 -0
  173. package/dist/src/styles/theme-stark.css +16 -0
  174. package/dist/src/styles/theme-sun-faded.css +7 -0
  175. package/dist/src/templates/default.html +31 -0
  176. package/dist/src/vite/config.d.ts +2 -0
  177. package/dist/src/vite/config.js +30 -0
  178. package/dist/src/vite/index.d.ts +2 -0
  179. package/dist/src/vite/index.js +2 -0
  180. package/dist/src/vite/observable.d.ts +12 -0
  181. package/dist/src/vite/observable.js +176 -0
  182. package/package.json +73 -0
@@ -0,0 +1,21 @@
1
+ interface Position {
2
+ line: number;
3
+ column: number;
4
+ }
5
+ export declare class Sourcemap {
6
+ readonly input: string;
7
+ private readonly _edits;
8
+ constructor(input: string);
9
+ private _bisectLeft;
10
+ private _bisectRight;
11
+ private _subsume;
12
+ insertLeft(index: number, value: string): typeof this;
13
+ insertRight(index: number, value: string): typeof this;
14
+ delete(start: number, end: number): typeof this;
15
+ replaceLeft(start: number, end: number, value: string): typeof this;
16
+ replaceRight(start: number, end: number, value: string): typeof this;
17
+ translate(position: Position): Position;
18
+ trim(): typeof this;
19
+ toString(): string;
20
+ }
21
+ export {};
@@ -0,0 +1,143 @@
1
+ // @ts-expect-error lineBreakG is private
2
+ import { lineBreakG } from "acorn";
3
+ export class Sourcemap {
4
+ constructor(input) {
5
+ Object.defineProperty(this, "input", {
6
+ enumerable: true,
7
+ configurable: true,
8
+ writable: true,
9
+ value: void 0
10
+ });
11
+ Object.defineProperty(this, "_edits", {
12
+ enumerable: true,
13
+ configurable: true,
14
+ writable: true,
15
+ value: void 0
16
+ });
17
+ this.input = input;
18
+ this._edits = [];
19
+ }
20
+ _bisectLeft(index) {
21
+ let lo = 0;
22
+ let hi = this._edits.length;
23
+ while (lo < hi) {
24
+ const mid = (lo + hi) >>> 1;
25
+ if (this._edits[mid].start < index)
26
+ lo = mid + 1;
27
+ else
28
+ hi = mid;
29
+ }
30
+ return lo;
31
+ }
32
+ _bisectRight(index) {
33
+ let lo = 0;
34
+ let hi = this._edits.length;
35
+ while (lo < hi) {
36
+ const mid = (lo + hi) >>> 1;
37
+ if (this._edits[mid].start > index)
38
+ hi = mid;
39
+ else
40
+ lo = mid + 1;
41
+ }
42
+ return lo;
43
+ }
44
+ _subsume(start, end) {
45
+ let n = 0;
46
+ for (let i = 0; i < this._edits.length; ++i) {
47
+ const e = this._edits[i];
48
+ if (start <= e.start && e.end < end)
49
+ continue;
50
+ this._edits[n++] = e;
51
+ }
52
+ this._edits.length = n;
53
+ }
54
+ insertLeft(index, value) {
55
+ return this.replaceLeft(index, index, value);
56
+ }
57
+ insertRight(index, value) {
58
+ return this.replaceRight(index, index, value);
59
+ }
60
+ delete(start, end) {
61
+ return this.replaceRight(start, end, "");
62
+ }
63
+ replaceLeft(start, end, value) {
64
+ this._subsume(start, end);
65
+ this._edits.splice(this._bisectLeft(start), 0, { start, end, value });
66
+ return this;
67
+ }
68
+ replaceRight(start, end, value) {
69
+ this._subsume(start, end);
70
+ this._edits.splice(this._bisectRight(start), 0, { start, end, value });
71
+ return this;
72
+ }
73
+ translate(position) {
74
+ let index = 0;
75
+ let ci = { line: 1, column: 0 };
76
+ let co = { line: 1, column: 0 };
77
+ for (const { start, end, value } of this._edits) {
78
+ if (start > index) {
79
+ const l = positionLength(this.input, index, start);
80
+ const ci2 = positionAdd(ci, l);
81
+ const co2 = positionAdd(co, l);
82
+ if (positionCompare(co2, position) > 0)
83
+ break;
84
+ ci = ci2;
85
+ co = co2;
86
+ }
87
+ const il = positionLength(this.input, start, end);
88
+ const ol = positionLength(value);
89
+ const ci2 = positionAdd(ci, il);
90
+ const co2 = positionAdd(co, ol);
91
+ if (positionCompare(co2, position) > 0)
92
+ return ci;
93
+ ci = ci2;
94
+ co = co2;
95
+ index = end;
96
+ }
97
+ const l = positionSubtract(position, co);
98
+ return positionAdd(ci, l);
99
+ }
100
+ trim() {
101
+ const input = this.input;
102
+ if (input.startsWith("\n"))
103
+ this.delete(0, 1); // TODO better trim
104
+ if (input.endsWith("\n"))
105
+ this.delete(input.length - 1, input.length); // TODO better trim
106
+ return this;
107
+ }
108
+ toString() {
109
+ let output = "";
110
+ let index = 0;
111
+ for (const { start, end, value } of this._edits) {
112
+ if (start > index)
113
+ output += this.input.slice(index, start);
114
+ output += value;
115
+ index = end;
116
+ }
117
+ output += this.input.slice(index);
118
+ return output;
119
+ }
120
+ }
121
+ function positionCompare(a, b) {
122
+ return a.line - b.line || a.column - b.column;
123
+ }
124
+ function positionLength(input, start = 0, end = input.length) {
125
+ let match;
126
+ let line = 0;
127
+ lineBreakG.lastIndex = start;
128
+ while ((match = lineBreakG.exec(input)) && match.index < end) {
129
+ ++line;
130
+ start = match.index + match[0].length;
131
+ }
132
+ return { line, column: end - start };
133
+ }
134
+ function positionSubtract(b, a) {
135
+ return b.line === a.line
136
+ ? { line: 0, column: b.column - a.column }
137
+ : { line: b.line - a.line, column: b.column };
138
+ }
139
+ function positionAdd(p, l) {
140
+ return l.line === 0
141
+ ? { line: p.line, column: p.column + l.column }
142
+ : { line: p.line + l.line, column: l.column };
143
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,88 @@
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
+ });
@@ -0,0 +1,8 @@
1
+ import type { BinaryExpression, Literal, Node, TemplateLiteral } from "acorn";
2
+ export type StringLiteral = (Literal & {
3
+ value: string;
4
+ }) | TemplateLiteral | BinaryExpression;
5
+ export declare function isLiteral(node: Node): node is Literal;
6
+ export declare function isTemplateLiteral(node: Node): node is TemplateLiteral;
7
+ export declare function isStringLiteral(node: Node): node is StringLiteral;
8
+ export declare function getStringLiteralValue(node: StringLiteral): string;
@@ -0,0 +1,42 @@
1
+ export function isLiteral(node) {
2
+ return node.type === "Literal";
3
+ }
4
+ export function isTemplateLiteral(node) {
5
+ return node.type === "TemplateLiteral";
6
+ }
7
+ export function isStringLiteral(node) {
8
+ return isLiteral(node)
9
+ ? /^['"]/.test(node.raw)
10
+ : isTemplateLiteral(node)
11
+ ? node.expressions.every(isStringLiteral)
12
+ : isBinaryExpression(node)
13
+ ? node.operator === "+" && isStringLiteral(node.left) && isStringLiteral(node.right)
14
+ : isMemberExpression(node)
15
+ ? "value" in node // param
16
+ : false;
17
+ }
18
+ export function getStringLiteralValue(node) {
19
+ return node.type === "TemplateLiteral"
20
+ ? getTemplateLiteralValue(node)
21
+ : node.type === "BinaryExpression"
22
+ ? getBinaryExpressionValue(node)
23
+ : node.value; // Literal or ParamReference
24
+ }
25
+ function getTemplateLiteralValue(node) {
26
+ let value = node.quasis[0].value.cooked;
27
+ for (let i = 0; i < node.expressions.length; ++i) {
28
+ value += getStringLiteralValue(node.expressions[i]);
29
+ value += node.quasis[i + 1].value.cooked;
30
+ }
31
+ return value;
32
+ }
33
+ function getBinaryExpressionValue(node) {
34
+ return (getStringLiteralValue(node.left) +
35
+ getStringLiteralValue(node.right));
36
+ }
37
+ function isMemberExpression(node) {
38
+ return node.type === "MemberExpression";
39
+ }
40
+ function isBinaryExpression(node) {
41
+ return node.type === "BinaryExpression";
42
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,31 @@
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
+ });
@@ -0,0 +1,2 @@
1
+ import type { Node } from "acorn";
2
+ export declare function syntaxError(message: string, node: Node, input: string): SyntaxError;
@@ -0,0 +1,5 @@
1
+ import { getLineInfo } from "acorn";
2
+ export function syntaxError(message, node, input) {
3
+ const { line, column } = getLineInfo(input, node.start);
4
+ return new SyntaxError(`${message} (${line}:${column})`);
5
+ }
@@ -0,0 +1,3 @@
1
+ import type { TemplateLiteral } from "acorn";
2
+ export declare function parseTemplate(input: string): TemplateLiteral;
3
+ export declare function transpileTemplate(input: string, tag?: string, raw?: boolean): string;
@@ -0,0 +1,141 @@
1
+ import { TokContext, tokTypes as tt, Parser } from "acorn";
2
+ import { acornOptions } from "./parse.js";
3
+ import { Sourcemap } from "./sourcemap.js";
4
+ const CODE_DOLLAR = 36;
5
+ const CODE_BACKSLASH = 92;
6
+ const CODE_BACKTICK = 96;
7
+ const CODE_BRACEL = 123;
8
+ // Based on acorn’s q_tmpl. We will use this to initialize the parser context so our
9
+ // `readTemplateToken` override is called. `readTemplateToken` is based on acorn's `readTmplToken`
10
+ // which is used inside template literals. Our version allows backQuotes.
11
+ const o_tmpl = new TokContext("`", // token
12
+ true, // isExpr
13
+ true, // preserveSpace
14
+ (parser) => parser.readTemplateToken() // override
15
+ );
16
+ // Adapted from https://github.com/observablehq/parser/blob/b6ec1db139913493b39c9d0ccb02a1636570a64e/src/parse.js#L233
17
+ class TemplateCellParser extends Parser {
18
+ constructor(options, input, startPos) {
19
+ super(options, input, startPos);
20
+ this.type = tt.backQuote; // initially inside a backQuote
21
+ this.exprAllowed = false;
22
+ }
23
+ initialContext() {
24
+ return [o_tmpl];
25
+ }
26
+ parseTopLevel(node) {
27
+ if (this.type === tt.eof)
28
+ this.value = ""; // fix for nextToken calling finishToken(tt.eof)
29
+ const isTagged = true;
30
+ const template = node;
31
+ template.expressions = [];
32
+ let curElt = this.parseTemplateElement({ isTagged });
33
+ template.quasis = [curElt];
34
+ while (this.type !== tt.eof) {
35
+ this.expect(tt.dollarBraceL);
36
+ template.expressions.push(this.parseExpression());
37
+ this.expect(tt.braceR);
38
+ template.quasis.push((curElt = this.parseTemplateElement({ isTagged })));
39
+ }
40
+ curElt.tail = true;
41
+ this.next();
42
+ this.finishNode(template, "TemplateLiteral");
43
+ this.expect(tt.eof);
44
+ return template;
45
+ }
46
+ readTemplateToken() {
47
+ out: for (; this.pos < this.input.length; this.pos++) {
48
+ switch (this.input.charCodeAt(this.pos)) {
49
+ case CODE_BACKSLASH: {
50
+ if (this.pos < this.input.length - 1)
51
+ ++this.pos; // not a terminal slash
52
+ break;
53
+ }
54
+ case CODE_DOLLAR: {
55
+ if (this.input.charCodeAt(this.pos + 1) === CODE_BRACEL) {
56
+ if (this.pos === this.start && this.type === tt.invalidTemplate) {
57
+ this.pos += 2;
58
+ return this.finishToken(tt.dollarBraceL);
59
+ }
60
+ break out;
61
+ }
62
+ break;
63
+ }
64
+ }
65
+ }
66
+ return this.finishToken(tt.invalidTemplate, this.input.slice(this.start, this.pos));
67
+ }
68
+ }
69
+ export function parseTemplate(input) {
70
+ return TemplateCellParser.parse(input, acornOptions);
71
+ }
72
+ export function transpileTemplate(input, tag = "", raw = false) {
73
+ if (!input)
74
+ return input;
75
+ const source = new Sourcemap(input);
76
+ const node = parseTemplate(input);
77
+ (raw ? escapeRawTemplateElements : escapeTemplateElements)(source, node);
78
+ source.insertLeft(node.start, "`");
79
+ source.insertRight(node.end, "`");
80
+ source.insertLeft(node.start, tag);
81
+ return String(source);
82
+ }
83
+ function escapeTemplateElements(source, node) {
84
+ for (const quasi of node.quasis) {
85
+ escapeBacktick(source, quasi);
86
+ escapeBackslash(source, quasi);
87
+ }
88
+ }
89
+ function escapeRawTemplateElements(source, node) {
90
+ for (const quasi of node.quasis) {
91
+ escapeBacktick(source, quasi);
92
+ }
93
+ interpolateTerminalBackslash(source);
94
+ }
95
+ function escapeBacktick(source, { start, end }) {
96
+ const { input } = source;
97
+ for (let i = start; i < end; ++i) {
98
+ if (input.charCodeAt(i) === CODE_BACKTICK) {
99
+ source.insertRight(i, "\\");
100
+ }
101
+ }
102
+ }
103
+ function escapeBackslash(source, { start, end }) {
104
+ const { input } = source;
105
+ let afterDollar = false;
106
+ let oddBackslashes = false;
107
+ for (let i = start; i < end; ++i) {
108
+ switch (input.charCodeAt(i)) {
109
+ case CODE_DOLLAR: {
110
+ afterDollar = true;
111
+ oddBackslashes = false;
112
+ break;
113
+ }
114
+ case CODE_BACKSLASH: {
115
+ oddBackslashes = !oddBackslashes;
116
+ if (afterDollar && input.charCodeAt(i + 1) === CODE_BRACEL)
117
+ continue;
118
+ if (oddBackslashes && input.charCodeAt(i + 1) === CODE_DOLLAR && input.charCodeAt(i + 2) === CODE_BRACEL)
119
+ continue; // prettier-ignore
120
+ source.insertRight(i, "\\");
121
+ break;
122
+ }
123
+ default: {
124
+ afterDollar = false;
125
+ oddBackslashes = false;
126
+ break;
127
+ }
128
+ }
129
+ }
130
+ }
131
+ function interpolateTerminalBackslash(source) {
132
+ const { input } = source;
133
+ let oddBackslashes = false;
134
+ for (let i = input.length - 1; i >= 0; i--) {
135
+ if (input.charCodeAt(i) !== CODE_BACKSLASH)
136
+ break;
137
+ oddBackslashes = !oddBackslashes;
138
+ }
139
+ if (oddBackslashes)
140
+ source.replaceRight(input.length - 1, input.length, "${'\\\\'}");
141
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,32 @@
1
+ import { expect, it } from "vitest";
2
+ import { parseTemplate, transpileTemplate } from "./template.js";
3
+ it("parses a simple template", () => {
4
+ expect(parseTemplate(`Hello, world!`)).toMatchSnapshot();
5
+ });
6
+ it("parses an empty template", () => {
7
+ expect(parseTemplate(``)).toMatchSnapshot();
8
+ });
9
+ it("parses a template with an interpolated expression", () => {
10
+ expect(parseTemplate(`Hello, $\{"world"}!`)).toMatchSnapshot();
11
+ });
12
+ it("parses a template with backquotes", () => {
13
+ expect(parseTemplate(`Hello, \`world\`!`)).toMatchSnapshot();
14
+ });
15
+ it("parses a template with backslashes", () => {
16
+ expect(parseTemplate(`Hello, \\world\\!`)).toMatchSnapshot();
17
+ });
18
+ it("transpiles a simple template", () => {
19
+ expect(transpileTemplate(`Hello, world!`)).toMatchSnapshot();
20
+ });
21
+ it("transpiles an empty template", () => {
22
+ expect(transpileTemplate(``)).toMatchSnapshot();
23
+ });
24
+ it("transpiles a template with an interpolated expression", () => {
25
+ expect(transpileTemplate(`Hello, $\{"world"}!`)).toMatchSnapshot();
26
+ });
27
+ it("transpiles a template with backquotes", () => {
28
+ expect(transpileTemplate(`Hello, \`world\`!`)).toMatchSnapshot();
29
+ });
30
+ it("transpiles a template with backslashes", () => {
31
+ expect(transpileTemplate(`Hello, \\world\\!`)).toMatchSnapshot();
32
+ });
@@ -0,0 +1,25 @@
1
+ import type { Cell } from "../lib/notebook.js";
2
+ export type TranspiledJavaScript = {
3
+ /** the source code of a JavaScript function defining the primary variable */
4
+ body: string;
5
+ /** any unbound references in body; corresponds to the body arguments, in order */
6
+ inputs?: string[];
7
+ /** if present, the body returns an object of named outputs; alternative to output */
8
+ outputs?: string[];
9
+ /** if present, the body returns a single named output; alternative to outputs */
10
+ output?: string;
11
+ /** whether to implicitly display the body value (e.g., an expression) */
12
+ autodisplay?: boolean;
13
+ /** whether to implicitly derive a view; for ojs compatibility; requires viewof output */
14
+ autoview?: boolean;
15
+ /** whether to implicitly derive a mutable; for ojs compatibility; requires mutable output */
16
+ automutable?: boolean;
17
+ };
18
+ export type TranspileOptions = {
19
+ /** If true, resolve local imports paths relative to document.baseURI. */
20
+ resolveLocalImports?: boolean;
21
+ /** If true, resolve file using import.meta.url (so Vite treats it as an asset). */
22
+ resolveFiles?: boolean;
23
+ };
24
+ export declare function transpile(input: string, mode: Cell["mode"], options?: TranspileOptions): TranspiledJavaScript;
25
+ export declare function transpileJavaScript(input: string, options?: TranspileOptions): TranspiledJavaScript;
@@ -0,0 +1,42 @@
1
+ import { rewriteFileExpressions } from "./files.js";
2
+ import { hasImportDeclaration, rewriteImportDeclarations, rewriteImportExpressions } from "./imports.js";
3
+ import { transpileObservable } from "./observable.js";
4
+ import { parseJavaScript } from "./parse.js";
5
+ import { Sourcemap } from "./sourcemap.js";
6
+ import { transpileTemplate } from "./template.js";
7
+ export function transpile(input, mode, options) {
8
+ return mode === "ojs"
9
+ ? transpileObservable(input, options) // TODO ojs+md etc.
10
+ : transpileJavaScript(transpileMode(input, mode), options);
11
+ }
12
+ function transpileMode(input, mode) {
13
+ if (mode === "js")
14
+ return input;
15
+ const tag = mode === "tex" ? "tex.block" : mode === "sql" ? "__sql(db, Inputs.table)" : mode; // for now
16
+ const raw = mode === "html" || mode === "tex" || mode === "dot";
17
+ return transpileTemplate(input, tag, raw);
18
+ }
19
+ export function transpileJavaScript(input, options) {
20
+ const cell = parseJavaScript(input);
21
+ let async = cell.async;
22
+ const inputs = Array.from(new Set(cell.references.map((r) => r.name)));
23
+ if (hasImportDeclaration(cell.body))
24
+ async = true;
25
+ const outputs = Array.from(new Set(cell.declarations?.map((r) => r.name)));
26
+ const output = new Sourcemap(input).trim();
27
+ rewriteImportDeclarations(output, cell.body, inputs, options);
28
+ rewriteImportExpressions(output, cell.body, options);
29
+ if (options?.resolveFiles)
30
+ rewriteFileExpressions(output, cell.body);
31
+ if (cell.expression)
32
+ output.insertLeft(0, `return (\n`);
33
+ output.insertLeft(0, `${async ? "async " : ""}(${inputs}) => {\n`);
34
+ if (outputs.length > 0)
35
+ output.insertRight(input.length, `\nreturn {${outputs}};`);
36
+ if (cell.expression)
37
+ output.insertRight(input.length, `\n)`);
38
+ output.insertRight(input.length, "\n}");
39
+ const body = String(output);
40
+ const autodisplay = cell.expression && !(inputs.includes("display") || inputs.includes("view"));
41
+ return { body, inputs, outputs, autodisplay };
42
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,29 @@
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 JavaScript programs", () => {
10
+ expect(transpile("const x = 1, y = 2;", "js")).toMatchSnapshot();
11
+ expect(transpile("x + y;", "js")).toMatchSnapshot();
12
+ expect(transpile("await z;", "js")).toMatchSnapshot();
13
+ });
14
+ it("transpiles static npm: imports", () => {
15
+ expect(transpile('import * as d3 from "npm:d3";', "js")).toMatchSnapshot();
16
+ expect(transpile('import _ from "npm:lodash";', "js")).toMatchSnapshot();
17
+ expect(transpile('import {} from "npm:d3";\nimport "npm:isoformat";', "js")).toMatchSnapshot();
18
+ });
19
+ it("transpiles dynamic npm: imports", () => {
20
+ expect(transpile('const d3 = await import("npm:d3");', "js")).toMatchSnapshot();
21
+ });
22
+ it("transpiles static observable: imports", () => {
23
+ expect(transpile('import {Scrubber} from "observable:@mbostock/scrubber";', "js")).toMatchSnapshot();
24
+ });
25
+ it("transpiles import.meta.resolve", () => {
26
+ expect(transpile('import.meta.resolve("npm:d3")', "js")).toMatchSnapshot();
27
+ expect(transpile('import.meta.resolve("./test")', "js", { resolveLocalImports: true })).toMatchSnapshot();
28
+ expect(transpile('import.meta.resolve("./test")', "js", { resolveLocalImports: false })).toMatchSnapshot();
29
+ });
@@ -0,0 +1,5 @@
1
+ import type { Node } from "acorn";
2
+ import type { AncestorVisitors, RecursiveVisitors, SimpleVisitors } from "acorn-walk";
3
+ export declare function ancestor<T>(node: Node, visitors: AncestorVisitors<T>): void;
4
+ export declare function recursive<T>(node: Node, state: T, functions: RecursiveVisitors<T>): void;
5
+ export declare function simple<T>(node: Node, visitors: SimpleVisitors<T>): void;
@@ -0,0 +1,13 @@
1
+ import { walk } from "@observablehq/parser";
2
+ import { ancestor as _ancestor } from "acorn-walk";
3
+ import { recursive as _recursive } from "acorn-walk";
4
+ import { simple as _simple } from "acorn-walk";
5
+ export function ancestor(node, visitors) {
6
+ return _ancestor(node, visitors, walk);
7
+ }
8
+ export function recursive(node, state, functions) {
9
+ return _recursive(node, state, functions, walk);
10
+ }
11
+ export function simple(node, visitors) {
12
+ return _simple(node, visitors, walk);
13
+ }