wip: defineContext -> useOptions
This commit is contained in:
parent
292a657861
commit
001f8ce993
@ -56,25 +56,7 @@ return { color }
|
|||||||
}"
|
}"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`SFC compile <script setup> defineContext() 1`] = `
|
exports[`SFC compile <script setup> errors should allow useOptions() referencing imported binding 1`] = `
|
||||||
"export default {
|
|
||||||
props: {
|
|
||||||
foo: String
|
|
||||||
},
|
|
||||||
emit: ['a', 'b'],
|
|
||||||
setup(__props, { props, emit }) {
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const bar = 1
|
|
||||||
|
|
||||||
return { props, emit, bar }
|
|
||||||
}
|
|
||||||
|
|
||||||
}"
|
|
||||||
`;
|
|
||||||
|
|
||||||
exports[`SFC compile <script setup> errors should allow defineContext() referencing imported binding 1`] = `
|
|
||||||
"import { bar } from './bar'
|
"import { bar } from './bar'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
@ -93,7 +75,7 @@ return { bar }
|
|||||||
}"
|
}"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`SFC compile <script setup> errors should allow defineContext() referencing scope var 1`] = `
|
exports[`SFC compile <script setup> errors should allow useOptions() referencing scope var 1`] = `
|
||||||
"export default {
|
"export default {
|
||||||
props: {
|
props: {
|
||||||
foo: {
|
foo: {
|
||||||
@ -393,7 +375,40 @@ return { a, b, c, d, x }
|
|||||||
}"
|
}"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`SFC compile <script setup> with TypeScript defineContext w/ runtime options 1`] = `
|
exports[`SFC compile <script setup> useOptions() 1`] = `
|
||||||
|
"export default {
|
||||||
|
props: {
|
||||||
|
foo: String
|
||||||
|
},
|
||||||
|
emit: ['a', 'b'],
|
||||||
|
setup(__props, { props, emit }) {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const bar = 1
|
||||||
|
|
||||||
|
return { props, emit, bar }
|
||||||
|
}
|
||||||
|
|
||||||
|
}"
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`SFC compile <script setup> with TypeScript hoist type declarations 1`] = `
|
||||||
|
"import { defineComponent } from 'vue'
|
||||||
|
export interface Foo {}
|
||||||
|
type Bar = {}
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
setup() {
|
||||||
|
|
||||||
|
|
||||||
|
return { }
|
||||||
|
}
|
||||||
|
|
||||||
|
})"
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`SFC compile <script setup> with TypeScript useOptions w/ runtime options 1`] = `
|
||||||
"import { defineComponent } from 'vue'
|
"import { defineComponent } from 'vue'
|
||||||
|
|
||||||
|
|
||||||
@ -410,7 +425,7 @@ return { props, emit }
|
|||||||
})"
|
})"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`SFC compile <script setup> with TypeScript defineContext w/ type / extract emits (union) 1`] = `
|
exports[`SFC compile <script setup> with TypeScript useOptions w/ type / extract emits (union) 1`] = `
|
||||||
"import { Slots, defineComponent } from 'vue'
|
"import { Slots, defineComponent } from 'vue'
|
||||||
|
|
||||||
|
|
||||||
@ -431,7 +446,7 @@ return { emit }
|
|||||||
})"
|
})"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`SFC compile <script setup> with TypeScript defineContext w/ type / extract emits 1`] = `
|
exports[`SFC compile <script setup> with TypeScript useOptions w/ type / extract emits 1`] = `
|
||||||
"import { Slots, defineComponent } from 'vue'
|
"import { Slots, defineComponent } from 'vue'
|
||||||
|
|
||||||
|
|
||||||
@ -452,7 +467,7 @@ return { emit }
|
|||||||
})"
|
})"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`SFC compile <script setup> with TypeScript defineContext w/ type / extract props 1`] = `
|
exports[`SFC compile <script setup> with TypeScript useOptions w/ type / extract props 1`] = `
|
||||||
"import { defineComponent } from 'vue'
|
"import { defineComponent } from 'vue'
|
||||||
|
|
||||||
interface Test {}
|
interface Test {}
|
||||||
@ -488,21 +503,6 @@ export default defineComponent({
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
return { }
|
|
||||||
}
|
|
||||||
|
|
||||||
})"
|
|
||||||
`;
|
|
||||||
|
|
||||||
exports[`SFC compile <script setup> with TypeScript hoist type declarations 1`] = `
|
|
||||||
"import { defineComponent } from 'vue'
|
|
||||||
export interface Foo {}
|
|
||||||
type Bar = {}
|
|
||||||
|
|
||||||
export default defineComponent({
|
|
||||||
setup() {
|
|
||||||
|
|
||||||
|
|
||||||
return { }
|
return { }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -36,11 +36,11 @@ describe('SFC compile <script setup>', () => {
|
|||||||
expect(content).toMatch('return { a, b, c, d, x }')
|
expect(content).toMatch('return { a, b, c, d, x }')
|
||||||
})
|
})
|
||||||
|
|
||||||
test('defineContext()', () => {
|
test('useOptions()', () => {
|
||||||
const { content, bindings } = compile(`
|
const { content, bindings } = compile(`
|
||||||
<script setup>
|
<script setup>
|
||||||
import { defineContext } from 'vue'
|
import { useOptions } from 'vue'
|
||||||
const { props, emit } = defineContext({
|
const { props, emit } = useOptions({
|
||||||
props: {
|
props: {
|
||||||
foo: String
|
foo: String
|
||||||
},
|
},
|
||||||
@ -60,8 +60,8 @@ const bar = 1
|
|||||||
emit: 'const'
|
emit: 'const'
|
||||||
})
|
})
|
||||||
|
|
||||||
// should remove defineContext import and call
|
// should remove useOptions import and call
|
||||||
expect(content).not.toMatch('defineContext')
|
expect(content).not.toMatch('useOptions')
|
||||||
// should generate correct setup signature
|
// should generate correct setup signature
|
||||||
expect(content).toMatch(`setup(__props, { props, emit }) {`)
|
expect(content).toMatch(`setup(__props, { props, emit }) {`)
|
||||||
// should include context options in default export
|
// should include context options in default export
|
||||||
@ -143,7 +143,7 @@ const bar = 1
|
|||||||
const { content } = compile(
|
const { content } = compile(
|
||||||
`
|
`
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, defineContext } from 'vue'
|
import { ref, useOptions } from 'vue'
|
||||||
import Foo from './Foo.vue'
|
import Foo from './Foo.vue'
|
||||||
import other from './util'
|
import other from './util'
|
||||||
const count = ref(0)
|
const count = ref(0)
|
||||||
@ -183,11 +183,11 @@ const bar = 1
|
|||||||
assertCode(content)
|
assertCode(content)
|
||||||
})
|
})
|
||||||
|
|
||||||
test('defineContext w/ runtime options', () => {
|
test('useOptions w/ runtime options', () => {
|
||||||
const { content } = compile(`
|
const { content } = compile(`
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { defineContext } from 'vue'
|
import { useOptions } from 'vue'
|
||||||
const { props, emit } = defineContext({
|
const { props, emit } = useOptions({
|
||||||
props: { foo: String },
|
props: { foo: String },
|
||||||
emits: ['a', 'b']
|
emits: ['a', 'b']
|
||||||
})
|
})
|
||||||
@ -200,15 +200,15 @@ const { props, emit } = defineContext({
|
|||||||
setup(__props, { props, emit }) {`)
|
setup(__props, { props, emit }) {`)
|
||||||
})
|
})
|
||||||
|
|
||||||
test('defineContext w/ type / extract props', () => {
|
test('useOptions w/ type / extract props', () => {
|
||||||
const { content, bindings } = compile(`
|
const { content, bindings } = compile(`
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { defineContext } from 'vue'
|
import { useOptions } from 'vue'
|
||||||
interface Test {}
|
interface Test {}
|
||||||
|
|
||||||
type Alias = number[]
|
type Alias = number[]
|
||||||
|
|
||||||
defineContext<{
|
useOptions<{
|
||||||
props: {
|
props: {
|
||||||
string: string
|
string: string
|
||||||
number: number
|
number: number
|
||||||
@ -288,11 +288,11 @@ const { props, emit } = defineContext({
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
test('defineContext w/ type / extract emits', () => {
|
test('useOptions w/ type / extract emits', () => {
|
||||||
const { content } = compile(`
|
const { content } = compile(`
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { defineContext } from 'vue'
|
import { useOptions } from 'vue'
|
||||||
const { emit } = defineContext<{
|
const { emit } = useOptions<{
|
||||||
emit: (e: 'foo' | 'bar') => void
|
emit: (e: 'foo' | 'bar') => void
|
||||||
}>()
|
}>()
|
||||||
</script>
|
</script>
|
||||||
@ -302,11 +302,11 @@ const { props, emit } = defineContext({
|
|||||||
expect(content).toMatch(`emits: ["foo", "bar"] as unknown as undefined`)
|
expect(content).toMatch(`emits: ["foo", "bar"] as unknown as undefined`)
|
||||||
})
|
})
|
||||||
|
|
||||||
test('defineContext w/ type / extract emits (union)', () => {
|
test('useOptions w/ type / extract emits (union)', () => {
|
||||||
const { content } = compile(`
|
const { content } = compile(`
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { defineContext } from 'vue'
|
import { useOptions } from 'vue'
|
||||||
const { emit } = defineContext<{
|
const { emit } = useOptions<{
|
||||||
emit: ((e: 'foo' | 'bar') => void) | ((e: 'baz', id: number) => void)
|
emit: ((e: 'foo' | 'bar') => void) | ((e: 'baz', id: number) => void)
|
||||||
}>()
|
}>()
|
||||||
</script>
|
</script>
|
||||||
@ -633,21 +633,21 @@ const { props, emit } = defineContext({
|
|||||||
).toThrow(`ref: statements can only contain assignment expressions`)
|
).toThrow(`ref: statements can only contain assignment expressions`)
|
||||||
})
|
})
|
||||||
|
|
||||||
test('defineContext() w/ both type and non-type args', () => {
|
test('useOptions() w/ both type and non-type args', () => {
|
||||||
expect(() => {
|
expect(() => {
|
||||||
compile(`<script setup lang="ts">
|
compile(`<script setup lang="ts">
|
||||||
import { defineContext } from 'vue'
|
import { useOptions } from 'vue'
|
||||||
defineContext<{}>({})
|
useOptions<{}>({})
|
||||||
</script>`)
|
</script>`)
|
||||||
}).toThrow(`cannot accept both type and non-type arguments`)
|
}).toThrow(`cannot accept both type and non-type arguments`)
|
||||||
})
|
})
|
||||||
|
|
||||||
test('defineContext() referencing local var', () => {
|
test('useOptions() referencing local var', () => {
|
||||||
expect(() =>
|
expect(() =>
|
||||||
compile(`<script setup>
|
compile(`<script setup>
|
||||||
import { defineContext } from 'vue'
|
import { useOptions } from 'vue'
|
||||||
const bar = 1
|
const bar = 1
|
||||||
defineContext({
|
useOptions({
|
||||||
props: {
|
props: {
|
||||||
foo: {
|
foo: {
|
||||||
default: () => bar
|
default: () => bar
|
||||||
@ -658,24 +658,24 @@ const { props, emit } = defineContext({
|
|||||||
).toThrow(`cannot reference locally declared variables`)
|
).toThrow(`cannot reference locally declared variables`)
|
||||||
})
|
})
|
||||||
|
|
||||||
test('defineContext() referencing ref declarations', () => {
|
test('useOptions() referencing ref declarations', () => {
|
||||||
expect(() =>
|
expect(() =>
|
||||||
compile(`<script setup>
|
compile(`<script setup>
|
||||||
import { defineContext } from 'vue'
|
import { useOptions } from 'vue'
|
||||||
ref: bar = 1
|
ref: bar = 1
|
||||||
defineContext({
|
useOptions({
|
||||||
props: { bar }
|
props: { bar }
|
||||||
})
|
})
|
||||||
</script>`)
|
</script>`)
|
||||||
).toThrow(`cannot reference locally declared variables`)
|
).toThrow(`cannot reference locally declared variables`)
|
||||||
})
|
})
|
||||||
|
|
||||||
test('should allow defineContext() referencing scope var', () => {
|
test('should allow useOptions() referencing scope var', () => {
|
||||||
assertCode(
|
assertCode(
|
||||||
compile(`<script setup>
|
compile(`<script setup>
|
||||||
import { defineContext } from 'vue'
|
import { useOptions } from 'vue'
|
||||||
const bar = 1
|
const bar = 1
|
||||||
defineContext({
|
useOptions({
|
||||||
props: {
|
props: {
|
||||||
foo: {
|
foo: {
|
||||||
default: bar => bar + 1
|
default: bar => bar + 1
|
||||||
@ -686,12 +686,12 @@ const { props, emit } = defineContext({
|
|||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
test('should allow defineContext() referencing imported binding', () => {
|
test('should allow useOptions() referencing imported binding', () => {
|
||||||
assertCode(
|
assertCode(
|
||||||
compile(`<script setup>
|
compile(`<script setup>
|
||||||
import { defineContext } from 'vue'
|
import { useOptions } from 'vue'
|
||||||
import { bar } from './bar'
|
import { bar } from './bar'
|
||||||
defineContext({
|
useOptions({
|
||||||
props: {
|
props: {
|
||||||
foo: {
|
foo: {
|
||||||
default: () => bar
|
default: () => bar
|
||||||
@ -901,8 +901,8 @@ describe('SFC analyze <script> bindings', () => {
|
|||||||
it('works for script setup', () => {
|
it('works for script setup', () => {
|
||||||
const { bindings } = compile(`
|
const { bindings } = compile(`
|
||||||
<script setup>
|
<script setup>
|
||||||
import { defineContext } from 'vue'
|
import { useOptions } from 'vue'
|
||||||
defineContext({
|
useOptions({
|
||||||
props: {
|
props: {
|
||||||
foo: String,
|
foo: String,
|
||||||
}
|
}
|
||||||
|
@ -28,7 +28,7 @@ import { genCssVarsCode, injectCssVarsCalls } from './genCssVars'
|
|||||||
import { compileTemplate, SFCTemplateCompileOptions } from './compileTemplate'
|
import { compileTemplate, SFCTemplateCompileOptions } from './compileTemplate'
|
||||||
import { BindingTypes } from 'packages/compiler-core/src/options'
|
import { BindingTypes } from 'packages/compiler-core/src/options'
|
||||||
|
|
||||||
const CTX_FN_NAME = 'defineContext'
|
const USE_OPTIONS = 'useOptions'
|
||||||
|
|
||||||
export interface SFCScriptCompileOptions {
|
export interface SFCScriptCompileOptions {
|
||||||
/**
|
/**
|
||||||
@ -143,10 +143,10 @@ export function compileScript(
|
|||||||
const refIdentifiers: Set<Identifier> = new Set()
|
const refIdentifiers: Set<Identifier> = new Set()
|
||||||
const enableRefSugar = options.refSugar !== false
|
const enableRefSugar = options.refSugar !== false
|
||||||
let defaultExport: Node | undefined
|
let defaultExport: Node | undefined
|
||||||
let hasContextCall = false
|
let hasOptionsCall = false
|
||||||
let setupContextExp: string | undefined
|
let optionsExp: string | undefined
|
||||||
let setupContextArg: ObjectExpression | undefined
|
let optionsArg: ObjectExpression | undefined
|
||||||
let setupContextType: TSTypeLiteral | undefined
|
let optionsType: TSTypeLiteral | undefined
|
||||||
let hasAwait = false
|
let hasAwait = false
|
||||||
|
|
||||||
const s = new MagicString(source)
|
const s = new MagicString(source)
|
||||||
@ -183,39 +183,39 @@ export function compileScript(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
function processContextCall(node: Node): boolean {
|
function processUseOptions(node: Node): boolean {
|
||||||
if (
|
if (
|
||||||
node.type === 'CallExpression' &&
|
node.type === 'CallExpression' &&
|
||||||
node.callee.type === 'Identifier' &&
|
node.callee.type === 'Identifier' &&
|
||||||
node.callee.name === CTX_FN_NAME
|
node.callee.name === USE_OPTIONS
|
||||||
) {
|
) {
|
||||||
if (hasContextCall) {
|
if (hasOptionsCall) {
|
||||||
error('duplicate defineContext() call', node)
|
error(`duplicate ${USE_OPTIONS}() call`, node)
|
||||||
}
|
}
|
||||||
hasContextCall = true
|
hasOptionsCall = true
|
||||||
const optsArg = node.arguments[0]
|
const optsArg = node.arguments[0]
|
||||||
if (optsArg) {
|
if (optsArg) {
|
||||||
if (optsArg.type === 'ObjectExpression') {
|
if (optsArg.type === 'ObjectExpression') {
|
||||||
setupContextArg = optsArg
|
optionsArg = optsArg
|
||||||
} else {
|
} else {
|
||||||
error(`${CTX_FN_NAME}() argument must be an object literal.`, optsArg)
|
error(`${USE_OPTIONS}() argument must be an object literal.`, optsArg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// context call has type parameters - infer runtime types from it
|
// context call has type parameters - infer runtime types from it
|
||||||
if (node.typeParameters) {
|
if (node.typeParameters) {
|
||||||
if (setupContextArg) {
|
if (optionsArg) {
|
||||||
error(
|
error(
|
||||||
`${CTX_FN_NAME}() cannot accept both type and non-type arguments ` +
|
`${USE_OPTIONS}() cannot accept both type and non-type arguments ` +
|
||||||
`at the same time. Use one or the other.`,
|
`at the same time. Use one or the other.`,
|
||||||
node
|
node
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
const typeArg = node.typeParameters.params[0]
|
const typeArg = node.typeParameters.params[0]
|
||||||
if (typeArg.type === 'TSTypeLiteral') {
|
if (typeArg.type === 'TSTypeLiteral') {
|
||||||
setupContextType = typeArg
|
optionsType = typeArg
|
||||||
} else {
|
} else {
|
||||||
error(
|
error(
|
||||||
`type argument passed to ${CTX_FN_NAME}() must be a literal type.`,
|
`type argument passed to ${USE_OPTIONS}() must be a literal type.`,
|
||||||
typeArg
|
typeArg
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -513,7 +513,7 @@ export function compileScript(
|
|||||||
specifier.imported.name
|
specifier.imported.name
|
||||||
const source = node.source.value
|
const source = node.source.value
|
||||||
const existing = userImports[local]
|
const existing = userImports[local]
|
||||||
if (source === 'vue' && imported === CTX_FN_NAME) {
|
if (source === 'vue' && imported === USE_OPTIONS) {
|
||||||
removed++
|
removed++
|
||||||
s.remove(
|
s.remove(
|
||||||
prev ? prev.end! + startOffset : specifier.start! + startOffset,
|
prev ? prev.end! + startOffset : specifier.start! + startOffset,
|
||||||
@ -545,18 +545,15 @@ export function compileScript(
|
|||||||
|
|
||||||
if (
|
if (
|
||||||
node.type === 'ExpressionStatement' &&
|
node.type === 'ExpressionStatement' &&
|
||||||
processContextCall(node.expression)
|
processUseOptions(node.expression)
|
||||||
) {
|
) {
|
||||||
s.remove(node.start! + startOffset, node.end! + startOffset)
|
s.remove(node.start! + startOffset, node.end! + startOffset)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (node.type === 'VariableDeclaration' && !node.declare) {
|
if (node.type === 'VariableDeclaration' && !node.declare) {
|
||||||
for (const decl of node.declarations) {
|
for (const decl of node.declarations) {
|
||||||
if (decl.init && processContextCall(decl.init)) {
|
if (decl.init && processUseOptions(decl.init)) {
|
||||||
setupContextExp = scriptSetup.content.slice(
|
optionsExp = scriptSetup.content.slice(decl.id.start!, decl.id.end!)
|
||||||
decl.id.start!,
|
|
||||||
decl.id.end!
|
|
||||||
)
|
|
||||||
if (node.declarations.length === 1) {
|
if (node.declarations.length === 1) {
|
||||||
s.remove(node.start! + startOffset, node.end! + startOffset)
|
s.remove(node.start! + startOffset, node.end! + startOffset)
|
||||||
} else {
|
} else {
|
||||||
@ -649,8 +646,8 @@ export function compileScript(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 5. extract runtime props/emits code from setup context type
|
// 5. extract runtime props/emits code from setup context type
|
||||||
if (setupContextType) {
|
if (optionsType) {
|
||||||
for (const m of setupContextType.members) {
|
for (const m of optionsType.members) {
|
||||||
if (m.type === 'TSPropertySignature' && m.key.type === 'Identifier') {
|
if (m.type === 'TSPropertySignature' && m.key.type === 'Identifier') {
|
||||||
const typeNode = m.typeAnnotation!.typeAnnotation
|
const typeNode = m.typeAnnotation!.typeAnnotation
|
||||||
const typeString = scriptSetup.content.slice(
|
const typeString = scriptSetup.content.slice(
|
||||||
@ -688,13 +685,13 @@ export function compileScript(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 5. check useSetupContext args to make sure it doesn't reference setup scope
|
// 5. check useOptions args to make sure it doesn't reference setup scope
|
||||||
// variables
|
// variables
|
||||||
if (setupContextArg) {
|
if (optionsArg) {
|
||||||
walkIdentifiers(setupContextArg, id => {
|
walkIdentifiers(optionsArg, id => {
|
||||||
if (setupBindings[id.name]) {
|
if (setupBindings[id.name]) {
|
||||||
error(
|
error(
|
||||||
`\`${CTX_FN_NAME}()\` in <script setup> cannot reference locally ` +
|
`\`${USE_OPTIONS}()\` in <script setup> cannot reference locally ` +
|
||||||
`declared variables because it will be hoisted outside of the ` +
|
`declared variables because it will be hoisted outside of the ` +
|
||||||
`setup() function. If your component options requires initialization ` +
|
`setup() function. If your component options requires initialization ` +
|
||||||
`in the module scope, use a separate normal <script> to export ` +
|
`in the module scope, use a separate normal <script> to export ` +
|
||||||
@ -725,8 +722,8 @@ export function compileScript(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 7. finalize setup argument signature.
|
// 7. finalize setup argument signature.
|
||||||
let args = setupContextExp ? `__props, ${setupContextExp}` : ``
|
let args = optionsExp ? `__props, ${optionsExp}` : ``
|
||||||
if (setupContextExp && setupContextType) {
|
if (optionsExp && optionsType) {
|
||||||
if (slotsType === 'Slots') {
|
if (slotsType === 'Slots') {
|
||||||
helperImports.add('Slots')
|
helperImports.add('Slots')
|
||||||
}
|
}
|
||||||
@ -761,13 +758,13 @@ export function compileScript(
|
|||||||
if (scriptAst) {
|
if (scriptAst) {
|
||||||
Object.assign(bindingMetadata, analyzeScriptBindings(scriptAst))
|
Object.assign(bindingMetadata, analyzeScriptBindings(scriptAst))
|
||||||
}
|
}
|
||||||
if (setupContextType) {
|
if (optionsType) {
|
||||||
for (const key in typeDeclaredProps) {
|
for (const key in typeDeclaredProps) {
|
||||||
bindingMetadata[key] = BindingTypes.PROPS
|
bindingMetadata[key] = BindingTypes.PROPS
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (setupContextArg) {
|
if (optionsArg) {
|
||||||
Object.assign(bindingMetadata, analyzeBindingsFromOptions(setupContextArg))
|
Object.assign(bindingMetadata, analyzeBindingsFromOptions(optionsArg))
|
||||||
}
|
}
|
||||||
for (const [key, { source }] of Object.entries(userImports)) {
|
for (const [key, { source }] of Object.entries(userImports)) {
|
||||||
bindingMetadata[key] = source.endsWith('.vue')
|
bindingMetadata[key] = source.endsWith('.vue')
|
||||||
@ -818,11 +815,11 @@ export function compileScript(
|
|||||||
|
|
||||||
// 12. finalize default export
|
// 12. finalize default export
|
||||||
let runtimeOptions = ``
|
let runtimeOptions = ``
|
||||||
if (setupContextArg) {
|
if (optionsArg) {
|
||||||
runtimeOptions = `\n ${scriptSetup.content
|
runtimeOptions = `\n ${scriptSetup.content
|
||||||
.slice(setupContextArg.start! + 1, setupContextArg.end! - 1)
|
.slice(optionsArg.start! + 1, optionsArg.end! - 1)
|
||||||
.trim()},`
|
.trim()},`
|
||||||
} else if (setupContextType) {
|
} else if (optionsType) {
|
||||||
runtimeOptions =
|
runtimeOptions =
|
||||||
genRuntimeProps(typeDeclaredProps) + genRuntimeEmits(typeDeclaredEmits)
|
genRuntimeProps(typeDeclaredProps) + genRuntimeEmits(typeDeclaredEmits)
|
||||||
}
|
}
|
||||||
@ -896,18 +893,18 @@ function walkDeclaration(
|
|||||||
const isConst = node.kind === 'const'
|
const isConst = node.kind === 'const'
|
||||||
// export const foo = ...
|
// export const foo = ...
|
||||||
for (const { id, init } of node.declarations) {
|
for (const { id, init } of node.declarations) {
|
||||||
const isContextCall = !!(
|
const isUseOptionsCall = !!(
|
||||||
isConst &&
|
isConst &&
|
||||||
init &&
|
init &&
|
||||||
init.type === 'CallExpression' &&
|
init.type === 'CallExpression' &&
|
||||||
init.callee.type === 'Identifier' &&
|
init.callee.type === 'Identifier' &&
|
||||||
init.callee.name === CTX_FN_NAME
|
init.callee.name === USE_OPTIONS
|
||||||
)
|
)
|
||||||
if (id.type === 'Identifier') {
|
if (id.type === 'Identifier') {
|
||||||
bindings[id.name] =
|
bindings[id.name] =
|
||||||
// if a declaration is a const literal, we can mark it so that
|
// if a declaration is a const literal, we can mark it so that
|
||||||
// the generated render fn code doesn't need to unref() it
|
// the generated render fn code doesn't need to unref() it
|
||||||
isContextCall ||
|
isUseOptionsCall ||
|
||||||
(isConst &&
|
(isConst &&
|
||||||
init!.type !== 'Identifier' && // const a = b
|
init!.type !== 'Identifier' && // const a = b
|
||||||
init!.type !== 'CallExpression' && // const a = ref()
|
init!.type !== 'CallExpression' && // const a = ref()
|
||||||
@ -915,9 +912,9 @@ function walkDeclaration(
|
|||||||
? BindingTypes.CONST
|
? BindingTypes.CONST
|
||||||
: BindingTypes.SETUP
|
: BindingTypes.SETUP
|
||||||
} else if (id.type === 'ObjectPattern') {
|
} else if (id.type === 'ObjectPattern') {
|
||||||
walkObjectPattern(id, bindings, isConst, isContextCall)
|
walkObjectPattern(id, bindings, isConst, isUseOptionsCall)
|
||||||
} else if (id.type === 'ArrayPattern') {
|
} else if (id.type === 'ArrayPattern') {
|
||||||
walkArrayPattern(id, bindings, isConst, isContextCall)
|
walkArrayPattern(id, bindings, isConst, isUseOptionsCall)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (
|
} else if (
|
||||||
@ -934,7 +931,7 @@ function walkObjectPattern(
|
|||||||
node: ObjectPattern,
|
node: ObjectPattern,
|
||||||
bindings: Record<string, BindingTypes>,
|
bindings: Record<string, BindingTypes>,
|
||||||
isConst: boolean,
|
isConst: boolean,
|
||||||
isContextCall = false
|
isUseOptionsCall = false
|
||||||
) {
|
) {
|
||||||
for (const p of node.properties) {
|
for (const p of node.properties) {
|
||||||
if (p.type === 'ObjectProperty') {
|
if (p.type === 'ObjectProperty') {
|
||||||
@ -942,11 +939,11 @@ function walkObjectPattern(
|
|||||||
if (p.key.type === 'Identifier') {
|
if (p.key.type === 'Identifier') {
|
||||||
if (p.key === p.value) {
|
if (p.key === p.value) {
|
||||||
// const { x } = ...
|
// const { x } = ...
|
||||||
bindings[p.key.name] = isContextCall
|
bindings[p.key.name] = isUseOptionsCall
|
||||||
? BindingTypes.CONST
|
? BindingTypes.CONST
|
||||||
: BindingTypes.SETUP
|
: BindingTypes.SETUP
|
||||||
} else {
|
} else {
|
||||||
walkPattern(p.value, bindings, isConst, isContextCall)
|
walkPattern(p.value, bindings, isConst, isUseOptionsCall)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -963,10 +960,10 @@ function walkArrayPattern(
|
|||||||
node: ArrayPattern,
|
node: ArrayPattern,
|
||||||
bindings: Record<string, BindingTypes>,
|
bindings: Record<string, BindingTypes>,
|
||||||
isConst: boolean,
|
isConst: boolean,
|
||||||
isContextCall = false
|
isUseOptionsCall = false
|
||||||
) {
|
) {
|
||||||
for (const e of node.elements) {
|
for (const e of node.elements) {
|
||||||
e && walkPattern(e, bindings, isConst, isContextCall)
|
e && walkPattern(e, bindings, isConst, isUseOptionsCall)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -974,10 +971,10 @@ function walkPattern(
|
|||||||
node: Node,
|
node: Node,
|
||||||
bindings: Record<string, BindingTypes>,
|
bindings: Record<string, BindingTypes>,
|
||||||
isConst: boolean,
|
isConst: boolean,
|
||||||
isContextCall = false
|
isUseOptionsCall = false
|
||||||
) {
|
) {
|
||||||
if (node.type === 'Identifier') {
|
if (node.type === 'Identifier') {
|
||||||
bindings[node.name] = isContextCall
|
bindings[node.name] = isUseOptionsCall
|
||||||
? BindingTypes.CONST
|
? BindingTypes.CONST
|
||||||
: BindingTypes.SETUP
|
: BindingTypes.SETUP
|
||||||
} else if (node.type === 'RestElement') {
|
} else if (node.type === 'RestElement') {
|
||||||
@ -991,7 +988,7 @@ function walkPattern(
|
|||||||
walkArrayPattern(node, bindings, isConst)
|
walkArrayPattern(node, bindings, isConst)
|
||||||
} else if (node.type === 'AssignmentPattern') {
|
} else if (node.type === 'AssignmentPattern') {
|
||||||
if (node.left.type === 'Identifier') {
|
if (node.left.type === 'Identifier') {
|
||||||
bindings[node.left.name] = isContextCall
|
bindings[node.left.name] = isUseOptionsCall
|
||||||
? BindingTypes.CONST
|
? BindingTypes.CONST
|
||||||
: BindingTypes.SETUP
|
: BindingTypes.SETUP
|
||||||
} else {
|
} else {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { Slots } from './componentSlots'
|
import { Slots } from '../componentSlots'
|
||||||
import { warn } from './warning'
|
import { warn } from '../warning'
|
||||||
|
|
||||||
interface DefaultContext {
|
interface DefaultContext {
|
||||||
props: Record<string, unknown>
|
props: Record<string, unknown>
|
||||||
@ -8,7 +8,13 @@ interface DefaultContext {
|
|||||||
slots: Slots
|
slots: Slots
|
||||||
}
|
}
|
||||||
|
|
||||||
export function defineContext<T extends Partial<DefaultContext> = {}>(
|
/**
|
||||||
|
* Compile-time-only helper used for declaring options and retrieving props
|
||||||
|
* and the setup context inside <script setup>.
|
||||||
|
* This is stripped away in the compiled code and should never be actually
|
||||||
|
* called at runtime.
|
||||||
|
*/
|
||||||
|
export function useOptions<T extends Partial<DefaultContext> = {}>(
|
||||||
opts?: any // TODO infer
|
opts?: any // TODO infer
|
||||||
): { [K in keyof DefaultContext]: T[K] extends {} ? T[K] : DefaultContext[K] } {
|
): { [K in keyof DefaultContext]: T[K] extends {} ? T[K] : DefaultContext[K] } {
|
||||||
if (__DEV__) {
|
if (__DEV__) {
|
@ -43,7 +43,7 @@ export { provide, inject } from './apiInject'
|
|||||||
export { nextTick } from './scheduler'
|
export { nextTick } from './scheduler'
|
||||||
export { defineComponent } from './apiDefineComponent'
|
export { defineComponent } from './apiDefineComponent'
|
||||||
export { defineAsyncComponent } from './apiAsyncComponent'
|
export { defineAsyncComponent } from './apiAsyncComponent'
|
||||||
export { defineContext } from './apiDefineContext'
|
export { useOptions } from './helpers/useOptions'
|
||||||
|
|
||||||
// Advanced API ----------------------------------------------------------------
|
// Advanced API ----------------------------------------------------------------
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user