From 8bf91823a5e0b80c61fbdfbcd781a52fa8819190 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Rivi=C3=A8re?= Date: Fri, 22 Nov 2024 16:13:42 +0100 Subject: [PATCH 1/3] when a module references a file attachment, include the file's lastModified timestamp in the module's hash. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit closes #1836 Note that this allows us to remove from the tests the ts rewrite that we used to do on modules, because their payload’s lastModified is now always set to the fake currentDate injected by the tests. Some tests don't want to use the fake date though! (I hope they never run in parallel?) --- src/config.ts | 2 +- src/javascript/module.ts | 3 +- src/loader.ts | 2 +- test/build-test.ts | 3 -- test/input/build/params2/[code]/analytics.js | 4 ++ test/input/build/params2/[code]/data.json.js | 2 + test/input/build/params2/index.md | 5 ++ test/loader-test.ts | 5 ++ .../_import/import-test.3349a02d.js | 1 + .../_import/import-test.e7269c4e.js | 1 - .../{test.86a60bc6.js => test.a9a4ef0e.js} | 2 +- test/output/build/data-loaders/index.html | 6 +-- .../{chart.2ce91e05.js => chart.4140747c.js} | 2 +- test/output/build/embed/chart.js | 2 +- .../foo/{foo.666599bc.js => foo.0cc12e18.js} | 4 +- .../{top.c85e149a.js => top.bacf54cc.js} | 6 +-- test/output/build/fetches/foo.html | 4 +- test/output/build/fetches/top.html | 6 +-- .../params2/_file/code/data.015abd7f.json | 1 + .../_import/code/analytics.06ccf9ff.js | 4 ++ .../params2/_observablehq/client.00000001.js | 0 .../params2/_observablehq/runtime.00000002.js | 0 .../params2/_observablehq/stdlib.00000003.js | 0 .../theme-air,near-midnight.00000004.css | 0 test/output/build/params2/index.html | 46 +++++++++++++++++++ 25 files changed, 88 insertions(+), 23 deletions(-) create mode 100644 test/input/build/params2/[code]/analytics.js create mode 100644 test/input/build/params2/[code]/data.json.js create mode 100644 test/input/build/params2/index.md create mode 100644 test/output/build/data-loaders/_import/import-test.3349a02d.js delete mode 100644 test/output/build/data-loaders/_import/import-test.e7269c4e.js rename test/output/build/data-loaders/_import/{test.86a60bc6.js => test.a9a4ef0e.js} (76%) rename test/output/build/embed/_import/{chart.2ce91e05.js => chart.4140747c.js} (84%) rename test/output/build/fetches/_import/foo/{foo.666599bc.js => foo.0cc12e18.js} (61%) rename test/output/build/fetches/_import/{top.c85e149a.js => top.bacf54cc.js} (57%) create mode 100644 test/output/build/params2/_file/code/data.015abd7f.json create mode 100644 test/output/build/params2/_import/code/analytics.06ccf9ff.js create mode 100644 test/output/build/params2/_observablehq/client.00000001.js create mode 100644 test/output/build/params2/_observablehq/runtime.00000002.js create mode 100644 test/output/build/params2/_observablehq/stdlib.00000003.js create mode 100644 test/output/build/params2/_observablehq/theme-air,near-midnight.00000004.css create mode 100644 test/output/build/params2/index.html diff --git a/src/config.ts b/src/config.ts index bf063bc46..8e53688ce 100644 --- a/src/config.ts +++ b/src/config.ts @@ -233,7 +233,7 @@ function readPages(root: string, md: MarkdownIt): Page[] { return pages; } -let currentDate: Date | null = null; +export let currentDate: Date | null = null; /** For testing only! */ export function setCurrentDate(date: Date | null): void { diff --git a/src/javascript/module.ts b/src/javascript/module.ts index 46daa8f47..03f5e1f5a 100644 --- a/src/javascript/module.ts +++ b/src/javascript/module.ts @@ -6,6 +6,7 @@ import {extname, join} from "node:path/posix"; import type {Program} from "acorn"; import type {TransformOptions} from "esbuild"; import {transform, transformSync} from "esbuild"; +import {currentDate} from "../config.js"; import {resolveJsrImport} from "../jsr.js"; import {resolveNodeImport} from "../node.js"; import {resolveNpmImport} from "../npm.js"; @@ -199,7 +200,7 @@ export function getFileInfo(root: string, path: string): FileInfo | undefined { const stat = statSync(key); if (!stat.isFile()) return; // ignore non-files accessSync(key, constants.R_OK); // verify that file is readable - mtimeMs = Math.floor(stat.mtimeMs); + mtimeMs = Math.floor((currentDate ?? stat.mtimeMs) as number); size = stat.size; } catch { fileInfoCache.delete(key); // delete stale entry diff --git a/src/loader.ts b/src/loader.ts index 324f1a8e1..8e28ace79 100644 --- a/src/loader.ts +++ b/src/loader.ts @@ -300,7 +300,7 @@ export class LoaderResolver { getOutputFileHash(name: string): string { const info = this.getOutputInfo(name); if (!info) throw new Error(`output file not found: ${name}`); - return info.hash; + return createHash("sha256").update(info.hash).update(String(info.mtimeMs)).digest("hex"); } getSourceInfo(name: string): FileInfo | undefined { diff --git a/test/build-test.ts b/test/build-test.ts index da7726f6c..2e162fa70 100644 --- a/test/build-test.ts +++ b/test/build-test.ts @@ -233,9 +233,6 @@ class TestEffects extends FileBuildEffects { contents = contents.replace(/^(\s* + + +
+ +
+

