Skip to content

Commit

Permalink
Merge pull request #83 from mogeko/dev
Browse files Browse the repository at this point in the history
Implement the encoder by ourselves
  • Loading branch information
mogeko authored Sep 28, 2024
2 parents 8f0baec + 51c7561 commit 891b419
Showing 19 changed files with 166 additions and 227 deletions.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file modified .yarn/install-state.gz
Binary file not shown.
6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "gatsby-remark-plantuml-lite",
"version": "0.2.1",
"version": "0.3.0",
"description": "A Gatsby plugin to transform PlantUML code blocks into SVG images",
"main": "dist/index.js",
"types": "dist/index.d.ts",
@@ -32,8 +32,8 @@
"cov": "vitest run --coverage"
},
"dependencies": {
"plantuml-encoder": "^1.4.0",
"unist-util-flatmap": "^1.0.0"
"unist-builder": "^4.0.0",
"unist-util-visit": "^5.0.0"
},
"devDependencies": {
"@biomejs/biome": "1.9.2",
8 changes: 0 additions & 8 deletions src/@types/plantuml-encoder.d.ts

This file was deleted.

15 changes: 0 additions & 15 deletions src/@types/unist-util-flatmap.d.ts

This file was deleted.

78 changes: 78 additions & 0 deletions src/encoder.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import { type InputType, deflateRawSync } from "node:zlib";

export function deflate(buff: InputType) {
return deflateRawSync(buff, { level: 9 }).toString("binary");
}

function encode6bit(code: number) {
if (code < 10) return String.fromCharCode(48 + code); // 0-9
if (code < 36) return String.fromCharCode(55 + code); // A-Z
if (code < 62) return String.fromCharCode(61 + code); // a-z
if (code === 62) return "-";
if (code === 63) return "_";
return "?";
}

function append3bytes(b1: number, b2: number, b3: number) {
return (
encode6bit((b1 >> 2) & 0x3f) +
encode6bit(((b1 & 0x3) << 4) | ((b2 >> 4) & 0x3f)) +
encode6bit(((b2 & 0xf) << 2) | ((b3 >> 6) & 0x3f)) +
encode6bit(b3 & 0x3f)
);
}

function encode64(data: string) {
let r = "";
for (let i = 0; i < data.length; i += 3) {
if (i + 2 === data.length) {
r += append3bytes(data.charCodeAt(i), data.charCodeAt(i + 1), 0);
} else if (i + 1 === data.length) {
r += append3bytes(data.charCodeAt(i), 0, 0);
} else {
r += append3bytes(
data.charCodeAt(i),
data.charCodeAt(i + 1),
data.charCodeAt(i + 2),
);
}
}
return r;
}

export function encoder(puml: string) {
return encode64(deflate(puml));
}

if (import.meta.vitest) {
const { Buffer } = await import("node:buffer");
const { expect, it } = await import("vitest");

it("encode6bit", () => {
expect(
[
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37,
38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55,
56, 57, 58, 59, 60, 61, 62, 63,
]
.map(encode6bit)
.join(""),
).toStrictEqual(
"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-_",
);
expect(encode6bit(64)).toStrictEqual("?");
});

it("append3bytes", () => {
expect(append3bytes(1, 2, 3)).toStrictEqual("0G83");
expect(append3bytes(1, 2, 0)).toStrictEqual("0G80");
expect(append3bytes(1, 0, 0)).toStrictEqual("0G00");
});

it("encode64", () => {
expect(
encode64(Buffer.from([75, 76, 74, 6, 0]).toString("binary")),
).toStrictEqual("IqnA1W00");
});
}
47 changes: 24 additions & 23 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,17 @@
import { type NodeOpt, nodeOperator } from "@/lib";
import { encoder } from "@/encoder";
import type { Root } from "mdast";
import { u } from "unist-builder";
import { visit } from "unist-util-visit";

export default function remarkPlantUML(
{ markdownAST }: ParsedTypes,
pluginOptions?: OptionTypes,
{ markdownAST }: { markdownAST: Root },
pluginOptions?: {
imageType?: "svg" | "png"; // Type of PlantUML image returned from Web Server
server?: string; // PlantUML server to generate UML diagrams on-the-fly
codeBlockLang?: string; // Name of the codeblock languange
title?: string; // Specifies the title property of the generated PlantUML image
alt?: string; // Specifies the alt property of the generated PlantUML image
},
): Root {
const imageType = pluginOptions?.imageType ?? "svg";
const server = pluginOptions?.server
@@ -12,25 +20,18 @@ export default function remarkPlantUML(
: pluginOptions.server
: "https://www.plantuml.com/plantuml";
const codeBlockLang = pluginOptions?.codeBlockLang ?? "plantuml";
return nodeOperator(
markdownAST,
(encoded) => {
return `${server}/${imageType}/${encoded}`;
},
codeBlockLang,
{
title: pluginOptions?.title ?? null,
alt: pluginOptions?.alt ?? null,
},
);
}

type ParsedTypes = {
markdownAST: Root;
};
visit(markdownAST, "code", (node, index, parents) => {
if (node.lang === codeBlockLang && parents) {
parents.children[index ?? 0] = u("paragraph", {}, [
u("image", {
url: `${server}/${imageType}/${encoder(node.value)}`,
title: pluginOptions?.title,
alt: pluginOptions?.alt ?? codeBlockLang,
}),
]);
}
});

type OptionTypes = {
imageType?: "svg" | "png";
server?: string;
codeBlockLang?: string;
} & NodeOpt;
return markdownAST;
}
36 changes: 0 additions & 36 deletions src/lib.ts

This file was deleted.

14 changes: 14 additions & 0 deletions tests/encoder.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { deflate, encoder } from "@/encoder";
import { expect, it } from "vitest";

it("deflateSync", () => {
expect(deflate("abc")).toStrictEqual(
Buffer.from([75, 76, 74, 6, 0]).toString("binary"),
);
});

it("encoderSync", () => {
expect(encoder(`@startuml\nA -> B: Hello / 你好'\n@enduml`)).toMatch(
/SoWkIImgAStDuN9KqBLJSB9Iy4ZDoSbNq5TuidV1qwLxrRaSKlDI/,
);
});
2 changes: 1 addition & 1 deletion tests/index.test.ts
Original file line number Diff line number Diff line change
@@ -31,7 +31,7 @@ describe("基础测试", () => {
});

it("测试 Image 的 Title", () => {
expect(image.title).toEqual(null);
expect(image.title).toBeUndefined();
});

it("测试 Image 的 Url", () => {
126 changes: 0 additions & 126 deletions tests/lib.test.ts

This file was deleted.

1 change: 1 addition & 0 deletions tsconfig.json
Original file line number Diff line number Diff line change
@@ -2,6 +2,7 @@
"$schema": "https://json.schemastore.org/tsconfig",
"extends": "@tsconfig/strictest/tsconfig.json",
"compilerOptions": {
"types": ["vitest/importMeta"],
"target": "ESNext",
"module": "ESNext",
"moduleResolution": "Bundler",
9 changes: 7 additions & 2 deletions tsup.config.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
import { defineConfig } from "tsup";

export default defineConfig({
entry: ["src/index.ts"],
entry: ["./src/index.ts"],
format: ["cjs"],
clean: true,
dts: true,
minify: true,

// To delete the in-source testing (comes from vitest)
// See: https://github.com/egoist/tsup/issues/625#issuecomment-1608591913
define: { "import.meta.vitest": "false" },
treeshake: true,
});
Loading

0 comments on commit 891b419

Please sign in to comment.