wip: useOptions -> defineOptions
This commit is contained in:
parent
91d990d45a
commit
1ff5960971
@ -56,7 +56,25 @@ return { color }
|
|||||||
}"
|
}"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`SFC compile <script setup> errors should allow useOptions() referencing imported binding 1`] = `
|
exports[`SFC compile <script setup> defineOptions() 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 defineOptions() referencing imported binding 1`] = `
|
||||||
"import { bar } from './bar'
|
"import { bar } from './bar'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
@ -75,7 +93,7 @@ return { bar }
|
|||||||
}"
|
}"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`SFC compile <script setup> errors should allow useOptions() referencing scope var 1`] = `
|
exports[`SFC compile <script setup> errors should allow defineOptions() referencing scope var 1`] = `
|
||||||
"export default {
|
"export default {
|
||||||
props: {
|
props: {
|
||||||
foo: {
|
foo: {
|
||||||
@ -375,40 +393,7 @@ return { a, b, c, d, x }
|
|||||||
}"
|
}"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`SFC compile <script setup> useOptions() 1`] = `
|
exports[`SFC compile <script setup> with TypeScript defineOptions w/ runtime options 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'
|
||||||
|
|
||||||
|
|
||||||
@ -425,7 +410,7 @@ return { props, emit }
|
|||||||
})"
|
})"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`SFC compile <script setup> with TypeScript useOptions w/ type / extract emits (union) 1`] = `
|
exports[`SFC compile <script setup> with TypeScript defineOptions w/ type / extract emits (union) 1`] = `
|
||||||
"import { Slots, defineComponent } from 'vue'
|
"import { Slots, defineComponent } from 'vue'
|
||||||
|
|
||||||
|
|
||||||
@ -446,7 +431,7 @@ return { emit }
|
|||||||
})"
|
})"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`SFC compile <script setup> with TypeScript useOptions w/ type / extract emits 1`] = `
|
exports[`SFC compile <script setup> with TypeScript defineOptions w/ type / extract emits 1`] = `
|
||||||
"import { Slots, defineComponent } from 'vue'
|
"import { Slots, defineComponent } from 'vue'
|
||||||
|
|
||||||
|
|
||||||
@ -467,7 +452,7 @@ return { emit }
|
|||||||
})"
|
})"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`SFC compile <script setup> with TypeScript useOptions w/ type / extract props 1`] = `
|
exports[`SFC compile <script setup> with TypeScript defineOptions w/ type / extract props 1`] = `
|
||||||
"import { defineComponent } from 'vue'
|
"import { defineComponent } from 'vue'
|
||||||
|
|
||||||
interface Test {}
|
interface Test {}
|
||||||
@ -503,6 +488,21 @@ 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('useOptions()', () => {
|
test('defineOptions()', () => {
|
||||||
const { content, bindings } = compile(`
|
const { content, bindings } = compile(`
|
||||||
<script setup>
|
<script setup>
|
||||||
import { useOptions } from 'vue'
|
import { defineOptions } from 'vue'
|
||||||
const { props, emit } = useOptions({
|
const { props, emit } = defineOptions({
|
||||||
props: {
|
props: {
|
||||||
foo: String
|
foo: String
|
||||||
},
|
},
|
||||||
@ -60,8 +60,8 @@ const bar = 1
|
|||||||
emit: 'const'
|
emit: 'const'
|
||||||
})
|
})
|
||||||
|
|
||||||
// should remove useOptions import and call
|
// should remove defineOptions import and call
|
||||||
expect(content).not.toMatch('useOptions')
|
expect(content).not.toMatch('defineOptions')
|
||||||
// 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, useOptions } from 'vue'
|
import { ref, defineOptions } 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('useOptions w/ runtime options', () => {
|
test('defineOptions w/ runtime options', () => {
|
||||||
const { content } = compile(`
|
const { content } = compile(`
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { useOptions } from 'vue'
|
import { defineOptions } from 'vue'
|
||||||
const { props, emit } = useOptions({
|
const { props, emit } = defineOptions({
|
||||||
props: { foo: String },
|
props: { foo: String },
|
||||||
emits: ['a', 'b']
|
emits: ['a', 'b']
|
||||||
})
|
})
|
||||||
@ -200,15 +200,15 @@ const { props, emit } = useOptions({
|
|||||||
setup(__props, { props, emit }) {`)
|
setup(__props, { props, emit }) {`)
|
||||||
})
|
})
|
||||||
|
|
||||||
test('useOptions w/ type / extract props', () => {
|
test('defineOptions w/ type / extract props', () => {
|
||||||
const { content, bindings } = compile(`
|
const { content, bindings } = compile(`
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { useOptions } from 'vue'
|
import { defineOptions } from 'vue'
|
||||||
interface Test {}
|
interface Test {}
|
||||||
|
|
||||||
type Alias = number[]
|
type Alias = number[]
|
||||||
|
|
||||||
useOptions<{
|
defineOptions<{
|
||||||
props: {
|
props: {
|
||||||
string: string
|
string: string
|
||||||
number: number
|
number: number
|
||||||
@ -288,11 +288,11 @@ const { props, emit } = useOptions({
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
test('useOptions w/ type / extract emits', () => {
|
test('defineOptions w/ type / extract emits', () => {
|
||||||
const { content } = compile(`
|
const { content } = compile(`
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { useOptions } from 'vue'
|
import { defineOptions } from 'vue'
|
||||||
const { emit } = useOptions<{
|
const { emit } = defineOptions<{
|
||||||
emit: (e: 'foo' | 'bar') => void
|
emit: (e: 'foo' | 'bar') => void
|
||||||
}>()
|
}>()
|
||||||
</script>
|
</script>
|
||||||
@ -302,11 +302,11 @@ const { props, emit } = useOptions({
|
|||||||
expect(content).toMatch(`emits: ["foo", "bar"] as unknown as undefined`)
|
expect(content).toMatch(`emits: ["foo", "bar"] as unknown as undefined`)
|
||||||
})
|
})
|
||||||
|
|
||||||
test('useOptions w/ type / extract emits (union)', () => {
|
test('defineOptions w/ type / extract emits (union)', () => {
|
||||||
const { content } = compile(`
|
const { content } = compile(`
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { useOptions } from 'vue'
|
import { defineOptions } from 'vue'
|
||||||
const { emit } = useOptions<{
|
const { emit } = defineOptions<{
|
||||||
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 } = useOptions({
|
|||||||
).toThrow(`ref: statements can only contain assignment expressions`)
|
).toThrow(`ref: statements can only contain assignment expressions`)
|
||||||
})
|
})
|
||||||
|
|
||||||
test('useOptions() w/ both type and non-type args', () => {
|
test('defineOptions() w/ both type and non-type args', () => {
|
||||||
expect(() => {
|
expect(() => {
|
||||||
compile(`<script setup lang="ts">
|
compile(`<script setup lang="ts">
|
||||||
import { useOptions } from 'vue'
|
import { defineOptions } from 'vue'
|
||||||
useOptions<{}>({})
|
defineOptions<{}>({})
|
||||||
</script>`)
|
</script>`)
|
||||||
}).toThrow(`cannot accept both type and non-type arguments`)
|
}).toThrow(`cannot accept both type and non-type arguments`)
|
||||||
})
|
})
|
||||||
|
|
||||||
test('useOptions() referencing local var', () => {
|
test('defineOptions() referencing local var', () => {
|
||||||
expect(() =>
|
expect(() =>
|
||||||
compile(`<script setup>
|
compile(`<script setup>
|
||||||
import { useOptions } from 'vue'
|
import { defineOptions } from 'vue'
|
||||||
const bar = 1
|
const bar = 1
|
||||||
useOptions({
|
defineOptions({
|
||||||
props: {
|
props: {
|
||||||
foo: {
|
foo: {
|
||||||
default: () => bar
|
default: () => bar
|
||||||
@ -658,24 +658,24 @@ const { props, emit } = useOptions({
|
|||||||
).toThrow(`cannot reference locally declared variables`)
|
).toThrow(`cannot reference locally declared variables`)
|
||||||
})
|
})
|
||||||
|
|
||||||
test('useOptions() referencing ref declarations', () => {
|
test('defineOptions() referencing ref declarations', () => {
|
||||||
expect(() =>
|
expect(() =>
|
||||||
compile(`<script setup>
|
compile(`<script setup>
|
||||||
import { useOptions } from 'vue'
|
import { defineOptions } from 'vue'
|
||||||
ref: bar = 1
|
ref: bar = 1
|
||||||
useOptions({
|
defineOptions({
|
||||||
props: { bar }
|
props: { bar }
|
||||||
})
|
})
|
||||||
</script>`)
|
</script>`)
|
||||||
).toThrow(`cannot reference locally declared variables`)
|
).toThrow(`cannot reference locally declared variables`)
|
||||||
})
|
})
|
||||||
|
|
||||||
test('should allow useOptions() referencing scope var', () => {
|
test('should allow defineOptions() referencing scope var', () => {
|
||||||
assertCode(
|
assertCode(
|
||||||
compile(`<script setup>
|
compile(`<script setup>
|
||||||
import { useOptions } from 'vue'
|
import { defineOptions } from 'vue'
|
||||||
const bar = 1
|
const bar = 1
|
||||||
useOptions({
|
defineOptions({
|
||||||
props: {
|
props: {
|
||||||
foo: {
|
foo: {
|
||||||
default: bar => bar + 1
|
default: bar => bar + 1
|
||||||
@ -686,12 +686,12 @@ const { props, emit } = useOptions({
|
|||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
test('should allow useOptions() referencing imported binding', () => {
|
test('should allow defineOptions() referencing imported binding', () => {
|
||||||
assertCode(
|
assertCode(
|
||||||
compile(`<script setup>
|
compile(`<script setup>
|
||||||
import { useOptions } from 'vue'
|
import { defineOptions } from 'vue'
|
||||||
import { bar } from './bar'
|
import { bar } from './bar'
|
||||||
useOptions({
|
defineOptions({
|
||||||
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 { useOptions } from 'vue'
|
import { defineOptions } from 'vue'
|
||||||
useOptions({
|
defineOptions({
|
||||||
props: {
|
props: {
|
||||||
foo: String,
|
foo: String,
|
||||||
}
|
}
|
||||||
|
@ -27,7 +27,7 @@ import { RawSourceMap } from 'source-map'
|
|||||||
import { genCssVarsCode, injectCssVarsCalls } from './genCssVars'
|
import { genCssVarsCode, injectCssVarsCalls } from './genCssVars'
|
||||||
import { compileTemplate, SFCTemplateCompileOptions } from './compileTemplate'
|
import { compileTemplate, SFCTemplateCompileOptions } from './compileTemplate'
|
||||||
|
|
||||||
const USE_OPTIONS = 'useOptions'
|
const DEFINE_OPTIONS = 'defineOptions'
|
||||||
|
|
||||||
export interface SFCScriptCompileOptions {
|
export interface SFCScriptCompileOptions {
|
||||||
/**
|
/**
|
||||||
@ -147,7 +147,18 @@ export function compileScript(
|
|||||||
let optionsArg: ObjectExpression | undefined
|
let optionsArg: ObjectExpression | undefined
|
||||||
let optionsType: TSTypeLiteral | undefined
|
let optionsType: TSTypeLiteral | undefined
|
||||||
let hasAwait = false
|
let hasAwait = false
|
||||||
|
// context types to generate
|
||||||
|
let propsType = `{}`
|
||||||
|
let emitType = `(e: string, ...args: any[]) => void`
|
||||||
|
let slotsType = `Slots`
|
||||||
|
let attrsType = `Record<string, any>`
|
||||||
|
// props/emits declared via types
|
||||||
|
const typeDeclaredProps: Record<string, PropTypeData> = {}
|
||||||
|
const typeDeclaredEmits: Set<string> = new Set()
|
||||||
|
// record declared types for runtime props type generation
|
||||||
|
const declaredTypes: Record<string, string[]> = {}
|
||||||
|
|
||||||
|
// magic-string state
|
||||||
const s = new MagicString(source)
|
const s = new MagicString(source)
|
||||||
const startOffset = scriptSetup.loc.start.offset
|
const startOffset = scriptSetup.loc.start.offset
|
||||||
const endOffset = scriptSetup.loc.end.offset
|
const endOffset = scriptSetup.loc.end.offset
|
||||||
@ -182,14 +193,14 @@ export function compileScript(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
function processUseOptions(node: Node): boolean {
|
function processDefineOptions(node: Node): boolean {
|
||||||
if (
|
if (
|
||||||
node.type === 'CallExpression' &&
|
node.type === 'CallExpression' &&
|
||||||
node.callee.type === 'Identifier' &&
|
node.callee.type === 'Identifier' &&
|
||||||
node.callee.name === USE_OPTIONS
|
node.callee.name === DEFINE_OPTIONS
|
||||||
) {
|
) {
|
||||||
if (hasOptionsCall) {
|
if (hasOptionsCall) {
|
||||||
error(`duplicate ${USE_OPTIONS}() call`, node)
|
error(`duplicate ${DEFINE_OPTIONS}() call`, node)
|
||||||
}
|
}
|
||||||
hasOptionsCall = true
|
hasOptionsCall = true
|
||||||
const optsArg = node.arguments[0]
|
const optsArg = node.arguments[0]
|
||||||
@ -197,14 +208,17 @@ export function compileScript(
|
|||||||
if (optsArg.type === 'ObjectExpression') {
|
if (optsArg.type === 'ObjectExpression') {
|
||||||
optionsArg = optsArg
|
optionsArg = optsArg
|
||||||
} else {
|
} else {
|
||||||
error(`${USE_OPTIONS}() argument must be an object literal.`, optsArg)
|
error(
|
||||||
|
`${DEFINE_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 (optionsArg) {
|
if (optionsArg) {
|
||||||
error(
|
error(
|
||||||
`${USE_OPTIONS}() cannot accept both type and non-type arguments ` +
|
`${DEFINE_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
|
||||||
)
|
)
|
||||||
@ -214,7 +228,7 @@ export function compileScript(
|
|||||||
optionsType = typeArg
|
optionsType = typeArg
|
||||||
} else {
|
} else {
|
||||||
error(
|
error(
|
||||||
`type argument passed to ${USE_OPTIONS}() must be a literal type.`,
|
`type argument passed to ${DEFINE_OPTIONS}() must be a literal type.`,
|
||||||
typeArg
|
typeArg
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -427,18 +441,7 @@ export function compileScript(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let propsType = `{}`
|
// 2. parse <script setup> and walk over top level statements
|
||||||
let emitType = `(e: string, ...args: any[]) => void`
|
|
||||||
let slotsType = `Slots`
|
|
||||||
let attrsType = `Record<string, any>`
|
|
||||||
|
|
||||||
// props/emits declared via types
|
|
||||||
const typeDeclaredProps: Record<string, PropTypeData> = {}
|
|
||||||
const typeDeclaredEmits: Set<string> = new Set()
|
|
||||||
// record declared types for runtime props type generation
|
|
||||||
const declaredTypes: Record<string, string[]> = {}
|
|
||||||
|
|
||||||
// 3. parse <script setup> and walk over top level statements
|
|
||||||
const scriptSetupAst = parse(
|
const scriptSetupAst = parse(
|
||||||
scriptSetup.content,
|
scriptSetup.content,
|
||||||
{
|
{
|
||||||
@ -512,7 +515,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 === USE_OPTIONS) {
|
if (source === 'vue' && imported === DEFINE_OPTIONS) {
|
||||||
removed++
|
removed++
|
||||||
s.remove(
|
s.remove(
|
||||||
prev ? prev.end! + startOffset : specifier.start! + startOffset,
|
prev ? prev.end! + startOffset : specifier.start! + startOffset,
|
||||||
@ -544,14 +547,14 @@ export function compileScript(
|
|||||||
|
|
||||||
if (
|
if (
|
||||||
node.type === 'ExpressionStatement' &&
|
node.type === 'ExpressionStatement' &&
|
||||||
processUseOptions(node.expression)
|
processDefineOptions(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 && processUseOptions(decl.init)) {
|
if (decl.init && processDefineOptions(decl.init)) {
|
||||||
optionsExp = scriptSetup.content.slice(decl.id.start!, decl.id.end!)
|
optionsExp = scriptSetup.content.slice(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)
|
||||||
@ -618,7 +621,7 @@ export function compileScript(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 4. Do a full walk to rewrite identifiers referencing let exports with ref
|
// 3. Do a full walk to rewrite identifiers referencing let exports with ref
|
||||||
// value access
|
// value access
|
||||||
if (enableRefSugar && Object.keys(refBindings).length) {
|
if (enableRefSugar && Object.keys(refBindings).length) {
|
||||||
for (const node of scriptSetupAst) {
|
for (const node of scriptSetupAst) {
|
||||||
@ -644,7 +647,7 @@ export function compileScript(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 5. extract runtime props/emits code from setup context type
|
// 4. extract runtime props/emits code from setup context type
|
||||||
if (optionsType) {
|
if (optionsType) {
|
||||||
for (const m of optionsType.members) {
|
for (const m of optionsType.members) {
|
||||||
if (m.type === 'TSPropertySignature' && m.key.type === 'Identifier') {
|
if (m.type === 'TSPropertySignature' && m.key.type === 'Identifier') {
|
||||||
@ -690,7 +693,7 @@ export function compileScript(
|
|||||||
walkIdentifiers(optionsArg, id => {
|
walkIdentifiers(optionsArg, id => {
|
||||||
if (setupBindings[id.name]) {
|
if (setupBindings[id.name]) {
|
||||||
error(
|
error(
|
||||||
`\`${USE_OPTIONS}()\` in <script setup> cannot reference locally ` +
|
`\`${DEFINE_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 ` +
|
||||||
@ -739,7 +742,7 @@ export function compileScript(
|
|||||||
allBindings[key] = true
|
allBindings[key] = true
|
||||||
}
|
}
|
||||||
|
|
||||||
// 9. inject `useCssVars` calls
|
// 8. inject `useCssVars` calls
|
||||||
if (hasCssVars) {
|
if (hasCssVars) {
|
||||||
helperImports.add(`useCssVars`)
|
helperImports.add(`useCssVars`)
|
||||||
for (const style of styles) {
|
for (const style of styles) {
|
||||||
@ -753,7 +756,7 @@ export function compileScript(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 10. analyze binding metadata
|
// 9. analyze binding metadata
|
||||||
if (scriptAst) {
|
if (scriptAst) {
|
||||||
Object.assign(bindingMetadata, analyzeScriptBindings(scriptAst))
|
Object.assign(bindingMetadata, analyzeScriptBindings(scriptAst))
|
||||||
}
|
}
|
||||||
@ -774,7 +777,7 @@ export function compileScript(
|
|||||||
bindingMetadata[key] = setupBindings[key]
|
bindingMetadata[key] = setupBindings[key]
|
||||||
}
|
}
|
||||||
|
|
||||||
// 11. generate return statement
|
// 10. generate return statement
|
||||||
let returned
|
let returned
|
||||||
if (options.inlineTemplate) {
|
if (options.inlineTemplate) {
|
||||||
if (sfc.template) {
|
if (sfc.template) {
|
||||||
@ -812,7 +815,7 @@ export function compileScript(
|
|||||||
}
|
}
|
||||||
s.appendRight(endOffset, `\nreturn ${returned}\n}\n\n`)
|
s.appendRight(endOffset, `\nreturn ${returned}\n}\n\n`)
|
||||||
|
|
||||||
// 12. finalize default export
|
// 11. finalize default export
|
||||||
let runtimeOptions = ``
|
let runtimeOptions = ``
|
||||||
if (optionsArg) {
|
if (optionsArg) {
|
||||||
runtimeOptions = `\n ${scriptSetup.content
|
runtimeOptions = `\n ${scriptSetup.content
|
||||||
@ -822,7 +825,6 @@ export function compileScript(
|
|||||||
runtimeOptions =
|
runtimeOptions =
|
||||||
genRuntimeProps(typeDeclaredProps) + genRuntimeEmits(typeDeclaredEmits)
|
genRuntimeProps(typeDeclaredProps) + genRuntimeEmits(typeDeclaredEmits)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isTS) {
|
if (isTS) {
|
||||||
// for TS, make sure the exported type is still valid type with
|
// for TS, make sure the exported type is still valid type with
|
||||||
// correct props information
|
// correct props information
|
||||||
@ -861,7 +863,7 @@ export function compileScript(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 13. finalize Vue helper imports
|
// 12. finalize Vue helper imports
|
||||||
// TODO account for cases where user imports a helper with the same name
|
// TODO account for cases where user imports a helper with the same name
|
||||||
// from a non-vue source
|
// from a non-vue source
|
||||||
const helpers = [...helperImports].filter(i => !userImports[i])
|
const helpers = [...helperImports].filter(i => !userImports[i])
|
||||||
@ -897,7 +899,7 @@ function walkDeclaration(
|
|||||||
init &&
|
init &&
|
||||||
init.type === 'CallExpression' &&
|
init.type === 'CallExpression' &&
|
||||||
init.callee.type === 'Identifier' &&
|
init.callee.type === 'Identifier' &&
|
||||||
init.callee.name === USE_OPTIONS
|
init.callee.name === DEFINE_OPTIONS
|
||||||
)
|
)
|
||||||
if (id.type === 'Identifier') {
|
if (id.type === 'Identifier') {
|
||||||
bindings[id.name] =
|
bindings[id.name] =
|
||||||
|
@ -1,11 +1,8 @@
|
|||||||
import { EmitFn, EmitsOptions } from '../componentEmits'
|
import { EmitFn, EmitsOptions } from './componentEmits'
|
||||||
import {
|
import { ComponentObjectPropsOptions, ExtractPropTypes } from './componentProps'
|
||||||
ComponentObjectPropsOptions,
|
import { Slots } from './componentSlots'
|
||||||
ExtractPropTypes
|
import { Directive } from './directives'
|
||||||
} from '../componentProps'
|
import { warn } from './warning'
|
||||||
import { Slots } from '../componentSlots'
|
|
||||||
import { Directive } from '../directives'
|
|
||||||
import { warn } from '../warning'
|
|
||||||
|
|
||||||
interface DefaultContext {
|
interface DefaultContext {
|
||||||
props: {}
|
props: {}
|
||||||
@ -45,7 +42,7 @@ interface Options<E extends EmitsOptions, EE extends string> {
|
|||||||
* called at runtime.
|
* called at runtime.
|
||||||
*/
|
*/
|
||||||
// overload 1: no props
|
// overload 1: no props
|
||||||
export function useOptions<
|
export function defineOptions<
|
||||||
T extends Partial<DefaultContext> = {},
|
T extends Partial<DefaultContext> = {},
|
||||||
E extends EmitsOptions = EmitsOptions,
|
E extends EmitsOptions = EmitsOptions,
|
||||||
EE extends string = string
|
EE extends string = string
|
||||||
@ -56,7 +53,7 @@ export function useOptions<
|
|||||||
): InferContext<T, {}, E>
|
): InferContext<T, {}, E>
|
||||||
|
|
||||||
// overload 2: object props
|
// overload 2: object props
|
||||||
export function useOptions<
|
export function defineOptions<
|
||||||
T extends Partial<DefaultContext> = {},
|
T extends Partial<DefaultContext> = {},
|
||||||
E extends EmitsOptions = EmitsOptions,
|
E extends EmitsOptions = EmitsOptions,
|
||||||
EE extends string = string,
|
EE extends string = string,
|
||||||
@ -69,7 +66,7 @@ export function useOptions<
|
|||||||
): InferContext<T, P, E>
|
): InferContext<T, P, E>
|
||||||
|
|
||||||
// overload 3: object props
|
// overload 3: object props
|
||||||
export function useOptions<
|
export function defineOptions<
|
||||||
T extends Partial<DefaultContext> = {},
|
T extends Partial<DefaultContext> = {},
|
||||||
E extends EmitsOptions = EmitsOptions,
|
E extends EmitsOptions = EmitsOptions,
|
||||||
EE extends string = string,
|
EE extends string = string,
|
||||||
@ -82,7 +79,7 @@ export function useOptions<
|
|||||||
): InferContext<T, P, E>
|
): InferContext<T, P, E>
|
||||||
|
|
||||||
// implementation
|
// implementation
|
||||||
export function useOptions() {
|
export function defineOptions() {
|
||||||
if (__DEV__) {
|
if (__DEV__) {
|
||||||
warn(
|
warn(
|
||||||
`defineContext() is a compiler-hint helper that is only usable inside ` +
|
`defineContext() is a compiler-hint helper that is only usable inside ` +
|
@ -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 { useOptions } from './helpers/useOptions'
|
export { defineOptions } from './apiDefineOptions'
|
||||||
|
|
||||||
// Advanced API ----------------------------------------------------------------
|
// Advanced API ----------------------------------------------------------------
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { expectType, useOptions, Slots, describe } from './index'
|
import { expectType, defineOptions, Slots, describe } from './index'
|
||||||
|
|
||||||
describe('no args', () => {
|
describe('no args', () => {
|
||||||
const { props, attrs, emit, slots } = useOptions()
|
const { props, attrs, emit, slots } = defineOptions()
|
||||||
expectType<{}>(props)
|
expectType<{}>(props)
|
||||||
expectType<Record<string, unknown>>(attrs)
|
expectType<Record<string, unknown>>(attrs)
|
||||||
expectType<(...args: any[]) => void>(emit)
|
expectType<(...args: any[]) => void>(emit)
|
||||||
@ -15,7 +15,7 @@ describe('no args', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
describe('with type arg', () => {
|
describe('with type arg', () => {
|
||||||
const { props, attrs, emit, slots } = useOptions<{
|
const { props, attrs, emit, slots } = defineOptions<{
|
||||||
props: {
|
props: {
|
||||||
foo: string
|
foo: string
|
||||||
}
|
}
|
||||||
@ -40,7 +40,7 @@ describe('with type arg', () => {
|
|||||||
|
|
||||||
// with runtime arg
|
// with runtime arg
|
||||||
describe('with runtime arg (array syntax)', () => {
|
describe('with runtime arg (array syntax)', () => {
|
||||||
const { props, emit } = useOptions({
|
const { props, emit } = defineOptions({
|
||||||
props: ['foo', 'bar'],
|
props: ['foo', 'bar'],
|
||||||
emits: ['foo', 'bar']
|
emits: ['foo', 'bar']
|
||||||
})
|
})
|
||||||
@ -59,7 +59,7 @@ describe('with runtime arg (array syntax)', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
describe('with runtime arg (object syntax)', () => {
|
describe('with runtime arg (object syntax)', () => {
|
||||||
const { props, emit } = useOptions({
|
const { props, emit } = defineOptions({
|
||||||
props: {
|
props: {
|
||||||
foo: String,
|
foo: String,
|
||||||
bar: {
|
bar: {
|
Loading…
x
Reference in New Issue
Block a user