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(compiler-sfc): defineDirective #10519

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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html

exports[`defineProps > basic usage 2`] = `
"
export default {
setup(__props, { expose: __expose }) {
__expose();

const vTest = { created(){} }

return { vTest }
}

}"
`;

exports[`defineProps > use of multiple define micro 2`] = `
"
export default {
props: {
bar: String
},
setup(__props, { expose: __expose }) {
__expose();

const vTest = { created(){} }
const props = __props
const vFoo = { mounted(){} }

return { vTest, props, vFoo }
}

}"
`;

exports[`defineProps > use with other micro 2`] = `
"
export default {
props: {
bar: String
},
setup(__props, { expose: __expose }) {
__expose();

const vTest = { created(){} }
const props = __props

return { vTest, props }
}

}"
`;

exports[`defineProps > with typescript 2`] = `
"import { defineComponent as _defineComponent } from 'vue'

export default /*#__PURE__*/_defineComponent({
setup(__props, { expose: __expose }) {
__expose();

const vTest = { created(){} }

return { vTest }
}

})"
`;
125 changes: 125 additions & 0 deletions packages/compiler-sfc/__tests__/compileScript/defineDirective.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
import { assertCode, compileSFCScript as compile } from '../utils'

describe('defineProps', () => {
test('basic usage', () => {
const { content } = compile(`
<script setup>
const vTest = defineDirective({ created(){} })
</script>
`)
expect(content).toMatchInlineSnapshot(`
"
export default {
setup(__props, { expose: __expose }) {
__expose();

const vTest = { created(){} }

return { vTest }
}

}"
`)

assertCode(content)
expect(content).not.toMatch('defineDirective')
expect(content).toMatch('const vTest = { created(){} }')
expect(content).toMatch('return { vTest }')
})

test('with typescript', () => {
const { content } = compile(`
<script setup lang="ts">
const vTest = defineDirective({ created(){} } as { name: string })
</script>
`)
expect(content).toMatchInlineSnapshot(`
"import { defineComponent as _defineComponent } from 'vue'

export default /*#__PURE__*/_defineComponent({
setup(__props, { expose: __expose }) {
__expose();

const vTest = { created(){} }

return { vTest }
}

})"
`)

assertCode(content)
expect(content).not.toMatch('defineDirective')
expect(content).toMatch('const vTest = { created(){} }')
expect(content).toMatch('return { vTest }')
})

test('use with other micro', () => {
const { content } = compile(`
<script setup>
const vTest = defineDirective({ created(){} })
const props = defineProps({
bar: String
})
</script>
`)
expect(content).toMatchInlineSnapshot(`
"
export default {
props: {
bar: String
},
setup(__props, { expose: __expose }) {
__expose();

const vTest = { created(){} }
const props = __props

return { vTest, props }
}

}"
`)

assertCode(content)
expect(content).not.toMatch('defineDirective')
expect(content).toMatch('const vTest = { created(){} }')
expect(content).toMatch('return { vTest, props }')
})

test('use of multiple define micro', () => {
const { content } = compile(`
<script setup>
const vTest = defineDirective({ created(){} })
const props = defineProps({
bar: String
})
const vFoo = defineDirective({ mounted(){} })
</script>
`)
expect(content).toMatchInlineSnapshot(`
"
export default {
props: {
bar: String
},
setup(__props, { expose: __expose }) {
__expose();

const vTest = { created(){} }
const props = __props
const vFoo = { mounted(){} }

return { vTest, props, vFoo }
}

}"
`)

assertCode(content)
expect(content).not.toMatch('defineDirective')
expect(content).toMatch('const vTest = { created(){} }')
expect(content).toMatch('const vFoo = { mounted(){} }')
expect(content).toMatch('return { vTest, props, vFoo }')
})
})
6 changes: 4 additions & 2 deletions packages/compiler-sfc/src/compileScript.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ import { getImportedName, isCallOf, isLiteralNode } from './script/utils'
import { analyzeScriptBindings } from './script/analyzeScriptBindings'
import { isImportUsed } from './script/importUsageCheck'
import { processAwait } from './script/topLevelAwait'
import { processDefineDirective } from './script/defineDirective'

export interface SFCScriptCompileOptions {
/**
Expand Down Expand Up @@ -523,13 +524,14 @@ export function compileScript(
)
}

// defineProps / defineEmits
// defineProps / defineEmits / defineDirective
const isDefineProps = processDefineProps(ctx, init, decl.id)
const isDefineEmits =
!isDefineProps && processDefineEmits(ctx, init, decl.id)
!isDefineEmits &&
(processDefineSlots(ctx, init, decl.id) ||
processDefineModel(ctx, init, decl.id))
processDefineModel(ctx, init, decl.id) ||
processDefineDirective(ctx, init, decl.id))

if (
isDefineProps &&
Expand Down
29 changes: 29 additions & 0 deletions packages/compiler-sfc/src/script/defineDirective.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import type { ScriptCompileContext } from './context'
import type { LVal, Node } from '@babel/types'
import { isCallOf } from './utils'
import { unwrapTSNode } from '@vue/compiler-dom'

export const DEFINE_DIRECTIVE = 'defineDirective'

export function processDefineDirective(
ctx: ScriptCompileContext,
node: Node,
declId?: LVal,
) {
if (!isCallOf(node, DEFINE_DIRECTIVE)) {
return false
}
let options: Node | undefined
const arg0 = node.arguments[0] && unwrapTSNode(node.arguments[0])
options = arg0

let optionsString = options && ctx.getString(options)

ctx.s.overwrite(
ctx.startOffset! + node.start!,
ctx.startOffset! + node.end!,
optionsString,
)

return true
}
11 changes: 11 additions & 0 deletions packages/runtime-core/src/apiSetupHelpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import type {
import { warn } from './warning'
import type { SlotsType, StrictUnwrapSlotsType } from './componentSlots'
import type { Ref } from '@vue/reactivity'
import type { Directive } from './directives'

// dev only
const warnRuntimeUsage = (method: string) =>
Expand Down Expand Up @@ -479,3 +480,13 @@ export function withAsyncContext(getAwaitable: () => any) {
}
return [awaitable, () => setCurrentInstance(ctx)]
}

export function defineDirective<T = any, V = any>(
options: Directive<T, V>,
): Directive<T, V>
export function defineDirective() {
if (__DEV__) {
warnRuntimeUsage('defineDirective')
}
return null as any
}