test

+
+
+ +
+ + From 679ed0afd7f37a4513fe90652cdfcc50306e4f28 Mon Sep 17 00:00:00 2001 From: Mike Bostock Date: Fri, 22 Nov 2024 08:41:29 -0800 Subject: [PATCH 2/3] clear currentDate in after --- test/build-test.ts | 1 + test/config-test.ts | 1 + test/deploy-test.ts | 1 + test/loader-test.ts | 5 ----- 4 files changed, 3 insertions(+), 5 deletions(-) diff --git a/test/build-test.ts b/test/build-test.ts index 2e162fa70..b477d58fd 100644 --- a/test/build-test.ts +++ b/test/build-test.ts @@ -32,6 +32,7 @@ const failureTests = ["missing-file", "missing-import"]; describe("build", () => { before(() => setCurrentDate(new Date("2024-01-10T16:00:00"))); + after(() => setCurrentDate(null)); mockJsDelivr(); mockJsr(); mockDuckDB(); diff --git a/test/config-test.ts b/test/config-test.ts index 32360f734..82c81daac 100644 --- a/test/config-test.ts +++ b/test/config-test.ts @@ -26,6 +26,7 @@ const DUCKDB_DEFAULTS: DuckDBConfig = { describe("readConfig(undefined, root)", () => { before(() => setCurrentDate(new Date("2024-01-10T16:00:00"))); + after(() => setCurrentDate(null)); it("imports the config file at the specified root", async () => { const {md, loaders, paths, normalizePath, ...config} = await readConfig(undefined, "test/input/build/config"); assert(md instanceof MarkdownIt); diff --git a/test/deploy-test.ts b/test/deploy-test.ts index abca7ae80..693801317 100644 --- a/test/deploy-test.ts +++ b/test/deploy-test.ts @@ -195,6 +195,7 @@ const DEPLOY_CONFIG: DeployConfig & {projectId: string; projectSlug: string; wor describe("deploy", () => { before(() => setCurrentDate(new Date("2024-01-10T16:00:00"))); + after(() => setCurrentDate(null)); mockObservableApi(); mockJsDelivr(); diff --git a/test/loader-test.ts b/test/loader-test.ts index c11459423..f2d4a7172 100644 --- a/test/loader-test.ts +++ b/test/loader-test.ts @@ -3,7 +3,6 @@ import {mkdir, readFile, rm, stat, unlink, utimes, writeFile} from "node:fs/prom import os from "node:os"; import {join} from "node:path/posix"; import {sort} from "d3-array"; -import {setCurrentDate} from "../src/config.js"; import {clearFileInfo} from "../src/javascript/module.js"; import type {LoadEffects} from "../src/loader.js"; import {LoaderResolver} from "../src/loader.js"; @@ -119,8 +118,6 @@ describe("LoaderResolver.find(path)", () => { describe("LoaderResolver.getSourceFileHash(path)", () => { const time = new Date(Date.UTC(2023, 11, 1)); - before(() => setCurrentDate(null)); - after(() => setCurrentDate(new Date("2024-01-10T16:00:00"))); it("returns the content hash for the specified file’s data loader", async () => { await utimes("test/input/build/archives.posix/dynamic.zip.sh", time, time); await utimes("test/input/build/archives.posix/static.zip", time, time); @@ -143,8 +140,6 @@ describe("LoaderResolver.get{Source,Output}Info(path)", () => { const time1 = new Date(Date.UTC(2023, 11, 1)); const time2 = new Date(Date.UTC(2024, 2, 1)); const loaders = new LoaderResolver({root: "test"}); - before(() => setCurrentDate(null)); - after(() => setCurrentDate(new Date("2024-01-10T16:00:00"))); it("both return the last modification time for a simple file", async () => { await utimes("test/input/loader/simple.txt", time1, time1); assert.deepStrictEqual(loaders.getSourceInfo("input/loader/simple.txt"), {hash: "3b09aeb6f5f5336beb205d7f720371bc927cd46c21922e334d47ba264acb5ba4", mtimeMs: +time1, size: 6}); // prettier-ignore From bf935d545f1591823bcbd2ca0d7ac3ad43672565 Mon Sep 17 00:00:00 2001 From: Mike Bostock Date: Fri, 22 Nov 2024 08:44:07 -0800 Subject: [PATCH 3/3] prettier --- test/input/build/params2/[code]/analytics.js | 1 - test/input/build/params2/[code]/data.json.js | 3 +-- .../code/{analytics.06ccf9ff.js => analytics.0d826e00.js} | 1 - test/output/build/params2/index.html | 4 ++-- 4 files changed, 3 insertions(+), 6 deletions(-) rename test/output/build/params2/_import/code/{analytics.06ccf9ff.js => analytics.0d826e00.js} (99%) diff --git a/test/input/build/params2/[code]/analytics.js b/test/input/build/params2/[code]/analytics.js index 9c4510b94..032484c72 100644 --- a/test/input/build/params2/[code]/analytics.js +++ b/test/input/build/params2/[code]/analytics.js @@ -1,4 +1,3 @@ import {FileAttachment} from "npm:@observablehq/stdlib"; FileAttachment("data.json"); - diff --git a/test/input/build/params2/[code]/data.json.js b/test/input/build/params2/[code]/data.json.js index f12089c27..52c4544eb 100644 --- a/test/input/build/params2/[code]/data.json.js +++ b/test/input/build/params2/[code]/data.json.js @@ -1,2 +1 @@ -process.stdout.write(JSON.stringify({ a: 1 })); - +process.stdout.write(JSON.stringify({a: 1})); diff --git a/test/output/build/params2/_import/code/analytics.06ccf9ff.js b/test/output/build/params2/_import/code/analytics.0d826e00.js similarity index 99% rename from test/output/build/params2/_import/code/analytics.06ccf9ff.js rename to test/output/build/params2/_import/code/analytics.0d826e00.js index d94b7c5bc..2247f2ae8 100644 --- a/test/output/build/params2/_import/code/analytics.06ccf9ff.js +++ b/test/output/build/params2/_import/code/analytics.0d826e00.js @@ -1,4 +1,3 @@ import {FileAttachment} from "../../_observablehq/stdlib.00000003.js"; FileAttachment({"name":"../../code/data.json","mimeType":"application/json","path":"../../_file/code/data.015abd7f.json","lastModified":1704931200000,"size":7}, import.meta.url); - diff --git a/test/output/build/params2/index.html b/test/output/build/params2/index.html index 1788673b6..0f53d336d 100644 --- a/test/output/build/params2/index.html +++ b/test/output/build/params2/index.html @@ -13,7 +13,7 @@ - +