From c016f1f98cf3cb1b125839e8e24f50ef25441bc2 Mon Sep 17 00:00:00 2001 From: patrickpircher Date: Fri, 22 Mar 2024 15:51:42 +0100 Subject: [PATCH] improve & add tests --- .../macros/src/babel/macros-babel-plugin.ts | 26 +++++++-- .../macros/tests/babel/import-sync.test.ts | 55 +++++++++++++++++++ 2 files changed, 76 insertions(+), 5 deletions(-) diff --git a/packages/macros/src/babel/macros-babel-plugin.ts b/packages/macros/src/babel/macros-babel-plugin.ts index 8920f8bcbf..7d49fb95ec 100644 --- a/packages/macros/src/babel/macros-babel-plugin.ts +++ b/packages/macros/src/babel/macros-babel-plugin.ts @@ -125,7 +125,7 @@ export default function main(context: typeof Babel): unknown { if (callee.referencesImport('@embroider/macros', 'importSync')) { let specifier = path.node.arguments[0]; if (specifier?.type !== 'StringLiteral') { - let relativePath; + let relativePath: string = ''; let property; if ( specifier.type === 'BinaryExpression' && @@ -136,9 +136,21 @@ export default function main(context: typeof Babel): unknown { property = specifier.right; } if (specifier.type === 'TemplateLiteral' && specifier.expressions[0].type === 'Identifier') { - relativePath = specifier.quasis[0].value.cooked; + relativePath = specifier.quasis[0].value.cooked!; property = specifier.expressions[0]; } + // babel might transform template form `../my-path/${id}` to '../my-path/'.concat(id) + if ( + specifier.type === 'CallExpression' && + specifier.callee.type === 'MemberExpression' && + specifier.callee.property.type === 'Identifier' && + specifier.callee.property.name === 'concat' && + specifier.callee.object.type === 'StringLiteral' && + specifier.arguments[0]?.type === 'Identifier' + ) { + relativePath = specifier.callee.object.value; + property = specifier.arguments[0]; + } if (property && relativePath && relativePath.startsWith('.')) { const resolvedPath = resolve(dirname((state as any).filename), relativePath); let entries: string[] = []; @@ -147,10 +159,14 @@ export default function main(context: typeof Babel): unknown { } const obj = t.objectExpression( entries.map(e => { - const key = e.split('.').slice(0, -1).join('.'); + let key = e.split('.')[0]; + const rest = e.split('.').slice(1, -1); + if (rest.length) { + key += `.${rest}`; + } const id = t.callExpression( state.importUtil.import(path, state.pathToOurAddon('es-compat2'), 'default', 'esc'), - [state.importUtil.import(path, join(resolvedPath, key).replace(/\\/g, '/'), '*')] + [state.importUtil.import(path, join(relativePath, key).replace(/\\/g, '/'), '*')] ); return t.objectProperty(t.stringLiteral(key), id); }) @@ -161,7 +177,7 @@ export default function main(context: typeof Babel): unknown { return; } else { throw new Error( - `importSync eager mode only supports dynamic paths which are relative, must start with a '.'` + `importSync eager mode only supports dynamic paths which are relative, must start with a '.', had ${specifier.type}` ); } } diff --git a/packages/macros/tests/babel/import-sync.test.ts b/packages/macros/tests/babel/import-sync.test.ts index 1d6b2529e9..3c01ff0cfe 100644 --- a/packages/macros/tests/babel/import-sync.test.ts +++ b/packages/macros/tests/babel/import-sync.test.ts @@ -53,5 +53,60 @@ describe('importSync', function () { `); expect(code).toMatch(/import \* as _importSync\d from "my-plugin"/); }); + test('importSync accepts template argument with dynamic part', () => { + let code = transform(` + import { importSync } from '@embroider/macros'; + function getFile(file) { + return importSync(\`../../\${file}\`).default; + } + `); + expect(code).toEqual(`import esc from "../../src/addon/es-compat2"; +import * as _importSync0 from "../../"; +import * as _importSync20 from "../../README"; +import * as _importSync30 from "../../jest.config"; +import * as _importSync40 from "../../node_modules"; +import * as _importSync50 from "../../package"; +import * as _importSync60 from "../../src"; +import * as _importSync70 from "../../tests"; +function getFile(file) { + return { + "": esc(_importSync0), + "README": esc(_importSync20), + "jest.config": esc(_importSync30), + "node_modules": esc(_importSync40), + "package": esc(_importSync50), + "src": esc(_importSync60), + "tests": esc(_importSync70) + }[file].default; +}`); + }); + + test('importSync accepts template argument with string binary expression', () => { + let code = transform(` + import { importSync } from '@embroider/macros'; + function getFile(file) { + return importSync('../../' + file).default; + } + `); + expect(code).toEqual(`import esc from "../../src/addon/es-compat2"; +import * as _importSync0 from "../../"; +import * as _importSync20 from "../../README"; +import * as _importSync30 from "../../jest.config"; +import * as _importSync40 from "../../node_modules"; +import * as _importSync50 from "../../package"; +import * as _importSync60 from "../../src"; +import * as _importSync70 from "../../tests"; +function getFile(file) { + return { + "": esc(_importSync0), + "README": esc(_importSync20), + "jest.config": esc(_importSync30), + "node_modules": esc(_importSync40), + "package": esc(_importSync50), + "src": esc(_importSync60), + "tests": esc(_importSync70) + }[file].default; +}`); + }); }); });