Skip to content

Commit

Permalink
refactor(macro) split and expose internals to be used in Vue macro (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
timofei-iatsenko authored Sep 23, 2024
1 parent a9d2cb5 commit 927c319
Show file tree
Hide file tree
Showing 11 changed files with 584 additions and 435 deletions.
10 changes: 10 additions & 0 deletions packages/babel-plugin-lingui-macro/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,16 @@
"types": "./dist/macro.d.mts",
"default": "./dist/macro.mjs"
}
},
"./ast": {
"require": {
"types": "./dist/ast.d.cts",
"default": "./dist/ast.cjs"
},
"import": {
"types": "./dist/ast.d.mts",
"default": "./dist/ast.mjs"
}
}
},
"files": [
Expand Down
19 changes: 19 additions & 0 deletions packages/babel-plugin-lingui-macro/src/ast.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
export * from "./icu"
export * from "./messageDescriptorUtils"
export { JsMacroName } from "./constants"

export {
isChoiceMethod,
isLinguiIdentifier,
isI18nMethod,
isDefineMessage,
tokenizeExpression,
tokenizeChoiceComponent,
tokenizeTemplateLiteral,
tokenizeNode,
processDescriptor,
createMacroJsContext,
type MacroJsContext,
tokenizeArg,
isArgDecorator,
} from "./macroJsAst"
1 change: 1 addition & 0 deletions packages/babel-plugin-lingui-macro/src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ export enum JsMacroName {
selectOrdinal = "selectOrdinal",
msg = "msg",
defineMessage = "defineMessage",
arg = "arg",
useLingui = "useLingui",
}

Expand Down
2 changes: 1 addition & 1 deletion packages/babel-plugin-lingui-macro/src/icu.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import ICUMessageFormat, { Token } from "./icu"
import { ICUMessageFormat, Token } from "./icu"
import { Identifier } from "@babel/types"

describe("ICU MessageFormat", function () {
Expand Down
32 changes: 15 additions & 17 deletions packages/babel-plugin-lingui-macro/src/icu.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,4 @@
import {
Expression,
isJSXEmptyExpression,
JSXElement,
Node,
} from "@babel/types"
import { Expression, isJSXEmptyExpression, Node } from "@babel/types"

const metaOptions = ["id", "comment", "props"]

Expand All @@ -12,18 +7,20 @@ const escapedMetaOptionsRe = new RegExp(`^_(${metaOptions.join("|")})$`)
export type ParsedResult = {
message: string
values?: Record<string, Expression>
jsxElements?: Record<string, JSXElement>
elements?: Record<string, any> // JSXElement or ElementNode in Vue
}

export type TextToken = {
type: "text"
value: string
}

export type ArgToken = {
type: "arg"
value: Expression
name?: string

raw?: boolean
/**
* plural
* select
Expand All @@ -35,16 +32,17 @@ export type ArgToken = {
[icuChoice: string]: string | Tokens
}
}

export type ElementToken = {
type: "element"
value: JSXElement
value: any // JSXElement or ElementNode in Vue
name?: string | number
children?: Token[]
}
export type Tokens = Token | Token[]
export type Token = TextToken | ArgToken | ElementToken

export default class ICUMessageFormat {
export class ICUMessageFormat {
public fromTokens(tokens: Tokens): ParsedResult {
return (Array.isArray(tokens) ? tokens : [tokens])
.map((token) => this.processToken(token))
Expand All @@ -54,18 +52,18 @@ export default class ICUMessageFormat {
...message,
message: props.message + message.message,
values: { ...props.values, ...message.values },
jsxElements: { ...props.jsxElements, ...message.jsxElements },
elements: { ...props.elements, ...message.elements },
}),
{
message: "",
values: {},
jsxElements: {},
elements: {},
}
)
}

public processToken(token: Token): ParsedResult {
const jsxElements: ParsedResult["jsxElements"] = {}
const jsxElements: ParsedResult["elements"] = {}

if (token.type === "text") {
return {
Expand Down Expand Up @@ -101,7 +99,7 @@ export default class ICUMessageFormat {
const {
message,
values: childValues,
jsxElements: childJsxElements,
elements: childJsxElements,
} = this.fromTokens(value)

Object.assign(values, childValues)
Expand All @@ -116,11 +114,11 @@ export default class ICUMessageFormat {
return {
message: `{${token.name}, ${token.format}, ${formatOptions}}`,
values,
jsxElements,
elements: jsxElements,
}
default:
return {
message: `{${token.name}}`,
message: token.raw ? `${token.name}` : `{${token.name}}`,
values,
}
}
Expand All @@ -132,7 +130,7 @@ export default class ICUMessageFormat {
const {
message: childMessage,
values: childValues,
jsxElements: childJsxElements,
elements: childJsxElements,
} = this.fromTokens(child)

message += childMessage
Expand All @@ -144,7 +142,7 @@ export default class ICUMessageFormat {
? `<${token.name}>${message}</${token.name}>`
: `<${token.name}/>`,
values: elementValues,
jsxElements,
elements: jsxElements,
}
}

Expand Down
75 changes: 62 additions & 13 deletions packages/babel-plugin-lingui-macro/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,19 @@
import type { PluginObj, Visitor, PluginPass } from "@babel/core"
import type { PluginObj, Visitor, PluginPass, BabelFile } from "@babel/core"
import type * as babelTypes from "@babel/types"
import { Program, Identifier } from "@babel/types"
import { MacroJSX } from "./macroJsx"
import { NodePath } from "@babel/traverse"
import { MacroJs } from "./macroJs"
import {
MACRO_CORE_PACKAGE,
MACRO_REACT_PACKAGE,
MACRO_LEGACY_PACKAGE,
JsMacroName,
} from "./constants"
import {
type LinguiConfigNormalized,
getConfig as loadConfig,
} from "@lingui/conf"
import { Program, Identifier } from "@babel/types"

let config: LinguiConfigNormalized

Expand Down Expand Up @@ -47,6 +48,21 @@ function reportUnsupportedSyntax(path: NodePath, e: Error) {

type LinguiSymbol = "Trans" | "useLingui" | "i18n"

const getIdentifierPath = ((path: NodePath, node: Identifier) => {
let foundPath: NodePath

path.traverse({
Identifier: (path) => {
if (path.node === node) {
foundPath = path
path.stop()
}
},
})

return foundPath
}) as any

export default function ({
types: t,
}: {
Expand Down Expand Up @@ -103,8 +119,41 @@ export default function ({
return state.get("linguiIdentifiers")[name]
}

function isLinguiIdentifier(
path: NodePath,
node: Identifier,
macro: JsMacroName
) {
let identPath = getIdentifierPath(path, node)

if (macro === JsMacroName.useLingui) {
if (
identPath.referencesImport(
MACRO_REACT_PACKAGE,
JsMacroName.useLingui
) ||
identPath.referencesImport(MACRO_LEGACY_PACKAGE, JsMacroName.useLingui)
) {
return true
}
} else {
// useLingui might ask for identifiers which are not direct child of macro
identPath = identPath || getIdentifierPath(path.getFunctionParent(), node)

if (
identPath.referencesImport(MACRO_CORE_PACKAGE, macro) ||
identPath.referencesImport(MACRO_LEGACY_PACKAGE, macro)
) {
return true
}
}
return false
}
return {
name: "lingui-macro-plugin",
pre(file: BabelFile) {
file.hub
},
visitor: {
Program: {
enter(path, state) {
Expand Down Expand Up @@ -161,17 +210,17 @@ export default function ({
>,
state: PluginPass
) {
const macro = new MacroJs(
{ types: t },
{
stripNonEssentialProps:
process.env.NODE_ENV == "production" &&
!(state.opts as LinguiPluginOpts).extract,
i18nImportName: getSymbolIdentifier(state, "i18n").name,
useLinguiImportName: getSymbolIdentifier(state, "useLingui")
.name,
}
)
const macro = new MacroJs({
stripNonEssentialProps:
process.env.NODE_ENV == "production" &&
!(state.opts as LinguiPluginOpts).extract,
i18nImportName: getSymbolIdentifier(state, "i18n").name,
useLinguiImportName: getSymbolIdentifier(state, "useLingui")
.name,

isLinguiIdentifier: (node: Identifier, macro) =>
isLinguiIdentifier(path, node, macro),
})
let newNode: false | babelTypes.Node

try {
Expand Down
Loading

0 comments on commit 927c319

Please sign in to comment.