Skip to content

Commit

Permalink
feat(macro): throw useful error message if macro used without a plugin (
Browse files Browse the repository at this point in the history
  • Loading branch information
timofei-iatsenko authored Jan 25, 2023
1 parent 04631c9 commit 7d55904
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 25 deletions.
52 changes: 30 additions & 22 deletions packages/macro/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,27 +27,41 @@ const getSymbolSource = (name: 'i18n' | 'Trans'): [source: string, identifier?:
const [i18nImportModule, i18nImportName = "i18n"] = getSymbolSource("i18n")
const [TransImportModule, TransImportName = "Trans"] = getSymbolSource("Trans")

const jsMacroTags = new Set([
'defineMessage',
'arg',
't',
'plural',
'select',
'selectOrdinal'
])

const jsxMacroTags = new Set([
'Trans',
'Plural',
'Select',
'SelectOrdinal',
])

function macro({ references, state, babel }: MacroParams) {
const jsxNodes: NodePath[] = []
const jsNodes: NodePath[] = []
let needsI18nImport = false

Object.keys(references).forEach((tagName) => {
const nodes = references[tagName]
const macroType = getMacroType(tagName)
if (macroType == null) {
throw nodes[0].buildCodeFrameError(`Unknown macro ${tagName}`)
}

if (macroType === "js") {
if (jsMacroTags.has(tagName)) {
nodes.forEach((node) => {
jsNodes.push(node.parentPath)
})
} else {
} else if(jsxMacroTags.has(tagName)) {
nodes.forEach((node) => {
// identifier.openingElement.jsxElement
jsxNodes.push(node.parentPath.parentPath)
})
} else {
throw nodes[0].buildCodeFrameError(`Unknown macro ${tagName}`)
}
})

Expand Down Expand Up @@ -131,21 +145,15 @@ const alreadyVisited = (path: NodePath) => {
}
}

function getMacroType(tagName: string): string {
switch (tagName) {
case "defineMessage":
case "arg":
case "t":
case "plural":
case "select":
case "selectOrdinal":
return "js"
case "Trans":
case "Plural":
case "Select":
case "SelectOrdinal":
return "jsx"
}
}
[...jsMacroTags, ...jsxMacroTags].forEach((name) => {
Object.defineProperty(module.exports, name, {
get() {
throw new Error(`The macro you imported from "@lingui/macro" is being executed outside the context of compilation with babel-plugin-macros. `
+ `This indicates that you don't have the babel plugin "babel-plugin-macros" configured correctly. `
+ `Please see the documentation for how to configure babel-plugin-macros properly: `
+ 'https://github.com/kentcdodds/babel-plugin-macros/blob/main/other/docs/user.md');
}
})
})

export default createMacro(macro)
26 changes: 23 additions & 3 deletions packages/macro/test/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ const testCases: Record<string, TestCase[]> = {
}

describe("macro", function () {
process.env.LINGUI_CONFIG = path.join(__dirname, "lingui.config.js")

const babelOptions: TransformOptions = {
filename: "<filename>",
configFile: false,
Expand All @@ -54,7 +56,16 @@ describe("macro", function () {

cases.forEach(
(
{ name, input, expected, filename, production, useTypescriptPreset, only, skip },
{
name,
input,
expected,
filename,
production,
useTypescriptPreset,
only,
skip,
},
index
) => {
let run = it
Expand All @@ -73,8 +84,6 @@ describe("macro", function () {
babelOptions.presets.push("@babel/preset-typescript")
}

process.env.LINGUI_CONFIG = path.join(__dirname, "lingui.config.js")

try {
if (filename) {
const inputPath = path.relative(
Expand Down Expand Up @@ -111,6 +120,17 @@ describe("macro", function () {
})
})

it("Should throw error if used without babel-macro-plugin", async () => {
await expect(
async () => {
const mod = await import("../src/index");
return (mod as unknown as typeof import('@lingui/macro')).Trans
}
).rejects.toThrow(
'The macro you imported from "@lingui/macro"'
)
})

describe.skip("validation", function () {
describe("plural/select/selectordinal", function () {
it("value is missing", function () {
Expand Down

1 comment on commit 7d55904

@vercel
Copy link

@vercel vercel bot commented on 7d55904 Jan 25, 2023

Choose a reason for hiding this comment

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

Please sign in to comment.