Skip to content

Commit 30be23f

Browse files
Filmbostock
andauthored
add lastModified to a module’s hash when it references a file attachment (#1837)
* when a module references a file attachment, include the file's lastModified timestamp in the module's hash. 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?) * clear currentDate in after * prettier --------- Co-authored-by: Mike Bostock <[email protected]>
1 parent 82922bd commit 30be23f

26 files changed

+83
-23
lines changed

src/config.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -233,7 +233,7 @@ function readPages(root: string, md: MarkdownIt): Page[] {
233233
return pages;
234234
}
235235

236-
let currentDate: Date | null = null;
236+
export let currentDate: Date | null = null;
237237

238238
/** For testing only! */
239239
export function setCurrentDate(date: Date | null): void {

src/javascript/module.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import {extname, join} from "node:path/posix";
66
import type {Program} from "acorn";
77
import type {TransformOptions} from "esbuild";
88
import {transform, transformSync} from "esbuild";
9+
import {currentDate} from "../config.js";
910
import {resolveJsrImport} from "../jsr.js";
1011
import {resolveNodeImport} from "../node.js";
1112
import {resolveNpmImport} from "../npm.js";
@@ -199,7 +200,7 @@ export function getFileInfo(root: string, path: string): FileInfo | undefined {
199200
const stat = statSync(key);
200201
if (!stat.isFile()) return; // ignore non-files
201202
accessSync(key, constants.R_OK); // verify that file is readable
202-
mtimeMs = Math.floor(stat.mtimeMs);
203+
mtimeMs = Math.floor((currentDate ?? stat.mtimeMs) as number);
203204
size = stat.size;
204205
} catch {
205206
fileInfoCache.delete(key); // delete stale entry

src/loader.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -300,7 +300,7 @@ export class LoaderResolver {
300300
getOutputFileHash(name: string): string {
301301
const info = this.getOutputInfo(name);
302302
if (!info) throw new Error(`output file not found: ${name}`);
303-
return info.hash;
303+
return createHash("sha256").update(info.hash).update(String(info.mtimeMs)).digest("hex");
304304
}
305305

306306
getSourceInfo(name: string): FileInfo | undefined {

test/build-test.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ const failureTests = ["missing-file", "missing-import"];
3232

3333
describe("build", () => {
3434
before(() => setCurrentDate(new Date("2024-01-10T16:00:00")));
35+
after(() => setCurrentDate(null));
3536
mockJsDelivr();
3637
mockJsr();
3738
mockDuckDB();
@@ -233,9 +234,6 @@ class TestEffects extends FileBuildEffects {
233234
contents = contents.replace(/^(\s*<script>\{).*(\}<\/script>)$/gm, "$1/* redacted init script */$2");
234235
contents = contents.replace(/(registerFile\(.*,"lastModified":)\d+(,"size":\d+.*\))/gm, "$1/* ts */1706742000000$2"); // prettier-ignore
235236
}
236-
if (typeof contents === "string" && outputPath.endsWith(".js")) {
237-
contents = contents.replace(/(FileAttachment\(.*,"lastModified":)\d+(,"size":\d+.*\))/gm, "$1/* ts */1706742000000$2"); // prettier-ignore
238-
}
239237
return super.writeFile(outputPath, contents);
240238
}
241239
}

test/config-test.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ const DUCKDB_DEFAULTS: DuckDBConfig = {
2626

2727
describe("readConfig(undefined, root)", () => {
2828
before(() => setCurrentDate(new Date("2024-01-10T16:00:00")));
29+
after(() => setCurrentDate(null));
2930
it("imports the config file at the specified root", async () => {
3031
const {md, loaders, paths, normalizePath, ...config} = await readConfig(undefined, "test/input/build/config");
3132
assert(md instanceof MarkdownIt);

test/deploy-test.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,7 @@ const DEPLOY_CONFIG: DeployConfig & {projectId: string; projectSlug: string; wor
195195

196196
describe("deploy", () => {
197197
before(() => setCurrentDate(new Date("2024-01-10T16:00:00")));
198+
after(() => setCurrentDate(null));
198199
mockObservableApi();
199200
mockJsDelivr();
200201

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import {FileAttachment} from "npm:@observablehq/stdlib";
2+
3+
FileAttachment("data.json");
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
process.stdout.write(JSON.stringify({a: 1}));

test/input/build/params2/index.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# test
2+
3+
```js
4+
import "/code/analytics.js"
5+
```
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export {test} from "./test.a9a4ef0e.js";

0 commit comments

Comments
 (0)