Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(extractor): support TS experimental decorators #1517

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 5 additions & 6 deletions packages/cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,12 +45,11 @@
"build/"
],
"dependencies": {
"@babel/core": "^7.20.12",
"@babel/generator": "^7.20.14",
"@babel/parser": "^7.20.15",
"@babel/plugin-syntax-jsx": "^7.18.6",
"@babel/runtime": "^7.20.13",
"@babel/types": "^7.20.7",
"@babel/core": "^7.21.0",
"@babel/generator": "^7.21.1",
"@babel/parser": "^7.21.2",
"@babel/runtime": "^7.21.0",
"@babel/types": "^7.21.2",
"@lingui/babel-plugin-extract-messages": "4.0.0-next.1",
"@lingui/conf": "4.0.0-next.1",
"@lingui/core": "4.0.0-next.1",
Expand Down
49 changes: 35 additions & 14 deletions packages/cli/src/api/catalog.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {
makeCatalog,
} from "../tests"
import { AllCatalogsType } from "./types"
import { extractFromFiles } from "./catalog/extractFromFiles"

export const fixture = (...dirs: string[]) =>
path.resolve(__dirname, path.join("fixtures", ...dirs)) +
Expand Down Expand Up @@ -165,26 +166,47 @@ describe("Catalog", () => {

describe("collect", () => {
it("should support JSX and Typescript", async () => {
const catalog = new Catalog(
{
name: "messages",
path: "locales/{locale}",
include: [fixture("collect-typescript-jsx/")],
exclude: [],
},
const messages = await extractFromFiles(
[
fixture("collect-typescript-jsx/jsx-syntax.jsx"),
fixture("collect-typescript-jsx/tsx-syntax.tsx"),
fixture("collect-typescript-jsx/macro.tsx"),
],
mockConfig()
)

const messages = await catalog.collect()
expect(messages).toBeTruthy()
expect(messages).toMatchSnapshot()
})

it("should support Flow syntax if enabled", async () => {
process.env.LINGUI_CONFIG = path.join(
__dirname,
"fixtures/collect-syntax-flow/lingui.config.js"
it("should support experimental typescript decorators under a flag", async () => {
const messages = await extractFromFiles(
[fixture("collect-typescript-jsx/tsx-experimental-decorators.tsx")],
mockConfig({
extractorParserOptions: {
tsExperimentalDecorators: true,
},
})
)

expect(messages).toBeTruthy()
expect(messages).toMatchInlineSnapshot(`
{
xDAtGP: {
context: undefined,
extractedComments: [],
message: Message,
origin: [
[
collect-typescript-jsx/tsx-experimental-decorators.tsx,
15,
],
],
},
}
`)
})

it("should support Flow syntax if enabled", async () => {
const catalog = new Catalog(
{
name: "messages",
Expand All @@ -200,7 +222,6 @@ describe("Catalog", () => {
)

const messages = await catalog.collect()
expect(messages).toBeTruthy()
expect(messages).toMatchSnapshot()
})
it("should extract messages from source files", async () => {
Expand Down
24 changes: 13 additions & 11 deletions packages/cli/src/api/extractors/babel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,22 +30,24 @@ const extractor: ExtractorType = {
async extract(filename, code, onMessageExtracted, ctx) {
const parserOptions = ctx.linguiConfig.extractorParserOptions

const parserPlugins: ParserPlugin[] = [
// https://babeljs.io/docs/en/babel-parser#latest-ecmascript-features
[
"decorators",
{
decoratorsBeforeExport: parserOptions?.decoratorsBeforeExport || true,
},
],
]
// https://babeljs.io/docs/en/babel-parser#latest-ecmascript-features
const parserPlugins: ParserPlugin[] = []

if (
[/\.ts$/, /\.mts$/, /\.cts$/, /\.tsx$/].some((r) => filename.match(r))
) {
parserPlugins.push("typescript")
} else if (parserOptions?.flow) {
parserPlugins.push("flow")
if (parserOptions.tsExperimentalDecorators) {
parserPlugins.push("decorators-legacy")
} else {
parserPlugins.push("decorators")
}
} else {
parserPlugins.push("decorators")

if (parserOptions?.flow) {
parserPlugins.push("flow")
}
}

if ([/\.jsx$/, /\.tsx$/].some((r) => filename.match(r))) {
Expand Down
10 changes: 0 additions & 10 deletions packages/cli/src/api/fixtures/collect-syntax-flow/lingui.config.js

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -5,34 +5,38 @@ const jsx = <div>Hello!</div>
@Decorator()
export class TestDecorator {
@Decorator()
prop;
prop

@Decorator()
method() {};
method() {}
}

export
@Decorator()
class TestDecoratorAfterExport {}

class A {
// classProperties
b = 1;
b = 1

// classPrivateProperties
#b = 1;
#b = 1
}

// dynamicImport
import('./guy').then(a)
import("./guy").then(a)
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Prettier change the formatting on save / before commit actions even if this files added as ignored 😬


// exportNamespaceFrom
export * as ns from "mod"

// nullishCoalescingOperator
const a = a ?? b;
const a = a ?? b

// objectRestSpread
const b = { b, ...c };
const b = { b, ...c }

// optionalChaining
const c = a?.b;
const c = a?.b

// topLevelAwait
await promise;
await promise

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { t } from "@lingui/macro"

@Decorator()
export class TestDecorator {
// supports typescript legacy decorator on parameters
constructor(@Decorator() param) {}
Comment on lines +5 to +6
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.


@Decorator()
prop

@Decorator()
method() {}
}

t`Message`
24 changes: 12 additions & 12 deletions packages/cli/src/api/fixtures/collect-typescript-jsx/tsx-syntax.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,46 +2,46 @@ const jsx = <div>Hello!</div>

// Typescript syntax
function foo(bar: string): string {
return bar;
return bar
}

const test1: string = "";
const test1: string = ""

// check parsing different syntax proposals
@Decorator()
export class TestDecorator {
@Decorator()
prop;
prop

@Decorator()
method() {};
method() {}
}

// optional chaining
const test = foo?.bar?.baz;
const test = foo?.bar?.baz

class A {
// classProperties
b = 1;
b = 1

// classPrivateProperties
#b = 1;
#b = 1
}

// dynamicImport
import('./guy').then(a)
import("./guy").then(a)

// exportNamespaceFrom
export * as ns from "mod"

// nullishCoalescingOperator
const a = a ?? b;
const a = a ?? b

// objectRestSpread
const b = { b, ...c };
const b = { b, ...c }

// optionalChaining
const c = a?.b;
const c = a?.b

// topLevelAwait
await promise;
await promise
2 changes: 1 addition & 1 deletion packages/conf/__typetests__/index.test-d.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ expectAssignable<LinguiConfig>({
},
extractorParserOptions: {
flow: false,
decoratorsBeforeExport: false,
tsExperimentalDecorators: false,
},
fallbackLocales: {} as FallbackLocales,
format: "po",
Expand Down
2 changes: 1 addition & 1 deletion packages/conf/src/__snapshots__/index.test.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,8 @@ exports[`@lingui/conf should return default config 1`] = `
minified: true,
},
extractorParserOptions: {
decoratorsBeforeExport: false,
flow: false,
tsExperimentalDecorators: false,
},
fallbackLocales: {
en-gb: en,
Expand Down
4 changes: 2 additions & 2 deletions packages/conf/src/makeConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ export const defaultConfig: LinguiConfig = {
},
extractorParserOptions: {
flow: false,
decoratorsBeforeExport: false,
tsExperimentalDecorators: false,
},
fallbackLocales: {} as FallbackLocales,
format: "po",
Expand Down Expand Up @@ -82,7 +82,7 @@ export const exampleConfig = {
),
extractorParserOptions: {
flow: false,
decoratorsBeforeExport: false,
tsExperimentalDecorators: false,
},
}

Expand Down
7 changes: 5 additions & 2 deletions packages/conf/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,9 +65,12 @@ export type LinguiConfig = {
compileNamespace?: "es" | "ts" | "cjs" | string
extractorParserOptions?: {
/**
* default true
* default false
*
* By default, standard decorators (Stage3) are applied for TS files
* Enable this if you want to use TypesScript's experimental decorators.
*/
decoratorsBeforeExport?: boolean
tsExperimentalDecorators?: boolean
/**
* Enable if you use flow. This will apply Flow syntax to js files
*/
Expand Down
7 changes: 4 additions & 3 deletions website/docs/ref/conf.md
Original file line number Diff line number Diff line change
Expand Up @@ -216,10 +216,11 @@ Specify extra options used to parse source files when messages are being extract
```ts
"extractorParserOptions": {
/**
* default true
* Use for Stage 3 decorators syntax.
* default false
* By default, standard decorators (Stage3) are applied for TS files
* Enable this if you want to use TypesScript's experimental decorators.
*/
decoratorsBeforeExport?: boolean
tsExperimentalDecorators?: boolean
/**
* default false
* Enable if you use flow. This will apply Flow syntax to files with .js, cjs, .mjs extension.
Expand Down
33 changes: 15 additions & 18 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -86,17 +86,6 @@ __metadata:
languageName: node
linkType: hard

"@babel/generator@npm:^7.20.14":
version: 7.20.14
resolution: "@babel/generator@npm:7.20.14"
dependencies:
"@babel/types": ^7.20.7
"@jridgewell/gen-mapping": ^0.3.2
jsesc: ^2.5.1
checksum: 5f6aa2d86af26e76d276923a5c34191124a119b16ee9ccc34aef654a7dec84fbd7d2daed2e6458a6a06bf87f3661deb77c9fea59b8f67faff5c90793c96d76d6
languageName: node
linkType: hard

"@babel/generator@npm:^7.20.7":
version: 7.20.7
resolution: "@babel/generator@npm:7.20.7"
Expand Down Expand Up @@ -432,7 +421,7 @@ __metadata:
languageName: node
linkType: hard

"@babel/parser@npm:7.20.15, @babel/parser@npm:^7.20.15":
"@babel/parser@npm:7.20.15":
version: 7.20.15
resolution: "@babel/parser@npm:7.20.15"
bin:
Expand Down Expand Up @@ -1486,6 +1475,15 @@ __metadata:
languageName: node
linkType: hard

"@babel/runtime@npm:^7.21.0":
version: 7.21.0
resolution: "@babel/runtime@npm:7.21.0"
dependencies:
regenerator-runtime: ^0.13.11
checksum: 7b33e25bfa9e0e1b9e8828bb61b2d32bdd46b41b07ba7cb43319ad08efc6fda8eb89445193e67d6541814627df0ca59122c0ea795e412b99c5183a0540d338ab
languageName: node
linkType: hard

"@babel/template@npm:^7.18.10, @babel/template@npm:^7.20.7, @babel/template@npm:^7.3.3":
version: 7.20.7
resolution: "@babel/template@npm:7.20.7"
Expand Down Expand Up @@ -2181,12 +2179,11 @@ __metadata:
version: 0.0.0-use.local
resolution: "@lingui/cli@workspace:packages/cli"
dependencies:
"@babel/core": ^7.20.12
"@babel/generator": ^7.20.14
"@babel/parser": ^7.20.15
"@babel/plugin-syntax-jsx": ^7.18.6
"@babel/runtime": ^7.20.13
"@babel/types": ^7.20.7
"@babel/core": ^7.21.0
"@babel/generator": ^7.21.1
"@babel/parser": ^7.21.2
"@babel/runtime": ^7.21.0
"@babel/types": ^7.21.2
"@lingui/babel-plugin-extract-messages": 4.0.0-next.1
"@lingui/conf": 4.0.0-next.1
"@lingui/core": 4.0.0-next.1
Expand Down