@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 +1 -1
- package/dist/src/javascript/features.d.ts +10 -0
- package/dist/src/javascript/features.js +29 -0
- package/dist/src/javascript/literal.d.ts +8 -0
- package/dist/src/javascript/literal.js +42 -0
- package/dist/src/javascript/parse.d.ts +4 -0
- package/dist/src/javascript/parse.js +6 -2
- package/package.json +1 -1
package/dist/package.json
CHANGED
|
@@ -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
|
};
|