docusaurus-plugin-docusynx 0.1.2 → 0.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/assets.d.ts CHANGED
@@ -3,5 +3,6 @@ export declare class AssetCollector {
3
3
  #private;
4
4
  constructor(outputDirectory: string);
5
5
  add(sourcePath: string, mimeType?: string): Promise<string>;
6
+ addBytes(content: string | Uint8Array, extension: string, mimeType?: string): Promise<string>;
6
7
  values(): BundleAsset[];
7
8
  }
package/dist/assets.js CHANGED
@@ -1,6 +1,7 @@
1
1
  import { createHash } from 'node:crypto';
2
- import { copyFile, mkdir, readFile } from 'node:fs/promises';
2
+ import { mkdir, readFile, writeFile } from 'node:fs/promises';
3
3
  import path from 'node:path';
4
+ import { assertSafeSvg } from './svg.js';
4
5
  const MIME_BY_EXTENSION = {
5
6
  '.gif': 'image/gif',
6
7
  '.jpeg': 'image/jpeg',
@@ -17,21 +18,47 @@ export class AssetCollector {
17
18
  }
18
19
  async add(sourcePath, mimeType) {
19
20
  const bytes = await readFile(sourcePath);
21
+ return this.addBytes(bytes, path.extname(sourcePath).toLowerCase(), mimeType);
22
+ }
23
+ async addBytes(content, extension, mimeType) {
24
+ if (!/^\.[a-z0-9]+$/.test(extension)) {
25
+ throw new Error(`invalid asset extension ${JSON.stringify(extension)}`);
26
+ }
27
+ const bytes = typeof content === 'string' ? Buffer.from(content, 'utf8') : content;
20
28
  const digest = createHash('sha256').update(bytes).digest('hex');
21
- const extension = path.extname(sourcePath).toLowerCase();
22
29
  const id = `sha256:${digest}`;
23
30
  const relativePath = `assets/${digest}${extension}`;
24
- if (!this.#assets.has(id)) {
31
+ const resolvedMimeType = mimeType ??
32
+ MIME_BY_EXTENSION[extension] ??
33
+ 'application/octet-stream';
34
+ if (extension === '.svg' ||
35
+ resolvedMimeType.split(';', 1)[0]?.trim().toLowerCase() ===
36
+ 'image/svg+xml') {
37
+ let svg;
38
+ try {
39
+ svg = new TextDecoder('utf-8', { fatal: true }).decode(bytes);
40
+ }
41
+ catch {
42
+ throw new Error('unsafe SVG content: invalid UTF-8');
43
+ }
44
+ assertSafeSvg(svg);
45
+ }
46
+ const existing = this.#assets.get(id);
47
+ if (existing) {
48
+ if (existing.path !== relativePath ||
49
+ existing.mimeType !== resolvedMimeType) {
50
+ throw new Error(`asset metadata conflicts for ${id}`);
51
+ }
52
+ }
53
+ else {
25
54
  await mkdir(path.join(this.#outputDirectory, 'assets'), {
26
55
  recursive: true,
27
56
  });
28
- await copyFile(sourcePath, path.join(this.#outputDirectory, relativePath));
57
+ await writeFile(path.join(this.#outputDirectory, relativePath), bytes);
29
58
  this.#assets.set(id, {
30
59
  id,
31
60
  path: relativePath,
32
- mimeType: mimeType ??
33
- MIME_BY_EXTENSION[extension] ??
34
- 'application/octet-stream',
61
+ mimeType: resolvedMimeType,
35
62
  hash: id,
36
63
  });
37
64
  }
package/dist/markdown.js CHANGED
@@ -184,7 +184,9 @@ async function transformComponent(node, context) {
184
184
  siteDir: context.siteDir,
185
185
  sourcePath: context.sourcePath,
186
186
  readSiteFile: async (requestedPath) => readFile(resolveSitePath(context.siteDir, requestedPath), 'utf8'),
187
- addAsset: async (input) => context.assets.add(resolveSitePath(context.siteDir, input.path), input.mimeType),
187
+ addAsset: async (input) => 'path' in input
188
+ ? context.assets.add(resolveSitePath(context.siteDir, input.path), input.mimeType)
189
+ : context.assets.addBytes(input.content, input.extension, input.mimeType),
188
190
  transformChildren: async () => transformBlockChildren(children, context),
189
191
  };
190
192
  const result = await handler.transform(handlerContext);
package/dist/types.d.ts CHANGED
@@ -98,10 +98,14 @@ export interface DocumentBundle {
98
98
  assets: BundleAsset[];
99
99
  hash: string;
100
100
  }
101
- export interface ComponentHandlerAssetInput {
101
+ export type ComponentHandlerAssetInput = {
102
102
  path: string;
103
103
  mimeType?: string;
104
- }
104
+ } | {
105
+ content: string | Uint8Array;
106
+ extension: '.svg';
107
+ mimeType: 'image/svg+xml';
108
+ };
105
109
  export interface ComponentHandlerContext {
106
110
  readonly node: MdxAstNode;
107
111
  readonly props: Readonly<Record<string, unknown>>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "docusaurus-plugin-docusynx",
3
- "version": "0.1.2",
3
+ "version": "0.1.3",
4
4
  "description": "Export a deterministic Docusaurus document bundle for docusynx",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {