@observablehq/notebook-kit 1.7.12 → 1.9.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/dist/package.json CHANGED
@@ -5,7 +5,7 @@
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/observablehq/notebook-kit.git"
7
7
  },
8
- "version": "1.7.12",
8
+ "version": "1.9.0",
9
9
  "type": "module",
10
10
  "scripts": {
11
11
  "test": "vitest",
@@ -0,0 +1,10 @@
1
+ import type { Node, CallExpression } from "acorn";
2
+ export type FeatureExpression = CallExpression & {
3
+ argument: string;
4
+ };
5
+ /**
6
+ * Returns all calls to the specified feature (e.g., FileAttachment) in the
7
+ * specified body. Throws a SyntaxError if any of the calls are invalid (e.g.,
8
+ * when FileAttachment is passed a dynamic argument).
9
+ */
10
+ export declare function findFeatures(name: string, body: Node, input: string): FeatureExpression[];
@@ -0,0 +1,29 @@
1
+ import { getStringLiteralValue, isStringLiteral } from "./literal.js";
2
+ import { findReferences } from "./references.js";
3
+ import { syntaxError } from "./syntaxError.js";
4
+ import { simple } from "./walk.js";
5
+ /**
6
+ * Returns all calls to the specified feature (e.g., FileAttachment) in the
7
+ * specified body. Throws a SyntaxError if any of the calls are invalid (e.g.,
8
+ * when FileAttachment is passed a dynamic argument).
9
+ */
10
+ export function findFeatures(name, body, input) {
11
+ const filter = (ref) => ref.name === name;
12
+ const references = new Set(findReferences(body, { filterDeclaration: filter, filterReference: filter })); // prettier-ignore
13
+ const calls = [];
14
+ simple(body, {
15
+ CallExpression(node) {
16
+ const { callee } = node;
17
+ if (callee.type !== "Identifier" || !references.has(callee))
18
+ return;
19
+ const args = node.arguments;
20
+ if (args.length !== 1)
21
+ throw syntaxError(`${name} requires a single literal string argument`, node, input); // prettier-ignore
22
+ const [arg] = args;
23
+ if (!isStringLiteral(arg))
24
+ throw syntaxError(`${name} requires a single literal string argument`, node, input); // prettier-ignore
25
+ calls.push(Object.assign(node, { argument: getStringLiteralValue(arg) }));
26
+ }
27
+ });
28
+ return calls;
29
+ }
@@ -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
+ }
@@ -1,9 +1,13 @@
1
1
  import type { Expression, Identifier, Options, Program } from "acorn";
2
+ import type { FeatureExpression } from "./features.js";
2
3
  export declare const acornOptions: Options;
3
4
  export interface JavaScriptCell {
4
5
  body: Program | Expression;
5
6
  declarations: Identifier[] | null;
6
7
  references: Identifier[];
8
+ files: FeatureExpression[];
9
+ databases: FeatureExpression[];
10
+ secrets: FeatureExpression[];
7
11
  expression: boolean;
8
12
  async: boolean;
9
13
  }
@@ -1,7 +1,8 @@
1
1
  import { Parser, tokTypes } from "acorn";
2
- import { findReferences } from "./references.js";
3
- import { findDeclarations } from "./declarations.js";
4
2
  import { findAwaits } from "./awaits.js";
