diff --git a/packages/format-csv/__typetests__/index.test-d.ts b/packages/format-csv/__typetests__/index.test-d.ts new file mode 100644 index 000000000..f61407344 --- /dev/null +++ b/packages/format-csv/__typetests__/index.test-d.ts @@ -0,0 +1,5 @@ +import { CatalogFormatter } from "@lingui/conf" +import { expectAssignable } from "tsd" +import { formatter } from "@lingui/format-csv" + +expectAssignable(formatter()) diff --git a/packages/format-csv/__typetests__/tsconfig.json b/packages/format-csv/__typetests__/tsconfig.json new file mode 100644 index 000000000..114e1ccd5 --- /dev/null +++ b/packages/format-csv/__typetests__/tsconfig.json @@ -0,0 +1,9 @@ +{ + "compilerOptions": { + "target": "ESNext", + "moduleResolution": "Node16", + "skipLibCheck": true, + "esModuleInterop": true + }, + "paths": {} +} diff --git a/packages/format-csv/package.json b/packages/format-csv/package.json index e3f5bf9b4..bec7c2b7c 100644 --- a/packages/format-csv/package.json +++ b/packages/format-csv/package.json @@ -41,6 +41,7 @@ "papaparse": "^5.4.0" }, "devDependencies": { + "tsd": "^0.28.0", "unbuild": "^1.1.2" } } diff --git a/packages/format-json/__typetests__/index.test-d.ts b/packages/format-json/__typetests__/index.test-d.ts new file mode 100644 index 000000000..420544cb0 --- /dev/null +++ b/packages/format-json/__typetests__/index.test-d.ts @@ -0,0 +1,8 @@ +import { CatalogFormatter } from "@lingui/conf" +import { expectAssignable } from "tsd" +import { formatter } from "@lingui/format-json" + +expectAssignable(formatter()) +expectAssignable( + formatter({ lineNumbers: true, origins: true }) +) diff --git a/packages/format-json/__typetests__/tsconfig.json b/packages/format-json/__typetests__/tsconfig.json new file mode 100644 index 000000000..114e1ccd5 --- /dev/null +++ b/packages/format-json/__typetests__/tsconfig.json @@ -0,0 +1,9 @@ +{ + "compilerOptions": { + "target": "ESNext", + "moduleResolution": "Node16", + "skipLibCheck": true, + "esModuleInterop": true + }, + "paths": {} +} diff --git a/packages/format-json/package.json b/packages/format-json/package.json index d1297a487..a0d98d6bf 100644 --- a/packages/format-json/package.json +++ b/packages/format-json/package.json @@ -41,6 +41,7 @@ "ramda": "^0.28.0" }, "devDependencies": { + "tsd": "^0.28.0", "unbuild": "^1.1.2" } } diff --git a/packages/format-po-gettext/__typetests__/index.test-d.ts b/packages/format-po-gettext/__typetests__/index.test-d.ts new file mode 100644 index 000000000..cafbd2834 --- /dev/null +++ b/packages/format-po-gettext/__typetests__/index.test-d.ts @@ -0,0 +1,13 @@ +import { CatalogFormatter } from "@lingui/conf" +import { expectAssignable } from "tsd" +import { formatter } from "@lingui/format-po-gettext" + +expectAssignable(formatter()) +expectAssignable( + formatter({ + lineNumbers: true, + origins: true, + printLinguiId: true, + disableSelectWarning: true, + }) +) diff --git a/packages/format-po-gettext/__typetests__/tsconfig.json b/packages/format-po-gettext/__typetests__/tsconfig.json new file mode 100644 index 000000000..114e1ccd5 --- /dev/null +++ b/packages/format-po-gettext/__typetests__/tsconfig.json @@ -0,0 +1,9 @@ +{ + "compilerOptions": { + "target": "ESNext", + "moduleResolution": "Node16", + "skipLibCheck": true, + "esModuleInterop": true + }, + "paths": {} +} diff --git a/packages/format-po-gettext/package.json b/packages/format-po-gettext/package.json index 5faf27d84..6abf61ae7 100644 --- a/packages/format-po-gettext/package.json +++ b/packages/format-po-gettext/package.json @@ -49,6 +49,7 @@ }, "devDependencies": { "@lingui/jest-mocks": "workspace:^", + "tsd": "^0.28.0", "unbuild": "^1.1.2" } } diff --git a/packages/format-po-gettext/src/po-gettext.test.ts b/packages/format-po-gettext/src/po-gettext.test.ts index 48f93b8a5..96ddaacaf 100644 --- a/packages/format-po-gettext/src/po-gettext.test.ts +++ b/packages/format-po-gettext/src/po-gettext.test.ts @@ -2,11 +2,24 @@ import { mockConsole } from "@lingui/jest-mocks" import fs from "fs" import path from "path" -import { CatalogType } from "@lingui/conf" +import { CatalogFormatter, CatalogType } from "@lingui/conf" import { formatter as createFormat } from "./po-gettext" +const defaultParseCtx: Parameters[1] = { + locale: "en", + sourceLocale: "en", + filename: "file.po", +} + +const defaultSerializeCtx: Parameters[1] = { + locale: "en", + existing: null, + filename: "file.po", + sourceLocale: "en", +} + describe("po-gettext format", () => { - let format = createFormat() + const format = createFormat() afterEach(() => { jest.useRealTimers() @@ -50,10 +63,7 @@ describe("po-gettext format", () => { }, } - const pofile = format.serialize(catalog, { - locale: "en", - existing: null, - }) + const pofile = format.serialize(catalog, defaultSerializeCtx) expect(pofile).toMatchSnapshot() }) @@ -63,7 +73,8 @@ describe("po-gettext format", () => { .readFileSync(path.join(__dirname, "fixtures/messages_plural.po")) .toString() - const catalog = format.parse(pofile) + const catalog = format.parse(pofile, defaultParseCtx) + expect(catalog).toMatchSnapshot() }) @@ -94,7 +105,7 @@ describe("po-gettext format", () => { } mockConsole((console) => { - format.serialize(catalog, { existing: null, locale: "en" }) + format.serialize(catalog, defaultSerializeCtx) expect(console.warn).toHaveBeenCalledWith( expect.stringContaining("Nested plurals"), @@ -118,7 +129,7 @@ msgstr[1] "# dny" msgstr[2] "# dní" ` - const parsed = format.parse(po) + const parsed = format.parse(po, defaultParseCtx) expect(parsed).toEqual({ Y8Xw2Y: { @@ -145,7 +156,7 @@ msgstr[2] "# dní" it("should warn", () => { mockConsole((console) => { - format.serialize(catalog, { locale: "en", existing: null }) + format.serialize(catalog, defaultSerializeCtx) expect(console.warn).toHaveBeenCalledWith( expect.stringContaining("select"), @@ -158,7 +169,7 @@ msgstr[2] "# dní" const format = createFormat({ disableSelectWarning: true }) mockConsole((console) => { - format.serialize(catalog, { locale: "en", existing: null }) + format.serialize(catalog, defaultSerializeCtx) expect(console.warn).not.toHaveBeenCalled() }) @@ -175,7 +186,7 @@ msgstr[2] "# dní" it("should warn", () => { mockConsole((console) => { - format.serialize(catalog, { locale: "en", existing: null }) + format.serialize(catalog, defaultSerializeCtx) expect(console.warn).toHaveBeenCalledWith( expect.stringContaining("selectOrdinal"), @@ -188,7 +199,7 @@ msgstr[2] "# dní" const format = createFormat({ disableSelectWarning: true }) mockConsole((console) => { - format.serialize(catalog, { locale: "en", existing: null }) + format.serialize(catalog, defaultSerializeCtx) expect(console.warn).not.toHaveBeenCalled() }) @@ -202,7 +213,8 @@ msgstr[2] "# dní" ) .toString() - const catalog = format.parse(pofile) + const catalog = format.parse(pofile, defaultParseCtx) + expect(catalog).toMatchSnapshot() }) }) diff --git a/packages/format-po-gettext/src/po-gettext.ts b/packages/format-po-gettext/src/po-gettext.ts index f59d317ad..aab6e55a8 100644 --- a/packages/format-po-gettext/src/po-gettext.ts +++ b/packages/format-po-gettext/src/po-gettext.ts @@ -238,7 +238,9 @@ const convertPluralsToICU = ( item.msgstr = ["{" + pluralizeOn + ", plural, " + pluralClauses + "}"] } -export function formatter(options: PoGettextFormatterOptions = {}) { +export function formatter( + options: PoGettextFormatterOptions = {} +): CatalogFormatter { options = { origins: true, lineNumbers: true, @@ -251,7 +253,7 @@ export function formatter(options: PoGettextFormatterOptions = {}) { catalogExtension: ".po", templateExtension: ".pot", - parse(content): CatalogType { + parse(content, ctx): CatalogType { const po = PO.parse(content) // .po plurals are numbered 0-N and need to be mapped to ICU plural classes ("one", "few", "many"...). Different @@ -263,14 +265,11 @@ export function formatter(options: PoGettextFormatterOptions = {}) { convertPluralsToICU(item, pluralForms, po.headers.Language) }) - return formatter.parse(po.toString()) + return formatter.parse(po.toString(), ctx) as CatalogType }, - serialize( - catalog: CatalogType, - ctx: { locale: string; existing: string } - ): string { - const po = PO.parse(formatter.serialize(catalog, ctx)) + serialize(catalog, ctx): string { + const po = PO.parse(formatter.serialize(catalog, ctx) as string) po.items = po.items.map((item) => { const isGeneratedId = !item.flags["explicit-id"] @@ -283,5 +282,5 @@ export function formatter(options: PoGettextFormatterOptions = {}) { return po.toString() }, - } satisfies CatalogFormatter + } } diff --git a/packages/format-po/__typetests__/index.test-d.ts b/packages/format-po/__typetests__/index.test-d.ts new file mode 100644 index 000000000..2b850dcb1 --- /dev/null +++ b/packages/format-po/__typetests__/index.test-d.ts @@ -0,0 +1,12 @@ +import { CatalogFormatter } from "@lingui/conf" +import { expectAssignable } from "tsd" +import { formatter } from "@lingui/format-po" + +expectAssignable(formatter()) +expectAssignable( + formatter({ + lineNumbers: true, + origins: true, + printLinguiId: true, + }) +) diff --git a/packages/format-po/__typetests__/tsconfig.json b/packages/format-po/__typetests__/tsconfig.json new file mode 100644 index 000000000..114e1ccd5 --- /dev/null +++ b/packages/format-po/__typetests__/tsconfig.json @@ -0,0 +1,9 @@ +{ + "compilerOptions": { + "target": "ESNext", + "moduleResolution": "Node16", + "skipLibCheck": true, + "esModuleInterop": true + }, + "paths": {} +} diff --git a/packages/format-po/package.json b/packages/format-po/package.json index 8f3efec39..0f66ba40d 100644 --- a/packages/format-po/package.json +++ b/packages/format-po/package.json @@ -46,6 +46,7 @@ }, "devDependencies": { "@lingui/jest-mocks": "workspace:^", + "tsd": "^0.28.0", "unbuild": "^1.1.2" } } diff --git a/packages/format-po/src/po.test.ts b/packages/format-po/src/po.test.ts index efbb459a7..3b6d15735 100644 --- a/packages/format-po/src/po.test.ts +++ b/packages/format-po/src/po.test.ts @@ -2,7 +2,20 @@ import fs from "fs" import path from "path" import { formatter as createFormatter } from "./po" -import { CatalogType } from "@lingui/conf" +import { CatalogFormatter, CatalogType } from "@lingui/conf" + +const defaultParseCtx: Parameters[1] = { + locale: "en", + sourceLocale: "en", + filename: "file.po", +} + +const defaultSerializeCtx: Parameters[1] = { + locale: "en", + existing: null, + filename: "file.po", + sourceLocale: "en", +} describe("pofile format", () => { jest.useFakeTimers().setSystemTime(new Date("2018-08-27T10:00Z").getTime()) @@ -65,10 +78,7 @@ describe("pofile format", () => { }, } - const pofile = format.serialize(catalog, { - locale: "en", - existing: null, - }) + const pofile = format.serialize(catalog, defaultSerializeCtx) expect(pofile).toMatchSnapshot() }) @@ -79,7 +89,7 @@ describe("pofile format", () => { .readFileSync(path.join(__dirname, "fixtures/messages.po")) .toString() - const actual = format.parse(pofile) + const actual = format.parse(pofile, defaultParseCtx) expect(actual).toMatchSnapshot() }) @@ -95,12 +105,9 @@ describe("pofile format", () => { }, } - const serialized = format.serialize(catalog, { - locale: "en", - existing: null, - }) + const serialized = format.serialize(catalog, defaultSerializeCtx) as string - const actual = format.parse(serialized) + const actual = format.parse(serialized, defaultParseCtx) expect(actual).toMatchObject(catalog) }) @@ -116,10 +123,7 @@ describe("pofile format", () => { }, } - const serialized = format.serialize(catalog, { - locale: "en", - existing: null, - }) + const serialized = format.serialize(catalog, defaultSerializeCtx) expect(serialized).toMatchSnapshot() }) @@ -137,10 +141,7 @@ describe("pofile format", () => { }, } - const serialized = format.serialize(catalog, { - locale: "en", - existing: null, - }) + const serialized = format.serialize(catalog, defaultSerializeCtx) expect(serialized).toMatchSnapshot() }) @@ -164,7 +165,7 @@ describe("pofile format", () => { msgstr "Second description joins translator comments" ` - const actual = format.parse(po) + const actual = format.parse(po, defaultParseCtx) expect(actual).toMatchSnapshot() }) @@ -188,7 +189,7 @@ describe("pofile format", () => { }, } - const actual = format.serialize(catalog, { locale: "en", existing: null }) + const actual = format.serialize(catalog, defaultSerializeCtx) const pofileOriginPrefix = "#:" expect(actual).toEqual(expect.not.stringContaining(pofileOriginPrefix)) }) @@ -212,10 +213,7 @@ describe("pofile format", () => { ], }, } - const actual = format.serialize(catalog, { - locale: "en", - existing: null, - }) + const actual = format.serialize(catalog, defaultSerializeCtx) expect(actual).toMatchInlineSnapshot(` msgid "" @@ -262,10 +260,7 @@ describe("pofile format", () => { }, } - const actual = format.serialize(catalog, { - locale: "en", - existing: null, - }) + const actual = format.serialize(catalog, defaultSerializeCtx) expect(actual).toMatchInlineSnapshot(` msgid "" diff --git a/packages/format-po/src/po.ts b/packages/format-po/src/po.ts index b38ab379d..4c7641229 100644 --- a/packages/format-po/src/po.ts +++ b/packages/format-po/src/po.ts @@ -131,7 +131,7 @@ function deserialize(items: POItem[]): CatalogType { }, {}) } -export function formatter(options: PoFormatterOptions = {}) { +export function formatter(options: PoFormatterOptions = {}): CatalogFormatter { options = { origins: true, lineNumbers: true, @@ -142,15 +142,12 @@ export function formatter(options: PoFormatterOptions = {}) { catalogExtension: ".po", templateExtension: ".pot", - parse(content: string): CatalogType { + parse(content): CatalogType { const po = PO.parse(content) return deserialize(po.items) }, - serialize( - catalog: CatalogType, - ctx: { locale: string; existing: string } - ): string { + serialize(catalog, ctx): string { let po: PO if (ctx.existing) { @@ -165,5 +162,5 @@ export function formatter(options: PoFormatterOptions = {}) { po.items = serialize(catalog, options) return po.toString() }, - } satisfies CatalogFormatter + } } diff --git a/yarn.lock b/yarn.lock index c9bce7c07..f777b02c5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2721,6 +2721,7 @@ __metadata: dependencies: "@lingui/conf": 4.0.0-next.3 papaparse: ^5.4.0 + tsd: ^0.28.0 unbuild: ^1.1.2 languageName: unknown linkType: soft @@ -2731,6 +2732,7 @@ __metadata: dependencies: "@lingui/conf": 4.0.0-next.3 ramda: ^0.28.0 + tsd: ^0.28.0 unbuild: ^1.1.2 languageName: unknown linkType: soft @@ -2747,6 +2749,7 @@ __metadata: node-gettext: ^3.0.0 plurals-cldr: ^2.0.1 pofile: ^1.1.4 + tsd: ^0.28.0 unbuild: ^1.1.2 languageName: unknown linkType: soft @@ -2760,6 +2763,7 @@ __metadata: "@lingui/jest-mocks": "workspace:^" date-fns: ^2.29.3 pofile: ^1.1.4 + tsd: ^0.28.0 unbuild: ^1.1.2 languageName: unknown linkType: soft @@ -3724,6 +3728,13 @@ __metadata: languageName: node linkType: hard +"@tsd/typescript@npm:~5.0.2": + version: 5.0.2 + resolution: "@tsd/typescript@npm:5.0.2" + checksum: ab9274c5208ec882840d3cbddd897fb14699afe2a71a6039027f60a4d1f5b37746f41a0dbc385ebef363717c5490e45f15308c0cfb023393194afaca24d66850 + languageName: node + linkType: hard + "@types/aria-query@npm:^4.2.0": version: 4.2.2 resolution: "@types/aria-query@npm:4.2.2" @@ -9143,6 +9154,18 @@ __metadata: languageName: node linkType: hard +"jest-diff@npm:^29.0.3": + version: 29.5.0 + resolution: "jest-diff@npm:29.5.0" + dependencies: + chalk: ^4.0.0 + diff-sequences: ^29.4.3 + jest-get-type: ^29.4.3 + pretty-format: ^29.5.0 + checksum: dfd0f4a299b5d127779c76b40106c37854c89c3e0785098c717d52822d6620d227f6234c3a9291df204d619e799e3654159213bf93220f79c8e92a55475a3d39 + languageName: node + linkType: hard + "jest-diff@npm:^29.4.3": version: 29.4.3 resolution: "jest-diff@npm:29.4.3" @@ -12061,6 +12084,17 @@ __metadata: languageName: node linkType: hard +"pretty-format@npm:^29.5.0": + version: 29.5.0 + resolution: "pretty-format@npm:29.5.0" + dependencies: + "@jest/schemas": ^29.4.3 + ansi-styles: ^5.0.0 + react-is: ^18.0.0 + checksum: 4065356b558e6db25b4d41a01efb386935a6c06a0c9c104ef5ce59f2f476b8210edb8b3949b386e60ada0a6dc5ebcb2e6ccddc8c64dfd1a9943c3c3a9e7eaf89 + languageName: node + linkType: hard + "proc-log@npm:^2.0.0, proc-log@npm:^2.0.1": version: 2.0.1 resolution: "proc-log@npm:2.0.1" @@ -13943,6 +13977,23 @@ __metadata: languageName: node linkType: hard +"tsd@npm:^0.28.0": + version: 0.28.0 + resolution: "tsd@npm:0.28.0" + dependencies: + "@tsd/typescript": ~5.0.2 + eslint-formatter-pretty: ^4.1.0 + globby: ^11.0.1 + jest-diff: ^29.0.3 + meow: ^9.0.0 + path-exists: ^4.0.0 + read-pkg-up: ^7.0.0 + bin: + tsd: dist/cli.js + checksum: 9dd5d58a1e568127b7e2ad6e91b2b791e81c807dfe063fa7547a756a0c3d5ca1366b19097cc6aa6d048d6b20d704469e511da5caf5db6d2b4283019187ad3130 + languageName: node + linkType: hard + "tslib@npm:^1.8.1, tslib@npm:^1.9.0": version: 1.14.1 resolution: "tslib@npm:1.14.1"