UNPKG

@inlang/paraglide-js

Version:

[![NPM Downloads](https://img.shields.io/npm/dw/%40inlang%2Fparaglide-js?logo=npm&logoColor=red&label=npm%20downloads)](https://www.npmjs.com/package/@inlang/paraglide-js) [![GitHub Issues](https://img.shields.io/github/issues-closed/opral/paraglide-js?lo

255 lines 9.38 kB
import { test, expect } from "vitest"; import { compilePattern } from "./compile-pattern.js"; test("should compile a text only pattern", () => { const pattern = [{ type: "text", value: "Hello" }]; const { code } = compilePattern({ pattern, declarations: [] }); expect(code).toBe("`Hello`"); }); test("should compile a pattern with multiple VariableReference's", () => { const pattern = [ { type: "text", value: "Hello " }, { type: "expression", arg: { type: "variable-reference", name: "name", }, }, { type: "text", value: "! You have " }, { type: "expression", arg: { type: "variable-reference", name: "count" } }, { type: "text", value: " messages." }, ]; const { code } = compilePattern({ pattern, declarations: [ { type: "input-variable", name: "name" }, { type: "input-variable", name: "count" }, ], }); expect(code).toBe("`Hello ${i?.name}! You have ${i?.count} messages.`"); }); test("uses bracket notation for input variables with non-identifier names", () => { const pattern = [ { type: "text", value: "Half " }, { type: "expression", arg: { type: "variable-reference", name: "half!", }, }, ]; const { code } = compilePattern({ pattern, declarations: [{ type: "input-variable", name: "half!" }], }); expect(code).toBe('`Half ${i?.["half!"]}`'); }); test("should escape backticks", () => { const pattern = [{ type: "text", value: "`Hello world`" }]; const { code } = compilePattern({ pattern, declarations: [] }); expect(code).toBe("`\\`Hello world\\``"); }); test("should escape backslashes", () => { const pattern = [{ type: "text", value: "\\Hello world\\" }]; const { code } = compilePattern({ pattern, declarations: [] }); expect(code).toBe("`\\\\Hello world\\\\`"); }); test("should escape escaped backticks", () => { const pattern = [{ type: "text", value: "\\`Hello world\\`" }]; const { code } = compilePattern({ pattern, declarations: [] }); expect(code).toBe("`\\\\\\`Hello world\\\\\\``"); }); test("should escape variable interpolation ( ${} )", () => { const pattern = [{ type: "text", value: "${name" }]; const { code } = compilePattern({ pattern, declarations: [] }); expect(code).toBe("`\\${name`"); }); test("it can reference local variables", () => { const { code } = compilePattern({ pattern: [ { type: "text", value: "Hello " }, { type: "expression", arg: { type: "variable-reference", name: "name", }, }, ], declarations: [ { type: "local-variable", name: "name", value: { type: "expression", arg: { type: "literal", value: "Peter" }, }, }, ], }); expect(code).toBe("`Hello ${name}`"); }); test("plain string mode strips markup wrappers", () => { const pattern = [ { type: "text", value: "Hello " }, { type: "markup-start", name: "b" }, { type: "expression", arg: { type: "variable-reference", name: "name" } }, { type: "markup-end", name: "b" }, { type: "text", value: "!" }, ]; const { code } = compilePattern({ pattern, declarations: [{ type: "input-variable", name: "name" }], }); expect(code).toBe("`Hello ${i?.name}!`"); }); test("compiles a pattern expression annotation to a registry call", () => { // https://github.com/opral/paraglide-js/issues/694 const pattern = [ { type: "expression", arg: { type: "variable-reference", name: "count" }, annotation: { type: "function-reference", name: "number", options: [] }, }, { type: "text", value: " views" }, ]; const { code } = compilePattern({ pattern, declarations: [{ type: "input-variable", name: "count" }], locale: "en", }); expect(code).toBe('`${registry.number("en", i?.count, {})} views`'); }); test("compiles pattern expression annotation options like local variable annotations", () => { const pattern = [ { type: "expression", arg: { type: "variable-reference", name: "price" }, annotation: { type: "function-reference", name: "number", options: [ { name: "minimumFractionDigits", value: { type: "literal", value: "2" }, }, { name: "style", value: { type: "literal", value: "percent" } }, ], }, }, ]; const { code } = compilePattern({ pattern, declarations: [{ type: "input-variable", name: "price" }], locale: "de", }); expect(code).toBe('`${registry.number("de", i?.price, { minimumFractionDigits: 2, style: "percent" })}`'); }); test("parts mode compiles pattern expression annotations to registry calls", () => { const pattern = [ { type: "expression", arg: { type: "variable-reference", name: "count" }, annotation: { type: "function-reference", name: "number", options: [] }, }, { type: "text", value: " views" }, ]; const { code } = compilePattern({ mode: "parts", pattern, declarations: [{ type: "input-variable", name: "count" }], locale: "en", }); expect(code).toBe('[{ type: "text", value: String(registry.number("en", i?.count, {})) }, { type: "text", value: " views" }]'); }); test("falls back to plain interpolation for unknown formatters", () => { const pattern = [ { type: "expression", arg: { type: "variable-reference", name: "name" }, annotation: { type: "function-reference", name: "uppercase", options: [], }, }, ]; const { code } = compilePattern({ pattern, declarations: [{ type: "input-variable", name: "name" }], locale: "en", }); expect(code).toBe("`${i?.name}`"); }); test("throws when a pattern annotation is compiled without a locale", () => { const pattern = [ { type: "expression", arg: { type: "variable-reference", name: "count" }, annotation: { type: "function-reference", name: "number", options: [] }, }, ]; expect(() => compilePattern({ pattern, declarations: [{ type: "input-variable", name: "count" }], })).toThrow('requires a locale to compile the formatter "number"'); }); test("validates relativetime options on pattern annotations", () => { const pattern = [ { type: "expression", arg: { type: "variable-reference", name: "days" }, annotation: { type: "function-reference", name: "relativetime", options: [], }, }, ]; expect(() => compilePattern({ pattern, declarations: [{ type: "input-variable", name: "days" }], locale: "en", })).toThrow('The "relativetime" formatter requires a "unit" option.'); }); test("parts mode compiles text, markup, options and attributes", () => { const pattern = [ { type: "text", value: "Read " }, { type: "markup-start", name: "link", options: [ { name: "to", value: { type: "literal", value: "/docs" } }, { name: "rel", value: { type: "variable-reference", name: "relationship" }, }, ], attributes: [ { name: "track", value: true }, { name: "variant", value: { type: "literal", value: "hero" } }, ], }, { type: "text", value: "docs" }, { type: "markup-end", name: "link", options: [{ name: "to", value: { type: "literal", value: "/docs" } }], attributes: [{ name: "track", value: true }], }, { type: "markup-standalone", name: "icon", options: [{ name: "name", value: { type: "literal", value: "arrow" } }], attributes: [{ name: "filled", value: true }], }, ]; const { code } = compilePattern({ mode: "parts", pattern, declarations: [{ type: "input-variable", name: "relationship" }], }); expect(code).toBe('[{ type: "text", value: "Read " }, { type: "markup-start", name: "link", options: { "to": "/docs", "rel": i?.relationship }, attributes: { "track": true, "variant": "hero" } }, { type: "text", value: "docs" }, { type: "markup-end", name: "link", options: { "to": "/docs" }, attributes: { "track": true } }, { type: "markup-standalone", name: "icon", options: { "name": "arrow" }, attributes: { "filled": true } }]'); }); //# sourceMappingURL=compile-pattern.test.js.map