diff --git a/example/assets/locales/pt-br/translations.ftl.d.ts b/example/assets/locales/pt-br/translations.ftl.d.ts index 8c0939c..088ad2f 100644 --- a/example/assets/locales/pt-br/translations.ftl.d.ts +++ b/example/assets/locales/pt-br/translations.ftl.d.ts @@ -1,12 +1,11 @@ // This file is automatically generated. // Please do not change this file! -import { ComplexPattern } from '@fluent/bundle/esm/ast' -import { FluentBundle } from '@fluent/bundle' +import { FluentBundle, FluentArgument } from '@fluent/bundle' -type Pattern = T | ComplexPattern +type Pattern = T | Parameters[0] -type Message = { +type Message = { id: T value: Pattern attributes: Record> @@ -15,7 +14,7 @@ type Message = { declare global { interface FluentBundleTyped extends FluentBundle { getMessage(id: T): Message - formatPattern(pattern: Pattern, args?: PatternArguments, errors?: Array | null): string + formatPattern: (pattern: Pattern, ...args: PatternArguments) => string } } @@ -24,10 +23,10 @@ type MessagesKey = 'hello' | 'bye' type PatternArguments = ( T extends 'hello' - ? { 'name': string | number }: + ? [{ 'name': FluentArgument }]: T extends 'how-are-you' - ? undefined: + ? []: T extends 'bye' - ? undefined + ? [] : never ) \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 0c9423d..1dd8622 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1162,10 +1162,10 @@ "minimist": "^1.2.0" } }, - "@fluent/bundle": { - "version": "0.15.1", - "resolved": "https://registry.npmjs.org/@fluent/bundle/-/bundle-0.15.1.tgz", - "integrity": "sha512-uhDGjpEwTMBNxYMSXyjXFBG5LY7dqoNatle6mnghu5lFOrf0JyblY/Y0al2GzDKFuYbtOSbJvUkxzjtYX3odkw==" + "@fluent/syntax": { + "version": "0.15.0", + "resolved": "https://registry.npmjs.org/@fluent/syntax/-/syntax-0.15.0.tgz", + "integrity": "sha512-NIObEPekXiaDDO10NQSOeylOETaI2Ns/ymKJNvgkM6FcBARS+t3NVGyLPPIl/pqHDUB9v7bWeEmuVMJQjnpNeg==" }, "@istanbuljs/load-nyc-config": { "version": "1.0.0", diff --git a/package.json b/package.json index 2c9d5ca..ba4140b 100644 --- a/package.json +++ b/package.json @@ -17,7 +17,7 @@ "test": "jest" }, "dependencies": { - "@fluent/bundle": "0.15.1", + "@fluent/syntax": "0.15.0", "chokidar": "3.4.0", "dedent-js": "1.0.1", "loader-utils": "2.0.0" diff --git a/src/build-header.js b/src/build-header.js index 7c10883..5aebeb8 100644 --- a/src/build-header.js +++ b/src/build-header.js @@ -5,12 +5,11 @@ const bannerMessage = ( ) const header = dedent` - import { ComplexPattern } from '@fluent/bundle/esm/ast' - import { FluentBundle } from '@fluent/bundle' + import { FluentBundle, FluentArgument } from '@fluent/bundle' - type Pattern = T | ComplexPattern + type Pattern = T | Parameters[0] - type Message = { + type Message = { id: T value: Pattern attributes: Record> @@ -19,7 +18,7 @@ const header = dedent` declare global { interface FluentBundleTyped extends FluentBundle { getMessage(id: T): Message - formatPattern(pattern: Pattern, args?: PatternArguments, errors?: Array | null): string + formatPattern: (pattern: Pattern, ...args: PatternArguments) => string } } ` diff --git a/src/build-type-messages-key.js b/src/build-type-messages-key.js index 47044ed..f1eaf1b 100644 --- a/src/build-type-messages-key.js +++ b/src/build-type-messages-key.js @@ -1,6 +1,9 @@ -const buildTypeMessagesKey = (resource) => { - const interfaceFields = resource - .map(message => `'${message.id}'`) +const buildTypeMessagesKey = (ast) => { + const messages = ast.body + .filter(node => node.type === 'Message') + + const interfaceFields = messages + .map(message => `'${message.id.name}'`) .join(' |\n') return `type MessagesKey = ${interfaceFields}` diff --git a/src/build-type-pattern-arguments.js b/src/build-type-pattern-arguments.js index b3a5ea3..3ad115f 100644 --- a/src/build-type-pattern-arguments.js +++ b/src/build-type-pattern-arguments.js @@ -1,39 +1,31 @@ import dedent from 'dedent-js' -const messageVariables = (message) => { - if (typeof message.value === 'string') { - return [] - } - - const variables = message.value.reduce( - (acc, current) => current.type === 'var' - ? [...acc, current.name] - : acc - , [] - ) - - return variables -} +const messageVariablesName = (message) => + message.value.elements + .filter(element => element.type === 'Placeable') + .filter(placeable => placeable.expression.type === 'VariableReference') + .map(placeable => placeable.expression.id.name) -const wrapVariables = variables => variables.map(i => `'${i}': string | number`) +const wrapVariables = variables => variables.map(i => `'${i}': FluentArgument`) const hasVariables = variables => variables.length > 0 -const buildTypePatternArguments = (resource) => { - const options = resource +const buildTypePatternArguments = (ast) => { + const messages = ast.body + const options = messages .map(message => { - const variables = messageVariables(message) + const variablesName = messageVariablesName(message) - if (hasVariables(variables)) { + if (hasVariables(variablesName)) { return dedent` - T extends '${message.id}' - ? { ${wrapVariables(messageVariables(message)).join(',')} } + T extends '${message.id.name}' + ? [{ ${wrapVariables(variablesName).join(',')} }] ` } return dedent` - T extends '${message.id}' - ? undefined + T extends '${message.id.name}' + ? [] ` }).join(':\n') diff --git a/src/index.js b/src/index.js index 371eaf7..c58da6d 100755 --- a/src/index.js +++ b/src/index.js @@ -1,15 +1,17 @@ -import { FluentResource } from '@fluent/bundle' +import { FluentParser } from '@fluent/syntax' import dedent from 'dedent-js' import buildHeader from './build-header' import buildTypeMessagesKey from './build-type-messages-key' import buildTypePatternArguments from './build-type-pattern-arguments' const buildFluentTypeModule = (content) => { - const resource = (new FluentResource(content)).body + const parser = new FluentParser({ withSpans: false }) + const ast = parser.parse(content) + const fluentTypeModule = dedent` ${buildHeader()} - ${buildTypeMessagesKey(resource)} - ${buildTypePatternArguments(resource)} + ${buildTypeMessagesKey(ast)} + ${buildTypePatternArguments(ast)} ` return fluentTypeModule diff --git a/test/index.test.js b/test/index.test.js index fe9d806..edb976b 100644 --- a/test/index.test.js +++ b/test/index.test.js @@ -14,12 +14,11 @@ test('Should match the types definitions', async () => { // This file is automatically generated. // Please do not change this file! - import { ComplexPattern } from '@fluent/bundle/esm/ast' - import { FluentBundle } from '@fluent/bundle' + import { FluentBundle, FluentArgument } from '@fluent/bundle' - type Pattern = T | ComplexPattern + type Pattern = T | Parameters[0] - type Message = { + type Message = { id: T value: Pattern attributes: Record> @@ -28,7 +27,7 @@ test('Should match the types definitions', async () => { declare global { interface FluentBundleTyped extends FluentBundle { getMessage(id: T): Message - formatPattern(pattern: Pattern, args?: PatternArguments, errors?: Array | null): string + formatPattern: (pattern: Pattern, ...args: PatternArguments) => string } } @@ -37,11 +36,11 @@ test('Should match the types definitions', async () => { 'bye' type PatternArguments = ( T extends 'hello' - ? { 'name': string | number }: + ? [{ 'name': FluentArgument }]: T extends 'how-are-you' - ? undefined: + ? []: T extends 'bye' - ? undefined + ? [] : never ) `)