Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(define-page): support babel-parser #514

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions src/core/__snapshots__/definePage.spec.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -72,3 +72,10 @@ const b = 1
</template>
"
`;

exports[`definePage > works with jsx 1`] = `
"export default {
name: 'custom',
path: '/custom',
}"
`;
6 changes: 3 additions & 3 deletions src/core/definePage.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ definePage({
})
})

it.todo('works with jsx', async () => {
it('works with jsx', async () => {
const code = `
const a = 1
definePage({
Expand All @@ -146,11 +146,11 @@ definePage({
`,
result = (await definePageTransform({
code,
id: 'src/pages/basic.vue?definePage&jsx',
id: 'src/pages/basic.jsx?definePage&jsx',
})) as Exclude<TransformResult, string>
expect(result).toBeDefined()
expect(result).toHaveProperty('code')
expect(result?.code).toMatchInlineSnapshot()
expect(result?.code).toMatchSnapshot()
})

it('throws if definePage uses a variable from the setup', async () => {
Expand Down
57 changes: 33 additions & 24 deletions src/core/definePage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,15 @@ import {
parseSFC,
MagicString,
checkInvalidScopeReference,
babelParse,
getLang,
} from '@vue-macros/common'
import type { Thenable, TransformResult } from 'unplugin'
import type {
CallExpression,
Node,
ObjectProperty,
Program,
Statement,
StringLiteral,
} from '@babel/types'
Expand All @@ -25,6 +28,25 @@ function isStringLiteral(node: Node | null | undefined): node is StringLiteral {
return node?.type === 'StringLiteral'
}

function getAst(code: string, id: string) {
let offset = 0
let ast: Program | undefined
const lang = getLang(id.split(MACRO_DEFINE_PAGE_QUERY)[0]!)
if (lang === 'vue') {
const sfc = parseSFC(code, id)
if (sfc.scriptSetup) {
ast = sfc.getSetupAst()
offset = sfc.scriptSetup.loc.start.offset
} else if (sfc.script) {
ast = sfc.getScriptAst()
offset = sfc.script.loc.start.offset
}
} else if (/[jt]sx?$/.test(lang)) {
ast = babelParse(code, lang)
}
return { ast, offset }
}

export function definePageTransform({
code,
id,
Expand All @@ -41,15 +63,10 @@ export function definePageTransform({
return isExtractingDefinePage ? 'export default {}' : undefined
}

// TODO: handle also non SFC

const sfc = parseSFC(code, id)
if (!sfc.scriptSetup) return
const { ast, offset } = getAst(code, id)
if (!ast) return

const { scriptSetup, getSetupAst } = sfc
const setupAst = getSetupAst()

const definePageNodes = (setupAst?.body || ([] as Node[]))
const definePageNodes = ((ast.body || []) as Node[])
.map((node) => {
if (node.type === 'ExpressionStatement') node = node.expression
return isCallOf(node, MACRO_DEFINE_PAGE) ? node : null
Expand All @@ -67,7 +84,6 @@ export function definePageTransform({
}

const definePageNode = definePageNodes[0]!
const setupOffset = scriptSetup.loc.start.offset

// we only want the page info
if (isExtractingDefinePage) {
Expand All @@ -82,13 +98,13 @@ export function definePageTransform({
)
}

const scriptBindings = setupAst?.body ? getIdentifiers(setupAst.body) : []
const scriptBindings = ast.body ? getIdentifiers(ast.body) : []

// this will throw if a property from the script setup is used in definePage
checkInvalidScopeReference(routeRecord, MACRO_DEFINE_PAGE, scriptBindings)

s.remove(setupOffset + routeRecord.end!, code.length)
s.remove(0, setupOffset + routeRecord.start!)
s.remove(offset + routeRecord.end!, code.length)
s.remove(0, offset + routeRecord.start!)
s.prepend(`export default `)

// find all static imports and filter out the ones that are not used
Expand Down Expand Up @@ -156,11 +172,8 @@ export function definePageTransform({

const s = new MagicString(code)

// s.removeNode(definePageNode, { offset: setupOffset })
s.remove(
setupOffset + definePageNode.start!,
setupOffset + definePageNode.end!
)
// s.removeNode(definePageNode, { offset })
s.remove(offset + definePageNode.start!, offset + definePageNode.end!)

return generateTransform(s, id)
}
Expand All @@ -172,14 +185,10 @@ export function extractDefinePageNameAndPath(
): { name?: string; path?: string } | null | undefined {
if (!sfcCode.includes(MACRO_DEFINE_PAGE)) return

const sfc = parseSFC(sfcCode, id)

if (!sfc.scriptSetup) return

const { getSetupAst } = sfc
const setupAst = getSetupAst()
const { ast } = getAst(sfcCode, id)
if (!ast) return

const definePageNodes = (setupAst?.body ?? ([] as Node[]))
const definePageNodes = ((ast.body ?? []) as Node[])
.map((node) => {
if (node.type === 'ExpressionStatement') node = node.expression
return isCallOf(node, MACRO_DEFINE_PAGE) ? node : null
Expand Down