@observablehq/notebook-kit 1.8.0 → 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.8.0",
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
  };
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.8.0",
8
+ "version": "1.9.0",
9
9
  "type": "module",
10
10
  "scripts": {
11
11
  "test": "vitest",