237 lines
5.9 KiB
JavaScript
237 lines
5.9 KiB
JavaScript
/**
|
|
* Codemod to update Lingui's useLingui() hook to use v5.
|
|
*
|
|
* Before:
|
|
* import {msg} from '@lingui/core/macro'
|
|
* import {useLingui} from '@lingui/react'
|
|
* const {_} = useLingui()
|
|
* _(msg`Lorem ipsum`)
|
|
*
|
|
* After:
|
|
* import {useLingui} from '@lingui/react/macro'
|
|
* const {t: l} = useLingui()
|
|
* l`Lorem ipsum`
|
|
*
|
|
* Usage: jscodeshift -t .jscodeshift/file/lingui-v5.js <file-path>
|
|
* Example: jscodeshift -t .jscodeshift/file/lingui-v5.js modules/bottom-sheet/src/lib/Portal.tsx
|
|
*/
|
|
|
|
/* eslint-disable */
|
|
|
|
export const parser = 'tsx'
|
|
|
|
export default function transformer(file, api) {
|
|
const j = api.jscodeshift
|
|
|
|
const root = j(file.source)
|
|
|
|
// Remove msg imports, including aliased imports
|
|
root
|
|
.find(j.ImportDeclaration)
|
|
.filter(path => path.node.source.value === '@lingui/core/macro')
|
|
.forEach(path => {
|
|
const newSpecifiers = path.node.specifiers.filter(specifier => {
|
|
if (j.ImportSpecifier.check(specifier)) {
|
|
const importedName = specifier.imported
|
|
? specifier.imported.name
|
|
: specifier.local.name
|
|
const localName = specifier.local
|
|
? specifier.local.name
|
|
: importedName
|
|
|
|
return !(
|
|
importedName === 'msg' &&
|
|
(localName === 'msg' || localName === 'msgLingui')
|
|
)
|
|
}
|
|
return true
|
|
})
|
|
|
|
if (newSpecifiers.length > 0) {
|
|
path.node.specifiers = newSpecifiers
|
|
} else {
|
|
j(path).remove()
|
|
}
|
|
})
|
|
|
|
// Update React imports
|
|
root
|
|
.find(j.ImportDeclaration)
|
|
.filter(path => path.node.source.value === '@lingui/react')
|
|
.forEach(path => {
|
|
path.node.source = j.stringLiteral('@lingui/react/macro')
|
|
})
|
|
|
|
// Replace {_} with {t: l}
|
|
root
|
|
.find(j.VariableDeclarator, {
|
|
init: {
|
|
type: 'CallExpression',
|
|
callee: {name: 'useLingui'},
|
|
},
|
|
})
|
|
.replaceWith(nodePath => {
|
|
const {node} = nodePath
|
|
for (let i = 0; i < node.id.properties.length; i++) {
|
|
if (node.id.properties[i].key.name === '_') {
|
|
node.id.properties[i].key = j.identifier('t')
|
|
node.id.properties[i].shorthand = false
|
|
node.id.properties[i].value = j.identifier('l')
|
|
}
|
|
}
|
|
return node
|
|
})
|
|
|
|
// Replace {_: _l} with {t: l}
|
|
root
|
|
.find(j.VariableDeclarator, {
|
|
init: {callee: {name: 'useLingui'}},
|
|
id: {
|
|
properties: properties =>
|
|
properties.some(p => p.key.name === '_' && p.value.name === '_l'),
|
|
},
|
|
})
|
|
.forEach(path => {
|
|
const prop = path.node.id.properties.find(
|
|
p => p.key.name === '_' && p.value.name === '_l',
|
|
)
|
|
if (prop) {
|
|
prop.key.name = 't'
|
|
prop.value.name = 'l'
|
|
}
|
|
})
|
|
|
|
// Replace _(msg``) with l``
|
|
root
|
|
.find(j.CallExpression, {
|
|
callee: {name: '_'},
|
|
arguments: [
|
|
{
|
|
type: 'TaggedTemplateExpression',
|
|
tag: {name: 'msg'},
|
|
},
|
|
],
|
|
})
|
|
.replaceWith(path => {
|
|
const quasis = path.node.arguments[0].quasi
|
|
|
|
return j.taggedTemplateExpression(j.identifier('l'), quasis)
|
|
})
|
|
|
|
// Replace _l(msgLingui``) with l``
|
|
root
|
|
.find(j.CallExpression, {
|
|
callee: {name: '_l'},
|
|
arguments: [
|
|
{
|
|
type: 'TaggedTemplateExpression',
|
|
tag: {name: 'msgLingui'},
|
|
},
|
|
],
|
|
})
|
|
.replaceWith(path => {
|
|
const quasis = path.node.arguments[0].quasi
|
|
|
|
return j.taggedTemplateExpression(j.identifier('l'), quasis)
|
|
})
|
|
|
|
// Replace _(msg()) with l()
|
|
root
|
|
.find(j.CallExpression, {
|
|
callee: {name: '_'},
|
|
arguments: [
|
|
{
|
|
type: 'CallExpression',
|
|
callee: {name: 'msg'},
|
|
},
|
|
],
|
|
})
|
|
.replaceWith(path => {
|
|
return j.callExpression(j.identifier('l'), [
|
|
path.node.arguments[0].arguments[0],
|
|
])
|
|
})
|
|
|
|
// Replace _l(msgLingui()) with l()
|
|
root
|
|
.find(j.CallExpression, {
|
|
callee: {name: '_l'},
|
|
arguments: [
|
|
{
|
|
type: 'CallExpression',
|
|
callee: {name: 'msgLingui'},
|
|
},
|
|
],
|
|
})
|
|
.replaceWith(path => {
|
|
return j.callExpression(j.identifier('l'), [
|
|
path.node.arguments[0].arguments[0],
|
|
])
|
|
})
|
|
|
|
// Replace _(plural()) with plural()
|
|
root
|
|
.find(j.CallExpression, {
|
|
callee: {
|
|
type: 'Identifier',
|
|
name: '_',
|
|
},
|
|
})
|
|
.forEach(path => {
|
|
const callExpression = path.node
|
|
if (
|
|
callExpression.arguments.length === 1 &&
|
|
callExpression.arguments[0].type === 'CallExpression'
|
|
) {
|
|
const innerCall = callExpression.arguments[0]
|
|
|
|
if (
|
|
innerCall.callee.type === 'Identifier' &&
|
|
innerCall.callee.name === 'plural'
|
|
) {
|
|
j(path).replaceWith(innerCall)
|
|
}
|
|
}
|
|
})
|
|
|
|
// Update hook dependency arrays
|
|
root
|
|
.find(j.CallExpression, {
|
|
callee: callee => {
|
|
if (
|
|
callee.type === 'Identifier' ||
|
|
callee.type === 'MemberExpression'
|
|
) {
|
|
return true
|
|
}
|
|
if (
|
|
['useCallback', 'useEffect', 'useMemo'].includes(callee.name) &&
|
|
callee.type === 'MemberExpression' &&
|
|
callee.object.type === 'Identifier' &&
|
|
callee.object.name === 'React' &&
|
|
callee.property.type === 'Identifier' &&
|
|
callee.property.name === 'useCallback'
|
|
) {
|
|
return true
|
|
}
|
|
return false
|
|
},
|
|
})
|
|
.forEach(path => {
|
|
const dependencyArray = path.node.arguments[1]
|
|
if (dependencyArray && dependencyArray.type === 'ArrayExpression') {
|
|
dependencyArray.elements = dependencyArray.elements.map(element => {
|
|
if (
|
|
element.type === 'Identifier' &&
|
|
(element.name === '_' || element.name === '_l')
|
|
) {
|
|
return j.identifier('l')
|
|
}
|
|
return element
|
|
})
|
|
}
|
|
})
|
|
|
|
return root.toSource()
|
|
}
|