3
+ import { findDeclarations } from "./declarations.js";
4
+ import { findFeatures } from "./features.js";
5
+ import { findReferences } from "./references.js";
5
6
  export const acornOptions = {
6
7
  ecmaVersion: "latest",
7
8
  sourceType: "module"
@@ -27,6 +28,9 @@ export function parseJavaScript(input) {
27
28
  body,
28
29
  declarations: expression ? null : findDeclarations(body, input),
29
30
  references: findReferences(body, { input }),
31
+ files: findFeatures("FileAttachment", body, input),
32
+ databases: findFeatures("DatabaseClient", body, input),
33
+ secrets: findFeatures("Secret", body, input),
30
34
  expression: !!expression,
31
35
  async: findAwaits(body).length > 0
32
36
  };
@@ -112,6 +112,7 @@ export declare class NotebookRuntime {
112
112
  };
113
113
  Mutable: () => typeof import("./stdlib/mutable.js").Mutable;
114
114
  Promises: () => typeof import("./stdlib/promises/index.js");
115
+ Files: () => typeof import("./stdlib/files/index.js");
115
116
  DOM: () => typeof import("./stdlib/dom/index.js");
116
117
  require: () => {
117
118
  (...specifiers: unknown[]): Promise<unknown>;
@@ -0,0 +1 @@
1
+ export declare function buffer(file: Blob): Promise<ArrayBuffer>;
@@ -0,0 +1,8 @@
1
+ export function buffer(file) {
2
+ return new Promise((resolve, reject) => {
3
+ const reader = new FileReader();
4
+ reader.onload = () => resolve(reader.result);
5
+ reader.onerror = reject;
6
+ reader.readAsArrayBuffer(file);
7
+ });
8
+ }
@@ -0,0 +1,3 @@
1
+ export { buffer } from "./buffer.js";
2
+ export { text } from "./text.js";
3
+ export { url } from "./url.js";
@@ -0,0 +1,3 @@
1
+ export { buffer } from "./buffer.js";
2
+ export { text } from "./text.js";
3
+ export { url } from "./url.js";
@@ -0,0 +1 @@
1
+ export declare function text(file: Blob): Promise<string>;
@@ -0,0 +1,8 @@
1
+ export function text(file) {
2
+ return new Promise((resolve, reject) => {
3
+ const reader = new FileReader();
4
+ reader.onload = () => resolve(reader.result);
5
+ reader.onerror = reject;
6
+ reader.readAsText(file);
7
+ });
8
+ }
@@ -0,0 +1 @@
1
+ export declare function url(file: Blob): Promise<string>;
@@ -0,0 +1,8 @@
1
+ export function url(file) {
2
+ return new Promise((resolve, reject) => {
3
+ const reader = new FileReader();
4
+ reader.onload = () => resolve(reader.result);
5
+ reader.onerror = reject;
6
+ reader.readAsDataURL(file);
7
+ });
8
+ }
@@ -1,5 +1,6 @@
1
1
  import { DatabaseClient } from "./databaseClient.js";
2
2
  import * as DOM from "./dom/index.js";
3
+ import * as Files from "./files/index.js";
3
4
  import { FileAttachment } from "./fileAttachment.js";
4
5
  import * as Generators from "./generators/index.js";
5
6
  import { Interpreter } from "./interpreter.js";
@@ -101,6 +102,7 @@ export declare const library: {
101
102
  };
102
103
  Mutable: () => typeof Mutable;
103
104
  Promises: () => typeof Promises;
105
+ Files: () => typeof Files;
104
106
  DOM: () => typeof DOM;
105
107
  require: () => {
106
108
  (...specifiers: unknown[]): Promise<unknown>;
@@ -1,5 +1,6 @@
1
1
  import { DatabaseClient } from "./databaseClient.js";
2
2
  import * as DOM from "./dom/index.js";
3
+ import * as Files from "./files/index.js";
3
4
  import { FileAttachment } from "./fileAttachment.js";
4
5
  import * as Generators from "./generators/index.js";
5
6
  import { Interpreter } from "./interpreter.js";
@@ -20,6 +21,7 @@ export const library = {
20
21
  Interpreter: () => Interpreter,
21
22
  Mutable: () => Mutable,
22
23
  Promises: () => Promises, // deprecated!
24
+ Files: () => Files, // deprecated!
23
25
  DOM: () => DOM, // deprecated!
24
26
  require: () => require, // deprecated!
25
27
  __ojs_observer: () => () => new Observer(),
package/package.json CHANGED
@@ -5,7 +5,7 @@
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/observablehq/notebook-kit.git"
7
7
  },
8
- "version": "1.7.12",
8
+ "version": "1.9.0",
9
9
  "type": "module",
10
10
  "scripts": {
11
11
  "test": "vitest",