Skip to content
Closed
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/build.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ export async function build({sourceRoot, outputRoot, verbose = true, addPublic =
// Copy over the referenced files.
for (const file of files) {
let sourcePath = join(sourceRoot, file);
const outputPath = join(outputRoot, "_file", file);
const outputPath = join(outputRoot, file);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we error if the file already exists? (Which shouldn’t have been possible before, but should now be possible if you have e.g. an index.html and an index.md.)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should not error, but we must definitely skip the file in that case.

Here are examples (admittedly fringe) where a file points to a generated page:

javascript.md:
<a href=javascript.html download>download this page</a>

or
<a href=javascript download>download this page</a>

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

now skipping both of these

if (!existsSync(sourcePath)) {
const loader = Loader.find(sourceRoot, file);
if (!loader) {
Expand Down
2 changes: 1 addition & 1 deletion src/files.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ export function fileReference(name: string, sourcePath: string): FileReference {
return {
name,
mimeType: mime.getType(name),
path: relativeUrl(sourcePath, resolvePath("_file", sourcePath, name))
path: relativeUrl(sourcePath, resolvePath(sourcePath, name)) // TODO simplify?
};
}

Expand Down
2 changes: 1 addition & 1 deletion src/javascript.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ export interface DatabaseReference {
export interface FileReference {
name: string;
mimeType: string | null;
/** The relative path from the document to the file in _file */
/** The relative path from the document to the file */
path: string;
}

Expand Down
4 changes: 2 additions & 2 deletions src/javascript/fetches.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ export function rewriteFetches(output: Sourcemap, rootNode: JavaScriptNode, sour
if (isLocalFetch(node, rootNode.references, sourcePath)) {
const arg = node.arguments[0];
const value = getStringLiteralValue(arg);
const path = resolvePath("_file", sourcePath, value);
output.replaceLeft(arg.start, arg.end, JSON.stringify(relativeUrl(sourcePath, path)));
const path = relativeUrl(sourcePath, resolvePath(sourcePath, value)); // TODO simplify?
Comment thread
Fil marked this conversation as resolved.
Outdated
output.replaceLeft(arg.start, arg.end, JSON.stringify(path));
}
}
});
Expand Down
2 changes: 1 addition & 1 deletion src/markdown.ts
Original file line number Diff line number Diff line change
Expand Up @@ -331,7 +331,7 @@ function normalizePieceHtml(html: string, root: string, sourcePath: string, cont
const path = getLocalPath(sourcePath, href);
if (path) {
context.files.push(fileReference(href, sourcePath));
element.setAttribute("href", relativeUrl(sourcePath, join("_file", path)));
element.setAttribute("href", relativeUrl(sourcePath, path));
}
}

Expand Down
44 changes: 22 additions & 22 deletions src/preview.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,28 +85,6 @@ export class Server {
throw new HttpError("Not found", 404);
}
end(req, res, rewriteModule(js, file, createImportResolver(this.root)), "text/javascript");
} else if (pathname.startsWith("/_file/")) {
const path = pathname.slice("/_file".length);
const filepath = join(this.root, path);
try {
await access(filepath, constants.R_OK);
send(req, pathname.slice("/_file".length), {root: this.root}).pipe(res);
return;
} catch (error) {
if (!isEnoent(error)) throw error;
}

// Look for a data loader for this file.
const loader = Loader.find(this.root, path);
if (loader) {
try {
send(req, await loader.load(), {root: this.root}).pipe(res);
return;
} catch (error) {
if (!isEnoent(error)) throw error;
}
}
throw new HttpError("Not found", 404);
} else {
if ((pathname = normalize(pathname)).startsWith("..")) throw new Error("Invalid path: " + pathname);
let path = join(this.root, pathname);
Expand Down Expand Up @@ -139,6 +117,28 @@ export class Server {
return;
}

// This handles a static file.
try {
await access(path, constants.R_OK);
Comment thread
mbostock marked this conversation as resolved.
Outdated
if ((await stat(path)).isFile()) {
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this test is new… otherwise javascript was detected as the javascript/ directory

send(req, pathname, {root: this.root}).pipe(res);
return;
}
} catch (error) {
if (!isEnoent(error)) throw error;
}

// Look for a data loader for this file.
const loader = Loader.find(this.root, pathname);
if (loader) {
try {
send(req, await loader.load(), {root: this.root}).pipe(res);
return;
} catch (error) {
if (!isEnoent(error)) throw error;
}
}

// Otherwise, serve the corresponding Markdown file, if it exists.
// Anything else should 404; static files should be matched above.
try {
Expand Down
1 change: 1 addition & 0 deletions test/files-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ describe("visitFiles(root)", () => {
"custom-styles.css",
"file-top.csv",
"files.md",
"another/file-another.csv",
"subsection/additional-styles.css",
"subsection/file-sub.csv",
"subsection/subfiles.md"
Expand Down
2 changes: 2 additions & 0 deletions test/input/build/files/another/file-another.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Hola,mundo
1,2
4 changes: 4 additions & 0 deletions test/input/build/files/subsection/subfiles.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ fetch("../file-top.csv")
fetch("./file-sub.csv")
```

```js
fetch("../another/file-another.csv")
```

```js
FileAttachment("../file-top.csv")
```
Expand Down
14 changes: 7 additions & 7 deletions test/output/build/archives/tar.html
Original file line number Diff line number Diff line change
Expand Up @@ -10,37 +10,37 @@

import {define} from "./_observablehq/client.js";

define({id: "d5134368", inputs: ["FileAttachment","display"], files: [{"name":"static-tar/file.txt","mimeType":"text/plain","path":"./_file/static-tar/file.txt"}], body: async (FileAttachment,display) => {
define({id: "d5134368", inputs: ["FileAttachment","display"], files: [{"name":"static-tar/file.txt","mimeType":"text/plain","path":"./static-tar/file.txt"}], body: async (FileAttachment,display) => {
display((
await FileAttachment("static-tar/file.txt").text()
))
}});
define({id: "a0c06958", inputs: ["FileAttachment","display"], files: [{"name":"static-tgz/file.txt","mimeType":"text/plain","path":"./_file/static-tgz/file.txt"}], body: async (FileAttachment,display) => {
define({id: "a0c06958", inputs: ["FileAttachment","display"], files: [{"name":"static-tgz/file.txt","mimeType":"text/plain","path":"./static-tgz/file.txt"}], body: async (FileAttachment,display) => {
display((
await FileAttachment("static-tgz/file.txt").text()
))
}});
define({id: "d84cd7fb", inputs: ["FileAttachment","display"], files: [{"name":"static-tar/does-not-exist.txt","mimeType":"text/plain","path":"./_file/static-tar/does-not-exist.txt"}], body: async (FileAttachment,display) => {
define({id: "d84cd7fb", inputs: ["FileAttachment","display"], files: [{"name":"static-tar/does-not-exist.txt","mimeType":"text/plain","path":"./static-tar/does-not-exist.txt"}], body: async (FileAttachment,display) => {
display((
await FileAttachment("static-tar/does-not-exist.txt").text()
))
}});
define({id: "86bd51aa", inputs: ["FileAttachment","display"], files: [{"name":"dynamic-tar/file.txt","mimeType":"text/plain","path":"./_file/dynamic-tar/file.txt"}], body: async (FileAttachment,display) => {
define({id: "86bd51aa", inputs: ["FileAttachment","display"], files: [{"name":"dynamic-tar/file.txt","mimeType":"text/plain","path":"./dynamic-tar/file.txt"}], body: async (FileAttachment,display) => {
display((
await FileAttachment("dynamic-tar/file.txt").text()
))
}});
define({id: "95938c22", inputs: ["FileAttachment","display"], files: [{"name":"dynamic-tar/does-not-exist.txt","mimeType":"text/plain","path":"./_file/dynamic-tar/does-not-exist.txt"}], body: async (FileAttachment,display) => {
define({id: "95938c22", inputs: ["FileAttachment","display"], files: [{"name":"dynamic-tar/does-not-exist.txt","mimeType":"text/plain","path":"./dynamic-tar/does-not-exist.txt"}], body: async (FileAttachment,display) => {
display((
await FileAttachment("dynamic-tar/does-not-exist.txt").text()
))
}});
define({id: "7e5740fd", inputs: ["FileAttachment","display"], files: [{"name":"dynamic-tar-gz/file.txt","mimeType":"text/plain","path":"./_file/dynamic-tar-gz/file.txt"}], body: async (FileAttachment,display) => {
define({id: "7e5740fd", inputs: ["FileAttachment","display"], files: [{"name":"dynamic-tar-gz/file.txt","mimeType":"text/plain","path":"./dynamic-tar-gz/file.txt"}], body: async (FileAttachment,display) => {
display((
await FileAttachment("dynamic-tar-gz/file.txt").text()
))
}});
define({id: "d0a58efd", inputs: ["FileAttachment","display"], files: [{"name":"dynamic-tar-gz/does-not-exist.txt","mimeType":"text/plain","path":"./_file/dynamic-tar-gz/does-not-exist.txt"}], body: async (FileAttachment,display) => {
define({id: "d0a58efd", inputs: ["FileAttachment","display"], files: [{"name":"dynamic-tar-gz/does-not-exist.txt","mimeType":"text/plain","path":"./dynamic-tar-gz/does-not-exist.txt"}], body: async (FileAttachment,display) => {
display((
await FileAttachment("dynamic-tar-gz/does-not-exist.txt").text()
))
Expand Down
8 changes: 4 additions & 4 deletions test/output/build/archives/zip.html
Original file line number Diff line number Diff line change
Expand Up @@ -10,22 +10,22 @@

import {define} from "./_observablehq/client.js";

define({id: "d3b9d0ee", inputs: ["FileAttachment","display"], files: [{"name":"static/file.txt","mimeType":"text/plain","path":"./_file/static/file.txt"}], body: async (FileAttachment,display) => {
define({id: "d3b9d0ee", inputs: ["FileAttachment","display"], files: [{"name":"static/file.txt","mimeType":"text/plain","path":"./static/file.txt"}], body: async (FileAttachment,display) => {
display((
await FileAttachment("static/file.txt").text()
))
}});
define({id: "bab54217", inputs: ["FileAttachment","display"], files: [{"name":"static/not-found.txt","mimeType":"text/plain","path":"./_file/static/not-found.txt"}], body: async (FileAttachment,display) => {
define({id: "bab54217", inputs: ["FileAttachment","display"], files: [{"name":"static/not-found.txt","mimeType":"text/plain","path":"./static/not-found.txt"}], body: async (FileAttachment,display) => {
display((
await FileAttachment("static/not-found.txt").text()
))
}});
define({id: "11eec300", inputs: ["FileAttachment","display"], files: [{"name":"dynamic/file.txt","mimeType":"text/plain","path":"./_file/dynamic/file.txt"}], body: async (FileAttachment,display) => {
define({id: "11eec300", inputs: ["FileAttachment","display"], files: [{"name":"dynamic/file.txt","mimeType":"text/plain","path":"./dynamic/file.txt"}], body: async (FileAttachment,display) => {
display((
await FileAttachment("dynamic/file.txt").text()
))
}});
define({id: "ee2310f3", inputs: ["FileAttachment","display"], files: [{"name":"dynamic/not-found.txt","mimeType":"text/plain","path":"./_file/dynamic/not-found.txt"}], body: async (FileAttachment,display) => {
define({id: "ee2310f3", inputs: ["FileAttachment","display"], files: [{"name":"dynamic/not-found.txt","mimeType":"text/plain","path":"./dynamic/not-found.txt"}], body: async (FileAttachment,display) => {
display((
await FileAttachment("dynamic/not-found.txt").text()
))
Expand Down
2 changes: 2 additions & 0 deletions test/output/build/files/another/file-another.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Hola,mundo
1,2
16 changes: 8 additions & 8 deletions test/output/build/files/files.html
Original file line number Diff line number Diff line change
Expand Up @@ -9,22 +9,22 @@

import {define} from "./_observablehq/client.js";

define({id: "a7808707", inputs: ["display"], files: [{"name":"./file-top.csv","mimeType":"text/csv","path":"./_file/file-top.csv"}], body: (display) => {
define({id: "a7808707", inputs: ["display"], files: [{"name":"./file-top.csv","mimeType":"text/csv","path":"./file-top.csv"}], body: (display) => {
display((
fetch("./_file/file-top.csv")
fetch("./file-top.csv")
))
}});
define({id: "03b99abc", inputs: ["display"], files: [{"name":"./subsection/file-sub.csv","mimeType":"text/csv","path":"./_file/subsection/file-sub.csv"}], body: (display) => {
define({id: "03b99abc", inputs: ["display"], files: [{"name":"./subsection/file-sub.csv","mimeType":"text/csv","path":"./subsection/file-sub.csv"}], body: (display) => {
display((
fetch("./_file/subsection/file-sub.csv")
fetch("./subsection/file-sub.csv")
))
}});
define({id: "10037545", inputs: ["FileAttachment","display"], files: [{"name":"file-top.csv","mimeType":"text/csv","path":"./_file/file-top.csv"}], body: (FileAttachment,display) => {
define({id: "10037545", inputs: ["FileAttachment","display"], files: [{"name":"file-top.csv","mimeType":"text/csv","path":"./file-top.csv"}], body: (FileAttachment,display) => {
display((
FileAttachment("file-top.csv")
))
}});
define({id: "453a8147", inputs: ["FileAttachment","display"], files: [{"name":"subsection/file-sub.csv","mimeType":"text/csv","path":"./_file/subsection/file-sub.csv"}], body: (FileAttachment,display) => {
define({id: "453a8147", inputs: ["FileAttachment","display"], files: [{"name":"subsection/file-sub.csv","mimeType":"text/csv","path":"./subsection/file-sub.csv"}], body: (FileAttachment,display) => {
display((
FileAttachment("subsection/file-sub.csv")
))
Expand All @@ -49,8 +49,8 @@
}</script>
<div id="observablehq-center">
<main id="observablehq-main" class="observablehq">
<span><link rel="stylesheet" href="./_file/custom-styles.css">
<link rel="stylesheet" href="./_file/subsection/additional-styles.css">
<span><link rel="stylesheet" href="./custom-styles.css">
<link rel="stylesheet" href="./subsection/additional-styles.css">
<link rel="stylesheet" href="https://example.com/style.css">
</span><div id="cell-a7808707" class="observablehq observablehq--block"></div>
<div id="cell-03b99abc" class="observablehq observablehq--block"></div>
Expand Down
22 changes: 14 additions & 8 deletions test/output/build/files/subsection/subfiles.html
Original file line number Diff line number Diff line change
Expand Up @@ -9,22 +9,27 @@

import {define} from "../_observablehq/client.js";

define({id: "62f1fd0c", inputs: ["display"], files: [{"name":"../file-top.csv","mimeType":"text/csv","path":"../_file/file-top.csv"}], body: (display) => {
define({id: "62f1fd0c", inputs: ["display"], files: [{"name":"../file-top.csv","mimeType":"text/csv","path":"../file-top.csv"}], body: (display) => {
display((
fetch("../_file/file-top.csv")
fetch("../file-top.csv")
))
}});
define({id: "94d347ec", inputs: ["display"], files: [{"name":"./file-sub.csv","mimeType":"text/csv","path":"../_file/subsection/file-sub.csv"}], body: (display) => {
define({id: "94d347ec", inputs: ["display"], files: [{"name":"./file-sub.csv","mimeType":"text/csv","path":"./file-sub.csv"}], body: (display) => {
display((
fetch("../_file/subsection/file-sub.csv")
fetch("./file-sub.csv")
))
}});
define({id: "ef9a31ef", inputs: ["FileAttachment","display"], files: [{"name":"../file-top.csv","mimeType":"text/csv","path":"../_file/file-top.csv"}], body: (FileAttachment,display) => {
define({id: "41cecaf7", inputs: ["display"], files: [{"name":"../another/file-another.csv","mimeType":"text/csv","path":"../another/file-another.csv"}], body: (display) => {
display((
fetch("../another/file-another.csv")
))
}});
define({id: "ef9a31ef", inputs: ["FileAttachment","display"], files: [{"name":"../file-top.csv","mimeType":"text/csv","path":"../file-top.csv"}], body: (FileAttachment,display) => {
display((
FileAttachment("../file-top.csv")
))
}});
define({id: "834ecf9f", inputs: ["FileAttachment","display"], files: [{"name":"file-sub.csv","mimeType":"text/csv","path":"../_file/subsection/file-sub.csv"}], body: (FileAttachment,display) => {
define({id: "834ecf9f", inputs: ["FileAttachment","display"], files: [{"name":"file-sub.csv","mimeType":"text/csv","path":"./file-sub.csv"}], body: (FileAttachment,display) => {
display((
FileAttachment("file-sub.csv")
))
Expand All @@ -49,10 +54,11 @@
}</script>
<div id="observablehq-center">
<main id="observablehq-main" class="observablehq">
<span><link rel="stylesheet" href="../_file/custom-styles.css">
<link rel="stylesheet" href="../_file/subsection/additional-styles.css">
<span><link rel="stylesheet" href="../custom-styles.css">
<link rel="stylesheet" href="./additional-styles.css">
</span><div id="cell-62f1fd0c" class="observablehq observablehq--block"></div>
<div id="cell-94d347ec" class="observablehq observablehq--block"></div>
<div id="cell-41cecaf7" class="observablehq observablehq--block"></div>
<div id="cell-ef9a31ef" class="observablehq observablehq--block"></div>
<div id="cell-834ecf9f" class="observablehq observablehq--block"></div>
</main>
Expand Down
4 changes: 2 additions & 2 deletions test/output/build/imports/foo/foo.html
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,14 @@

import {define} from "../_observablehq/client.js";

define({id: "9c60abc0", inputs: ["display"], outputs: ["d3","bar","top"], files: [{"name":"/top.js","mimeType":"application/javascript","path":"../_file/top.js"}], body: async (display) => {
define({id: "9c60abc0", inputs: ["display"], outputs: ["d3","bar","top"], files: [{"name":"/top.js","mimeType":"application/javascript","path":"../top.js"}], body: async (display) => {
const d3 = await import("https://cdn.jsdelivr.net/npm/d3/+esm");
const {bar} = await import("../_import/bar/bar.js?sha=2e71da6918681d51fd9e7ed79b03aed514771c2e1583af42783665aff3f5ef5e");
const {top} = await import("../_import/top.js?sha=43e37c2a4fe9ca94e62d0d8acd5dbd8bdd5f0ec845503964f465979c4c82c2a3");

display(bar);
display(top);
fetch("../_file/top.js");
fetch("../top.js");
return {d3,bar,top};
}});

Expand Down
2 changes: 1 addition & 1 deletion test/output/build/missing-file/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

import {define} from "./_observablehq/client.js";

define({id: "5760fd93", inputs: ["FileAttachment","display"], files: [{"name":"does-not-exist.txt","mimeType":"text/plain","path":"./_file/does-not-exist.txt"}], body: (FileAttachment,display) => {
define({id: "5760fd93", inputs: ["FileAttachment","display"], files: [{"name":"does-not-exist.txt","mimeType":"text/plain","path":"./does-not-exist.txt"}], body: (FileAttachment,display) => {
display((
FileAttachment("does-not-exist.txt")
))
Expand Down
6 changes: 3 additions & 3 deletions test/output/build/multi/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

import {define} from "./_observablehq/client.js";

define({id: "1bcb5df5", inputs: ["FileAttachment"], outputs: ["f1"], files: [{"name":"file1.csv","mimeType":"text/csv","path":"./_file/file1.csv"}], body: (FileAttachment) => {
define({id: "1bcb5df5", inputs: ["FileAttachment"], outputs: ["f1"], files: [{"name":"file1.csv","mimeType":"text/csv","path":"./file1.csv"}], body: (FileAttachment) => {
const f1 = FileAttachment("file1.csv").csv();
return {f1};
}});
Expand All @@ -19,8 +19,8 @@
Input.table(f1)
))
}});
define({id: "aaa5c01d", outputs: ["f2"], files: [{"name":"./file2.csv","mimeType":"text/csv","path":"./_file/file2.csv"}], body: () => {
const f2 = fetch("./_file/file2.csv");
define({id: "aaa5c01d", outputs: ["f2"], files: [{"name":"./file2.csv","mimeType":"text/csv","path":"./file2.csv"}], body: () => {
const f2 = fetch("./file2.csv");
return {f2};
}});

Expand Down
2 changes: 1 addition & 1 deletion test/output/build/simple/simple.html
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

import {define} from "./_observablehq/client.js";

define({id: "115586ff", inputs: ["FileAttachment"], outputs: ["result"], files: [{"name":"data.txt","mimeType":"text/plain","path":"./_file/data.txt"}], body: (FileAttachment) => {
define({id: "115586ff", inputs: ["FileAttachment"], outputs: ["result"], files: [{"name":"data.txt","mimeType":"text/plain","path":"./data.txt"}], body: (FileAttachment) => {
let result = FileAttachment("data.txt").text();
return {result};
}});
Expand Down
Loading