Skip to content

Commit da6be7c

Browse files
committed
fix(observablehq-compiler): update dependencies and improve file attachment handling
- Updated `@observablehq/runtime` to version 6.0.0 and added `@observablehq/inspector` and `@observablehq/stdlib` as dependencies in `markdown-it-plugins` and `observablehq-compiler`. - Enhanced `index-kit.html` and `index-preview.html` to demonstrate file attachment functionality with a CSV example. - Refactored import statements in various HTML files to align with the new dependency structure. - Modified `compiler.ts` and `writer.ts` to utilize `FileAttachments` from `@observablehq/stdlib` for better file handling. - Updated test files to reflect changes in the compilation process and ensure compatibility with the new runtime. Signed-off-by: Gordon Smith <GordonJSmith@gmail.com>
1 parent 40c9476 commit da6be7c

19 files changed

Lines changed: 1427 additions & 2960 deletions

File tree

package-lock.json

Lines changed: 1296 additions & 2879 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@
4141
"devDependencies": {
4242
"@eslint/js": "10.0.1",
4343
"@types/esbuild-copy-static-files": "0.1.4",
44-
"@typescript-eslint/parser": "8.59.4",
44+
"@typescript-eslint/parser": "8.60.0",
4545
"@vitest/browser": "4.1.7",
4646
"@vitest/browser-playwright": "4.1.7",
4747
"@vitest/coverage-v8": "4.1.7",
@@ -56,7 +56,7 @@
5656
"playwright": "1.60.0",
5757
"rimraf": "6.1.3",
5858
"typescript": "6.0.3",
59-
"typescript-eslint": "8.59.4",
59+
"typescript-eslint": "8.60.0",
6060
"vite": "7.3.3",
6161
"vitepress": "1.6.4",
6262
"vitest": "4.1.7"
@@ -77,7 +77,7 @@
7777
},
7878
"yaml": "2.8.3",
7979
"tar": "7.5.11",
80-
"tmp": "0.2.5"
80+
"tmp": "0.2.6"
8181
},
8282
"repository": {
8383
"type": "git",

packages/comms/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@
7878
"dependencies": {
7979
"@hpcc-js/util": "^3.5.8",
8080
"@xmldom/xmldom": "0.9.10",
81-
"undici": "7.25.0"
81+
"undici": "7.26.0"
8282
},
8383
"devDependencies": {
8484
"@hpcc-js/ddl-shim": "^3.3.8",

packages/dgrid-shim/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@
4343
"string-replace-loader": "3.3.0",
4444
"terser-webpack-plugin": "5.6.0",
4545
"typescript": "5.9.3",
46-
"webpack": "5.107.0",
46+
"webpack": "5.107.2",
4747
"webpack-cli": "5.1.4",
4848
"webpack-hasjs-plugin": "1.0.4"
4949
},

packages/esbuild-plugins/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,8 @@
4848
"vite-plugin-static-copy": "3.4.0"
4949
},
5050
"devDependencies": {
51-
"@hpcc-js/wasm-base91": "1.13.5",
52-
"@hpcc-js/wasm-zstd": "1.12.5"
51+
"@hpcc-js/wasm-base91": "1.13.7",
52+
"@hpcc-js/wasm-zstd": "1.12.6"
5353
},
5454
"keywords": [
5555
"esbuild",

packages/graph/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@
5151
},
5252
"devDependencies": {
5353
"@hpcc-js/esbuild-plugins": "^1.8.10",
54-
"@hpcc-js/wasm-graphviz": "1.21.6",
54+
"@hpcc-js/wasm-graphviz": "1.21.7",
5555
"@types/d3-transition": "1.3.6",
5656
"@types/dagre": "0.7.54",
5757
"d3-force": "^1",
@@ -61,6 +61,7 @@
6161
"d3-shape": "^1",
6262
"d3-tile": "^1",
6363
"d3-transition": "^1",
64+
"d3-hierarchy": "^1",
6465
"dagre": "0.8.5",
6566
"lit-html": "3.3.3"
6667
},

