Skip to content

Commit

Permalink
refactor: major update with moving to eager based loading
Browse files Browse the repository at this point in the history
These changes were made to support localization
  • Loading branch information
github-actions[bot] committed Jun 1, 2023
1 parent 87c5793 commit ca12934
Show file tree
Hide file tree
Showing 7 changed files with 98 additions and 54 deletions.
5 changes: 5 additions & 0 deletions .changeset/thin-actors-run.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'vite-plugin-import-intl': major
---

Moved to eager based loading for localization support
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@
"prepare": "husky install"
},
"dependencies": {
"fast-glob": "^3.2.12",
"uuid": "^9.0.0"
"@internationalized/string-compiler": "^3.2.0",
"fast-glob": "^3.2.12"
},
"devDependencies": {
"@changesets/cli": "^2.26.1",
Expand Down
55 changes: 46 additions & 9 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 5 additions & 2 deletions src/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,17 @@ const pattern = /(.*?)import\.meta\.intl\(.*?;/g
export function plugin(): Plugin {
return {
name: 'intl-import-plugin',
transform(code, id) {
async transform(code, id) {
const matches: string[] = code.match(pattern) ?? []

if (!matches.length) {
return
}

return { code: matches.reduce((result, match) => transform({ code: result, match, id }), code) }
const transforms = matches.map((match) => transform({ match, id }))
const results = await Promise.all(transforms)

return { code: matches.reduce((result, match, index) => result.replace(match, results[index]), code) }
},
}
}
31 changes: 14 additions & 17 deletions src/transform/index.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import fg from 'fast-glob'
import fs from 'fs'
import path from 'path'
import { v4 as uuid } from 'uuid'
import { compileString } from '@internationalized/string-compiler'

type TransformConfig = { code: string; match: string; id: string }
type TransformConfig = { match: string; id: string }

export function transform({ code, match, id }: TransformConfig) {
export async function transform({ match, id }: TransformConfig) {
const [parameters] = match.match(/\((.*?)\)/gm) ?? []
const [variable] = match.match(/(.*)= /gm) ?? []

Expand All @@ -23,18 +23,15 @@ export function transform({ code, match, id }: TransformConfig) {
.filter((file) => file.endsWith('json'))
.filter((file) => fs.statSync(file).size > 0)

let importStatement = ''
let variableStatement = `\n${variable}{`

filePaths.forEach((filePath) => {
const name = path.basename(filePath, '.json')
const safeName = `_${uuid().replace(/-/g, '')}`

importStatement += `\nimport ${safeName} from '${filePath}';`
variableStatement += `\n '${name}': ${safeName},`
})

variableStatement += '\n}'

return code.replace(match, `${importStatement}${variableStatement}`)
const filesPromised = filePaths.map((filePath) => fs.promises.readFile(filePath, { encoding: 'utf8' }))
const contentsRaw = await Promise.all(filesPromised)
const contentsParsed = contentsRaw.map((content) => JSON.parse(content))

return `${variable}{${filePaths.map(
(filePath, index) =>
`'${path.basename(filePath, '.json')}': {${Object.entries(contentsParsed[index]).reduce(
(result, [key, value]) => `${result}${key}: ${typeof value === 'string' ? compileString(value) : value},`,
'',
)}}`,
)}}`
}
3 changes: 3 additions & 0 deletions test/mocks/locales.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"with_argument": "{title}"
}
47 changes: 23 additions & 24 deletions test/plugin.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,81 +12,80 @@ it('should return an object with a name and transform of type function', () => {
expect(typeof instance.transform).toEqual('function')
})

it('should return undefined on no transform matches', () => {
it('should return undefined on no transform matches', async () => {
const instance: any = plugin()
const matchedString = 'no match'

const transformed = instance.transform(matchedString, process.cwd())
const transformed = await instance.transform(matchedString, process.cwd())

expect(transformed).toEqual(undefined)
})

it('should handle multiple transforms', () => {
it('should handle multiple transforms', async () => {
const instance: any = plugin()
const string1 = "const test_1 = import.meta.intl(['*/package.json']);"
const string2 = "const test_2 = import.meta.intl(['*/tsconfig.json']);"
const string3 = "const test_3 = import.meta.intl(['*/tsconfig.json', '*/package.json']);"
const strings = `${string1}\n${string2}\n${string3}`

const transformed = instance.transform(strings, process.cwd())
const transformed = await instance.transform(strings, process.cwd())

expect(transformed.code).toEqual(expect.stringContaining('const test_1 = {'))
expect(transformed.code).toEqual(expect.stringContaining('const test_2 = {'))
expect(transformed.code).toEqual(expect.stringContaining('const test_3 = {'))
})

it('should transform files according to the file system', () => {
it('should transform files according to the file system', async () => {
const instance: any = plugin()
const matchedString = `const test = import.meta.intl(['vite-plugin-*/package.json']);`

const transformed = instance.transform(matchedString, process.cwd())
const transformed = await instance.transform(matchedString, process.cwd())

expect(transformed).toHaveProperty('code')
expect(transformed.code).toEqual(expect.stringContaining('const test = {'))
expect(transformed.code).toEqual(expect.stringContaining('package.json'))
expect(transformed.code).toEqual(expect.stringContaining('version'))
expect(transformed.code).toEqual(expect.stringContaining('}'))
})

it('should be able to read all json in a folder', () => {
it('should be able to read all json in a folder', async () => {
const instance: any = plugin()
const matchedString = `const test = import.meta.intl(['vite-plugin-*/*']);`

const transformed = instance.transform(matchedString, process.cwd())
const transformed = await instance.transform(matchedString, process.cwd())

expect(transformed).toHaveProperty('code')
expect(transformed.code).toEqual(expect.stringContaining('const test = {'))
expect(transformed.code).toEqual(expect.stringContaining('package.json'))
expect(transformed.code).toEqual(expect.stringContaining('version'))
expect(transformed.code).toEqual(expect.stringContaining('}'))
})

it('should not have conflicting import keys', () => {
it('should filter only json files', async () => {
const instance: any = plugin()
const matchedString = `const package = import.meta.intl(['vite-plugin-*/package.json']);`
const matchedString = `const package = import.meta.intl('vite-plugin-*/*');`

const transformed = instance.transform(matchedString, process.cwd())
const transformed = await instance.transform(matchedString, process.cwd())

expect(transformed).toHaveProperty('code')
expect(transformed.code).not.toEqual(expect.stringContaining('import package'))
expect(transformed.code).toEqual(expect.stringMatching(/import _.*\/package\.json';/))
expect(transformed.code).toEqual(expect.stringContaining('package.json'))
expect(transformed.code).not.toEqual(expect.stringMatching(/import _.*\/(?!.*\.json)/))
})

it('should filter only json files', () => {
it('should filter out empty files', async () => {
const instance: any = plugin()
const matchedString = `const package = import.meta.intl('vite-plugin-*/*');`
const matchedString = `const package = import.meta.intl('vite-plugin-*/**/empty.json');`

const transformed = instance.transform(matchedString, process.cwd())
const transformed = await instance.transform(matchedString, process.cwd())

expect(transformed).toHaveProperty('code')
expect(transformed.code).not.toEqual(expect.stringMatching(/import _.*\/(?!.*\.json)/))
expect(transformed.code).not.toEqual(expect.stringMatching(/import _.*\/empty\.json';/))
})

it('should filter out empty files', () => {
it('should use transform code using internationalization', async () => {
const instance: any = plugin()
const matchedString = `const package = import.meta.intl('vite-plugin-*/**/empty.json');`
const matchedString = `const package = import.meta.intl('vite-plugin-*/**/locales.json');`

const transformed = instance.transform(matchedString, process.cwd())
const transformed = await instance.transform(matchedString, process.cwd())

expect(transformed).toHaveProperty('code')
expect(transformed.code).not.toEqual(expect.stringMatching(/import _.*\/empty\.json';/))
expect(transformed.code).toEqual(expect.stringMatching(/\(args\) => `/))
expect(transformed.code).toEqual(expect.stringMatching(/args\.title/))
})

0 comments on commit ca12934

Please sign in to comment.