Skip to content

Commit

Permalink
promote local media assets to file attachments
Browse files Browse the repository at this point in the history
  • Loading branch information
cinxmo committed Nov 28, 2023
1 parent 5f34821 commit 006b229
Show file tree
Hide file tree
Showing 2 changed files with 97 additions and 8 deletions.
26 changes: 18 additions & 8 deletions src/markdown.ts
Original file line number Diff line number Diff line change
Expand Up @@ -316,22 +316,32 @@ function renderIntoPieces(renderer: Renderer, root: string, sourcePath: string):
}
let result = "";
for (const piece of context.pieces) {
result += piece.html = normalizePieceHtml(piece.html, root, sourcePath, context);
result += piece.html = normalizePieceHtml(piece.html, sourcePath, context);
}
return result;
};
}

function normalizePieceHtml(html: string, root: string, sourcePath: string, context: ParseContext): string {
const SUPPORTED_PROPERTIES: readonly {query: string; src: string}[] = Object.freeze([
{query: "img[src]", src: "src"},
{query: "video[src]", src: "src"},
{query: "video source[src]", src: "src"},
{query: "audio[src]", src: "src"},
{query: "audio source[src]", src: "src"},
{query: "link[href]", src: "href"}
]);
export function normalizePieceHtml(html: string, sourcePath: string, context: ParseContext): string {
const {document} = parseHTML(html);

// Extracting references to files (such as from linked stylesheets).
for (const element of document.querySelectorAll("link[href]") as any as Iterable<Element>) {
const href = element.getAttribute("href")!;
const path = getLocalPath(sourcePath, href);
if (path) {
context.files.push(fileReference(href, sourcePath));
element.setAttribute("href", relativeUrl(sourcePath, join("_file", path)));
for (const {query, src} of SUPPORTED_PROPERTIES) {
for (const element of document.querySelectorAll(query) as any as Iterable<Element>) {
const relativePath = element.getAttribute(src)!;
const path = getLocalPath(sourcePath, relativePath);
if (path) {
context.files.push(fileReference(relativePath, sourcePath));
element.setAttribute(src!, relativeUrl(sourcePath, join("_file", path)));
}
}
}

Expand Down
79 changes: 79 additions & 0 deletions test/promote-file-attachment-test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import assert from "node:assert";
import {normalizePieceHtml} from "../src/markdown.js";
import {resolvePath} from "../src/url.js";

Check failure on line 3 in test/promote-file-attachment-test.ts

View workflow job for this annotation

GitHub Actions / test

'resolvePath' is defined but never used.

const html = (strings, ...values) => String.raw({raw: strings}, ...values);
const mockContext = () => ({files: [], imports: [], pieces: [], startLine: 0, currentLine: 0});

describe("file attachments", () => {
describe("success", () => {
const sourcePath = "/attachments.md";

it("img[src]", () => {
const htmlStr = html`<img src="./test.png">`;
const expected = html`<img src="./_file/test.png">`;
const context = mockContext();
const actual = normalizePieceHtml(htmlStr, sourcePath, context);

assert.equal(expected, actual);
assert.deepEqual(context.files, [
{
mimeType: "image/png",
name: "./test.png",
path: "./_file/test.png"
}
]);
});

it("video[src]", () => {
const htmlStr = html`<video src="observable.mov" controls>
Learn more about Observable CLI
</video>`;
const expected = html`<video src="./_file/observable.mov" controls>
Learn more about Observable CLI
</video>`;
const context = mockContext();
const actual = normalizePieceHtml(htmlStr, sourcePath, context);

assert.equal(expected, actual);
assert.deepEqual(context.files, [
{
mimeType: "video/quicktime",
name: "observable.mov",
path: "./_file/observable.mov"
}
]);
});

it("video source[src]", () => {
const htmlStr = html`<video width="320" height="240" controls>
<source src="observable.mp4" type="video/mp4">
<source src="observable.mov" type="video/mov">
Learn more about Observable CLI
</video>`;

const expected = html`<video width="320" height="240" controls>
<source src="./_file/observable.mp4" type="video/mp4">
<source src="./_file/observable.mov" type="video/mov">
Learn more about Observable CLI
</video>`;

const context = mockContext();
const actual = normalizePieceHtml(htmlStr, sourcePath, context);

assert.equal(expected, actual);
assert.deepEqual(context.files, [
{
mimeType: "video/mp4",
name: "observable.mp4",
path: "./_file/observable.mp4"
},
{
mimeType: "video/quicktime",
name: "observable.mov",
path: "./_file/observable.mov"
}
]);
});
});
});

0 comments on commit 006b229

Please sign in to comment.