@fraqjs/plugin-takumi 0.1.0 → 0.1.2
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/index.d.mts +8 -3
- package/dist/index.mjs +42 -12
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Context, Disposable } from "@fraqjs/fraq";
|
|
2
2
|
import { ConstructRendererOptions, Font, RenderOptions, Renderer } from "@takumi-rs/core";
|
|
3
3
|
import { ReactElementLike } from "@takumi-rs/helpers";
|
|
4
|
+
import { EmojiType } from "@takumi-rs/helpers/emoji";
|
|
4
5
|
import { ReactNode } from "react";
|
|
5
6
|
|
|
6
7
|
//#region src/service.d.ts
|
|
@@ -15,15 +16,18 @@ interface PathBasedFontDetails {
|
|
|
15
16
|
style?: 'normal' | 'italic' | 'oblique' | `oblique ${number}deg` | (string & {});
|
|
16
17
|
}
|
|
17
18
|
declare class TakumiService implements Disposable {
|
|
18
|
-
private readonly ctx
|
|
19
|
+
private readonly ctx?;
|
|
19
20
|
readonly renderer: Renderer;
|
|
20
21
|
private readonly abortController;
|
|
21
22
|
private readonly registeredFontFamilies;
|
|
22
23
|
private onFontRegisterConflict;
|
|
23
|
-
constructor(ctx
|
|
24
|
+
constructor(options?: TakumiServiceOptions, ctx?: Context | undefined);
|
|
24
25
|
registerFontFamily(family: string, fonts: (string | PathBasedFontDetails | Font)[], signal?: AbortSignal): Promise<void>;
|
|
25
26
|
renderJsx(jsx: ReactNode | ReactElementLike, renderOptions?: RenderOptions, signal?: AbortSignal): Promise<Buffer>;
|
|
27
|
+
renderJsxWithEmoji(jsx: ReactNode | ReactElementLike, renderOptions?: RenderOptions, signal?: AbortSignal, emojiType?: EmojiType): Promise<Buffer>;
|
|
26
28
|
renderHtml(html: string, renderOptions?: RenderOptions, signal?: AbortSignal): Promise<Buffer>;
|
|
29
|
+
renderHtmlWithEmoji(html: string, renderOptions?: RenderOptions, signal?: AbortSignal, emojiType?: EmojiType): Promise<Buffer>;
|
|
30
|
+
private processEmoji;
|
|
27
31
|
dispose(): void;
|
|
28
32
|
}
|
|
29
33
|
//#endregion
|
|
@@ -31,6 +35,7 @@ declare class TakumiService implements Disposable {
|
|
|
31
35
|
interface TakumiPluginOptions extends TakumiServiceOptions {
|
|
32
36
|
loadBuiltinFonts?: boolean;
|
|
33
37
|
}
|
|
38
|
+
declare function loadBuiltinFontsForService(service: TakumiService): Promise<void>;
|
|
34
39
|
declare const TakumiPlugin: import("@fraqjs/fraq").Plugin<[options?: TakumiPluginOptions | undefined], import("@fraqjs/fraq").Injection | undefined, import("@fraqjs/fraq").Injection | undefined>;
|
|
35
40
|
//#endregion
|
|
36
|
-
export { PathBasedFontDetails, TakumiPlugin, TakumiPlugin as default, TakumiPluginOptions, TakumiService, TakumiServiceOptions };
|
|
41
|
+
export { PathBasedFontDetails, TakumiPlugin, TakumiPlugin as default, TakumiPluginOptions, TakumiService, TakumiServiceOptions, loadBuiltinFontsForService };
|
package/dist/index.mjs
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { createRequire } from "node:module";
|
|
2
2
|
import { definePlugin } from "@fraqjs/fraq";
|
|
3
|
-
import { Renderer } from "@takumi-rs/core";
|
|
3
|
+
import { Renderer, extractResourceUrls } from "@takumi-rs/core";
|
|
4
|
+
import { fetchResources } from "@takumi-rs/helpers";
|
|
5
|
+
import { extractEmojis } from "@takumi-rs/helpers/emoji";
|
|
4
6
|
import { fromHtml } from "@takumi-rs/helpers/html";
|
|
5
7
|
import { fromJsx } from "@takumi-rs/helpers/jsx";
|
|
6
8
|
import fs from "node:fs/promises";
|
|
@@ -21,19 +23,21 @@ var TakumiService = class {
|
|
|
21
23
|
abortController = new AbortController();
|
|
22
24
|
registeredFontFamilies = /* @__PURE__ */ new Set();
|
|
23
25
|
onFontRegisterConflict;
|
|
24
|
-
constructor(
|
|
26
|
+
constructor(options, ctx) {
|
|
25
27
|
this.ctx = ctx;
|
|
26
|
-
this.renderer = new Renderer(options
|
|
27
|
-
this.onFontRegisterConflict = options
|
|
28
|
+
this.renderer = new Renderer(options?.renderer);
|
|
29
|
+
this.onFontRegisterConflict = options?.onFontRegisterConflict ?? "warn-and-ignore";
|
|
28
30
|
}
|
|
29
31
|
async registerFontFamily(family, fonts, signal) {
|
|
30
32
|
if (this.registeredFontFamilies.has(family)) {
|
|
31
33
|
const message = `Font family "${family}" has already been registered.`;
|
|
32
34
|
if (this.onFontRegisterConflict === "error") throw new Error(message);
|
|
33
35
|
else if (this.onFontRegisterConflict === "warn-and-ignore") {
|
|
34
|
-
this.ctx.logger.warn(`${message} Ignoring new registration.`);
|
|
36
|
+
if (this.ctx) this.ctx.logger.warn(`${message} Ignoring new registration.`);
|
|
37
|
+
else console.warn(`${message} Ignoring new registration.`);
|
|
35
38
|
return;
|
|
36
|
-
} else if (this.onFontRegisterConflict === "warn-and-replace") this.ctx.logger.warn(`${message} Replacing previous registration.`);
|
|
39
|
+
} else if (this.onFontRegisterConflict === "warn-and-replace") if (this.ctx) this.ctx.logger.warn(`${message} Replacing previous registration.`);
|
|
40
|
+
else console.warn(`${message} Replacing previous registration.`);
|
|
37
41
|
}
|
|
38
42
|
await this.renderer.loadFonts(await Promise.all(fonts.map(async (font) => {
|
|
39
43
|
if (typeof font === "string") return {
|
|
@@ -56,30 +60,56 @@ var TakumiService = class {
|
|
|
56
60
|
const { node, stylesheets } = await fromJsx(jsx);
|
|
57
61
|
return this.renderer.render(node, withMergedStylesheets(stylesheets, renderOptions), combineAbortSignals(signal, this.abortController.signal));
|
|
58
62
|
}
|
|
63
|
+
async renderJsxWithEmoji(jsx, renderOptions, signal, emojiType = "noto") {
|
|
64
|
+
const { node, stylesheets } = await fromJsx(jsx);
|
|
65
|
+
const { node: processedNode, fetchedResources } = await this.processEmoji(node, emojiType);
|
|
66
|
+
return this.renderer.render(processedNode, withMergedStylesheets(stylesheets, {
|
|
67
|
+
...renderOptions,
|
|
68
|
+
fetchedResources: [...fetchedResources, ...renderOptions?.fetchedResources ?? []]
|
|
69
|
+
}), combineAbortSignals(signal, this.abortController.signal));
|
|
70
|
+
}
|
|
59
71
|
async renderHtml(html, renderOptions, signal) {
|
|
60
72
|
const { node, stylesheets } = fromHtml(html);
|
|
61
73
|
return this.renderer.render(node, withMergedStylesheets(stylesheets, renderOptions), combineAbortSignals(signal, this.abortController.signal));
|
|
62
74
|
}
|
|
75
|
+
async renderHtmlWithEmoji(html, renderOptions, signal, emojiType = "noto") {
|
|
76
|
+
const { node, stylesheets } = fromHtml(html);
|
|
77
|
+
const { node: processedNode, fetchedResources } = await this.processEmoji(node, emojiType);
|
|
78
|
+
return this.renderer.render(processedNode, withMergedStylesheets(stylesheets, {
|
|
79
|
+
...renderOptions,
|
|
80
|
+
fetchedResources: [...fetchedResources, ...renderOptions?.fetchedResources ?? []]
|
|
81
|
+
}), combineAbortSignals(signal, this.abortController.signal));
|
|
82
|
+
}
|
|
83
|
+
async processEmoji(node, emojiType = "twemoji") {
|
|
84
|
+
const processedNode = extractEmojis(node, emojiType);
|
|
85
|
+
return {
|
|
86
|
+
node: processedNode,
|
|
87
|
+
fetchedResources: await fetchResources(extractResourceUrls(processedNode))
|
|
88
|
+
};
|
|
89
|
+
}
|
|
63
90
|
dispose() {
|
|
64
91
|
this.abortController.abort();
|
|
65
92
|
}
|
|
66
93
|
};
|
|
67
94
|
//#endregion
|
|
68
95
|
//#region src/index.ts
|
|
96
|
+
async function loadBuiltinFontsForService(service) {
|
|
97
|
+
const require = createRequire(import.meta.url);
|
|
98
|
+
await service.registerFontFamily("Inter", [require.resolve("../fonts/Inter-VariableFont_opsz,wght.ttf"), require.resolve("../fonts/Inter-Italic-VariableFont_opsz,wght.ttf")]);
|
|
99
|
+
await service.registerFontFamily("Roboto Mono", [require.resolve("../fonts/RobotoMono-VariableFont_wght.ttf"), require.resolve("../fonts/RobotoMono-Italic-VariableFont_wght.ttf")]);
|
|
100
|
+
await service.registerFontFamily("Noto Sans SC", [require.resolve("../fonts/NotoSansSC-VariableFont_wght.ttf")]);
|
|
101
|
+
}
|
|
69
102
|
const TakumiPlugin = definePlugin({
|
|
70
103
|
name: "takumi",
|
|
71
104
|
provides: [TakumiService],
|
|
72
105
|
async apply(ctx, options) {
|
|
73
|
-
const service = new TakumiService(
|
|
106
|
+
const service = new TakumiService(options, ctx);
|
|
74
107
|
if (options?.loadBuiltinFonts ?? true) {
|
|
75
108
|
ctx.logger.debug("Loading built-in fonts...");
|
|
76
|
-
|
|
77
|
-
await service.registerFontFamily("Inter", [require.resolve("../fonts/Inter-VariableFont_opsz,wght.ttf"), require.resolve("../fonts/Inter-Italic-VariableFont_opsz,wght.ttf")]);
|
|
78
|
-
await service.registerFontFamily("Roboto Mono", [require.resolve("../fonts/RobotoMono-VariableFont_wght.ttf"), require.resolve("../fonts/RobotoMono-Italic-VariableFont_wght.ttf")]);
|
|
79
|
-
await service.registerFontFamily("Noto Sans SC", [require.resolve("../fonts/NotoSansSC-VariableFont_wght.ttf")]);
|
|
109
|
+
await loadBuiltinFontsForService(service);
|
|
80
110
|
}
|
|
81
111
|
ctx.provide(TakumiService, service);
|
|
82
112
|
}
|
|
83
113
|
});
|
|
84
114
|
//#endregion
|
|
85
|
-
export { TakumiPlugin, TakumiPlugin as default, TakumiService };
|
|
115
|
+
export { TakumiPlugin, TakumiPlugin as default, TakumiService, loadBuiltinFontsForService };
|