diff --git a/.gitignore b/.gitignore index 246e8b2..c98486e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ node_modules scripts/dist packages/*/dist -.turbo \ No newline at end of file +.turbo +.vscode/settings.json diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 0000000..a5824a5 --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,5 @@ +{ + "recommendations": [ + "biomejs.biome" + ] +} \ No newline at end of file diff --git a/.vscode/settings.recommend.json b/.vscode/settings.recommend.json new file mode 100644 index 0000000..d83931f --- /dev/null +++ b/.vscode/settings.recommend.json @@ -0,0 +1,8 @@ +{ + "[json]": { + "editor.defaultFormatter": "biomejs.biome" + }, + "[typescript]": { + "editor.defaultFormatter": "biomejs.biome" + }, +} \ No newline at end of file diff --git a/packages/minify-literals/lib/index.test.ts b/packages/minify-literals/lib/index.test.ts index 5607a98..6a2b042 100644 --- a/packages/minify-literals/lib/index.test.ts +++ b/packages/minify-literals/lib/index.test.ts @@ -12,11 +12,68 @@ import { } from "./"; import { defaultMinifyOptions, defaultStrategy } from "./strategy"; +/** + * get code snippet from function body + */ +const fn_body = (fn: Function, tabSize = 2) => { + const fn_str = fn.toString(); + const body_str = fn_str + .slice(fn_str.indexOf("{") + 1, fn_str.lastIndexOf("}")) + // remove trailing whitespace + .trimEnd() + // remove empty lines + .replace(/^([\s\t]*$\r?\n)+/gm, "") + // use spaces uniformly: current indentStyle is "tab",and tab-width == 2(spaces) + .replace(/^\t+/gm, (tabs) => " ".repeat(tabs.length * tabSize)); + /// remove indent + const indent = body_str.match(/\s+/)?.[0]; + if (!indent) { + return body_str.trim(); + } + const indent_reg = new RegExp(`^\\s{${indent.length}}`, "gm"); + return body_str.replace(indent_reg, ""); +}; // https://github.com/explodingcamera/esm/issues/1 describe("handle key value pairs correctly", () => { - it("should minify html", async () => { - const source = `const css = css\`:host{\${"color"}: \${"red"}}\``; - expect((await minifyHTMLLiterals(source))?.code).toMatch('const css = css`:host{${"color"}:${"red"}}`'); + it("should minify css", async () => { + const source = fn_body((css = String.raw) => { + const cssText = css`:host{ + ${"color"}: ${"red"}; + }`; + }); + + expect((await minifyHTMLLiterals(source))?.code).toMatch( + fn_body((css = String.raw) => { + const cssText = css`:host{${"color"}:${"red"}}`; + }), + ); + }); + + it("should minify css with unit", async () => { + const source = fn_body((css = String.raw) => { + const cssText = css`:host{ + ${"width"}: ${10}px; + }`; + }); + + expect((await minifyHTMLLiterals(source))?.code).toMatch( + fn_body((css = String.raw) => { + const cssText = css`:host{${"width"}:${10}px}`; + }), + ); + }); + it("should minify css within css-function", async () => { + const source = fn_body((css = String.raw) => { + const cssText = css`:host{ + ${"width"}: calc(${10}px + ${"var(--data)"}); + }`; + }); + + expect((await minifyHTMLLiterals(source))?.code).toMatch( + fn_body((css = String.raw) => { + const cssText = css`:host{${"width"}:calc(${10}px + ${"var(--data)"})}`; + }), + ); }); }); diff --git a/packages/minify-literals/lib/index.ts b/packages/minify-literals/lib/index.ts index 93d0699..a09f923 100644 --- a/packages/minify-literals/lib/index.ts +++ b/packages/minify-literals/lib/index.ts @@ -210,9 +210,13 @@ export function defaultShouldMinifyCSS(template: Template) { */ export const defaultValidation: Validation = { ensurePlaceholderValid(placeholder) { - if (typeof placeholder !== "string" || !placeholder.length) { - throw new Error("getPlaceholder() must return a non-empty string"); + if (typeof placeholder === "string" && placeholder.length > 0) { + return; } + if (Array.isArray(placeholder) && placeholder.every((ph) => ph.length > 0)) { + return; + } + throw new Error("getPlaceholder() must return a non-empty string | string[]"); }, ensureHTMLPartsValid(parts, htmlParts) { if (parts.length !== htmlParts.length) { @@ -291,7 +295,7 @@ export async function minifyHTMLLiterals(source: string, options: Options = {}): if (!(minifyHTML || minifyCSS)) return; - const placeholder = strategy.getPlaceholder(template.parts); + const placeholder = strategy.getPlaceholder(template.parts, template.tag); if (validate) { validate.ensurePlaceholderValid(placeholder); } diff --git a/packages/minify-literals/lib/strategy.test.ts b/packages/minify-literals/lib/strategy.test.ts index 7ac991d..929f0bf 100644 --- a/packages/minify-literals/lib/strategy.test.ts +++ b/packages/minify-literals/lib/strategy.test.ts @@ -26,10 +26,12 @@ describe("strategy", () => { }); it('should append "_" if placeholder exists in templates', () => { - const regularPlaceholder = defaultStrategy.getPlaceholder(parts); + const regularPlaceholder = defaultStrategy.getPlaceholder(parts) as string; + expect(regularPlaceholder).toBeTypeOf("string"); const oneUnderscore = defaultStrategy.getPlaceholder([ { text: regularPlaceholder, start: 0, end: regularPlaceholder.length }, - ]); + ]) as string; + expect(oneUnderscore).toBeTypeOf("string"); expect(oneUnderscore).not.toEqual(regularPlaceholder); expect(oneUnderscore.includes("_")).toEqual(true); @@ -53,7 +55,8 @@ describe("strategy", () => { }); it("should return a value that is preserved by html-minifier when splitting", async () => { - const placeholder = defaultStrategy.getPlaceholder(parts); + const placeholder = defaultStrategy.getPlaceholder(parts) as string; + expect(placeholder).toBeTypeOf("string"); const minHtml = await defaultStrategy.minifyHTML( `