Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
19 changes: 1 addition & 18 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -408,24 +408,7 @@ const document = await FileAttachment("index.html").html();

*Note: this function is not part of the Observable standard library (in notebooks), but is provided by this module as a means for defining custom file attachment implementations when working directly with the Observable runtime.*

Returns a [*FileAttachment*](#FileAttachment) function given the specified *resolve* function. The *resolve* function is an async function that takes a *name* and returns a URL at which the file of that name can be loaded. For example:

```js
const FileAttachment = FileAttachments((name) =>
`https://my.server/notebooks/demo/${name}`
);
```

Or, with a more complex example, calling an API to produce temporary URLs:

```js
const FileAttachment = FileAttachments(async (name) =>
if (cachedUrls.has(name)) return cachedUrls.get(name);
const url = await fetchSignedFileUrl(notebookId, name);
cachedUrls.set(name, url);
return url;
);
```
Returns a [*FileAttachment*](#FileAttachment) function given the specified *resolve* function. The *resolve* function is a function that takes a *name* and returns either an object {url, mimeType} representing the requested file if it exists, or null if the file does not exist. The url field (though not the object itself!) may be represented as a Promise if the URL is not yet known, such as for a file that is currently being uploaded. The mimeType must be a string, or undefined if the mime type is not known. For backwards compatibility, the *resolve* function may instead return just a URL, either a string or a promise.

### Generators

Expand Down
17 changes: 11 additions & 6 deletions src/fileAttachment.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,9 @@ async function dsv(file, delimiter, {array = false, typed = false} = {}) {
}

export class AbstractFile {
constructor(name) {
constructor(name, mimeType) {
Object.defineProperty(this, "name", {value: name, enumerable: true});
if (mimeType !== undefined) Object.defineProperty(this, "mimeType", {value: mimeType + "", enumerable: true});
}
async blob() {
return (await remote_fetch(this)).blob();
Expand Down Expand Up @@ -79,8 +80,8 @@ export class AbstractFile {
}

class FileAttachment extends AbstractFile {
constructor(url, name) {
super(name);
constructor(url, name, mimeType) {
super(name, mimeType);
Object.defineProperty(this, "_url", {value: url});
}
async url() {
Expand All @@ -95,9 +96,13 @@ export function NoFileAttachments(name) {
export default function FileAttachments(resolve) {
return Object.assign(
name => {
const url = resolve(name += ""); // Returns a Promise, string, or null.
if (url == null) throw new Error(`File not found: ${name}`);
return new FileAttachment(url, name);
const result = resolve(name += "");
if (result == null) throw new Error(`File not found: ${name}`);
if (typeof result === "object" && "url" in result) {
const {url, mimeType} = result;
return new FileAttachment(url, name, mimeType);
}
return new FileAttachment(result, name);
},
{prototype: FileAttachment.prototype} // instanceof
);
Expand Down