packages/markdown-it-plugins/index-preview.html

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,14 @@
2424
<script type="importmap">
2525
{
2626
"imports": {
27-
"@observablehq/runtime": "https://cdn.jsdelivr.net/npm/@observablehq/runtime@5.9.9/dist/runtime.js",
27+
"@observablehq/runtime": "https://cdn.jsdelivr.net/npm/@observablehq/runtime/src/index.js",
28+
"@observablehq/stdlib": "https://cdn.jsdelivr.net/npm/@observablehq/stdlib/src/index.js",
29+
"@observablehq/inspector": "https://cdn.jsdelivr.net/npm/@observablehq/inspector/src/index.js",
30+
"d3-require": "https://cdn.jsdelivr.net/npm/d3-require/src/index.mjs",
31+
"d3-dsv": "https://cdn.jsdelivr.net/npm/d3-dsv/src/index.js",
32+
"d3-array": "https://cdn.jsdelivr.net/npm/d3-array/src/index.js",
33+
"internmap": "https://cdn.jsdelivr.net/npm/internmap/src/index.js",
34+
"isoformat": "https://cdn.jsdelivr.net/npm/isoformat/src/index.js",
2835
"markdown-it": "../../node_modules/markdown-it/index.mjs",
2936
"linkify-it": "../../node_modules/linkify-it/index.mjs",
3037
"mdurl": "../../node_modules/mdurl/index.mjs",

packages/markdown-it-plugins/package.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,9 @@
5555
},
5656
"dependencies": {
5757
"@hpcc-js/observablehq-compiler": "^3.7.12",
58-
"@observablehq/framework": "1.13.4",
59-
"@observablehq/runtime": "5.9.9",
58+
"@observablehq/inspector": "5.0.1",
59+
"@observablehq/stdlib": "5.8.8",
60+
"@observablehq/runtime": "6.0.0",
6061
"@types/markdown-it": "14.1.2"
6162
},
6263
"peerDependencies": {

packages/markdown-it-plugins/src/loader.ts

Lines changed: 57 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1,60 +1,76 @@
11
import { existsSync } from "node:fs";
2-
import { readdir, readFile } from "node:fs/promises";
2+
import { readdir, readFile, mkdir } from "node:fs/promises";
3+
import { createWriteStream } from "node:fs";
34
import path from "node:path";
4-
import { pathToFileURL } from "node:url";
5+
import { spawn } from "node:child_process";
56
import { dsvFormat, autoType } from "d3-dsv";
6-
import { LoaderResolver, } from "@observablehq/framework/dist/loader.js";
7-
import { getResolvers } from "@observablehq/framework/dist/resolvers.js";
8-
import { normalizeConfig } from "@observablehq/framework/dist/config.js";
9-
import { parseMarkdown } from "@observablehq/framework/dist/markdown.js";
107

11-
function getOptions({ path, ...config }) {
12-
return { ...normalizeConfig(config), path };
8+
const CACHE_DIR = ".observablehq/cache";
9+
10+
// Interpreter commands for data loader scripts (mirrors @observablehq/framework defaults)
11+
function getInterpreterCommand(ext: string): [string, string[]] | null {
12+
switch (ext) {
13+
case ".js": return ["node", ["--no-warnings=ExperimentalWarning"]];
14+
case ".ts": return ["tsx", []];
15+
case ".py": return ["python3", []];
16+
case ".r":
17+
case ".R": return ["Rscript", []];
18+
default: return null;
19+
}
20+
}
21+
22+
function findLoader(partialPath: string, root: string): { loaderPath: string; loaderExt: string } | null {
23+
for (const ext of [".js", ".ts", ".py", ".r", ".R"]) {
24+
const loaderPath = path.resolve(root, `${partialPath}${ext}`);
25+
if (existsSync(loaderPath)) {
26+
return { loaderPath, loaderExt: ext };
27+
}
28+
}
29+
return null;
30+
}
31+
32+
async function runLoader(loaderPath: string, loaderExt: string, cachePath: string): Promise<void> {
33+
const cmd = getInterpreterCommand(loaderExt);
34+
if (!cmd) throw new Error(`No interpreter for loader extension: ${loaderExt}`);
35+
await mkdir(path.dirname(cachePath), { recursive: true });
36+
const [command, args] = cmd;
37+
const child = spawn(command, [...args, loaderPath], {
38+
windowsHide: true,
39+
stdio: ["ignore", "pipe", "inherit"]
40+
});
41+
child.stdout!.pipe(createWriteStream(cachePath));
42+
await new Promise<void>((resolve, reject) => {
43+
child.on("error", reject);
44+
child.on("exit", (code) =>
45+
code === 0 ? resolve() : reject(new Error(`Loader "${loaderPath}" exited with code ${code}`))
46+
);
47+
});
1348
}
1449

1550
export class DataFile {
1651

1752
private filePath: string;
18-
private options: any;
19-
private resolvers: any;
2053
readonly ext: string;
2154

22-
protected constructor(filePath, options, resolvers) {
55+
protected constructor(filePath: string) {
2356
this.filePath = filePath;
24-
this.options = options;
25-
this.resolvers = resolvers;
2657
this.ext = path.extname(filePath).substring(1);
2758
}
2859

2960
static async attach(partialPath: string, root: string = path.resolve(".")) {
30-
const exists = existsSync(path.resolve(root, partialPath));
31-
const loaders = new LoaderResolver({ root, interpreters: {} });
32-
const loader = loaders.find(partialPath);
33-
if (loader) {
34-
await loader.load();
35-
const ext = path.extname(partialPath);
36-
const options = getOptions({ root, path: "dummy.md" });
37-
const page = parseMarkdown(`\${FileAttachment('${partialPath}')${ext}()}`, options);
38-
const resolvers = await getResolvers(page, options);
39-
resolvers.resolveFile(partialPath);
40-
return new DataFile(exists ? path.resolve(root, partialPath) : path.resolve(path.join(root, ".observablehq", "cache", partialPath)), options, resolvers);
61+
const absolutePath = path.resolve(root, partialPath);
62+
if (existsSync(absolutePath)) {
63+
return new DataFile(absolutePath);
4164
}
42-
}
43-
44-
async myResolve(module: string) {
45-
const partialPath = await this.resolvers.resolveImport(module);
46-
return path.resolve(path.join(this.options.root, ".observablehq", "cache", partialPath));
47-
}
48-
49-
async myImport(module: string) {
50-
if (module === "npm:apache-arrow") {
51-
return import("apache-arrow");
65+
const loaderInfo = findLoader(partialPath, root);
66+
if (loaderInfo) {
67+
const cachePath = path.resolve(root, CACHE_DIR, partialPath);
68+
if (!existsSync(cachePath)) {
69+
await runLoader(loaderInfo.loaderPath, loaderInfo.loaderExt, cachePath);
70+
}
71+
return new DataFile(cachePath);
5272
}
53-
const fullPath = await this.myResolve(module);
54-
const href = pathToFileURL(fullPath).href;
55-
return import(href).catch((error) => {
56-
console.error(error);
57-
});
73+
return undefined;
5874
}
5975

6076
buffer(): Promise<Buffer> {
@@ -92,24 +108,13 @@ export class DataFile {
92108
}
93109

94110
arrow() {
95-
return Promise.all([this.myImport("npm:apache-arrow"), this.arrayBuffer()]).then(([Arrow, response]) => {
111+
return Promise.all([import("apache-arrow"), this.arrayBuffer()]).then(([Arrow, response]) => {
96112
return Arrow.tableFromIPC(response);
97113
});
98114
}
99115

100116
parquet() {
101-
return this.myResolve("npm:parquet-wasm/esm/parquet_wasm_bg.wasm").then(wasmBytes => {
102-
const wasmFile = new DataFile(wasmBytes, this.options, this.resolvers);
103-
return Promise.all([
104-
this.myImport("npm:apache-arrow"),
105-
this.myImport("npm:parquet-wasm"),
106-
wasmFile.arrayBuffer(),
107-
this.arrayBuffer()
108-
]).then(([Arrow, Parquet, wasm, buffer]) => {
109-
Parquet.initSync(wasm);
110-
return Arrow.tableFromIPC(Parquet.readParquet(new Uint8Array(buffer)).intoIPCStream());
111-
});
112-
});
117+
throw new Error("parquet() is not supported; install @observablehq/framework for npm: package resolution.");
113118
}
114119

115120
fetch() {

packages/markdown-it-plugins/src/render.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
import { Runtime, Library, Inspector as BaseInspector } from "@observablehq/runtime";
1+
import { Runtime } from "@observablehq/runtime";
2+
import { Library } from "@observablehq/stdlib";
3+
import { Inspector as BaseInspector } from "@observablehq/inspector";
24
import { compile, type ohq } from "@hpcc-js/observablehq-compiler";
35
import { FenceInfo, renderExecutedSrc } from "./util.ts";
46

0 commit comments

Comments
 (0)