import { describe, test, expect } from 'vitest'
import { parse as babelParse } from '@babel/parser'
import { Compiler, FervidCompileOptions } from '..'
const mockId = 'xxxxxxxx'
describe('SFC compile
`)
expect(content).toMatch(
` return {
get xx () {
return xx;
},
get aa () {
return aa;
},
set aa (v){
aa = v;
},
bb,
cc,
dd,
get x () {
return x;
},
get a () {
return a;
},
set a (v){
a = v;
},
b,
c,
d
};`,
)
// expect(bindings).toStrictEqual({
// x: BindingTypes.SETUP_MAYBE_REF,
// a: BindingTypes.SETUP_LET,
// b: BindingTypes.SETUP_CONST,
// c: BindingTypes.SETUP_CONST,
// d: BindingTypes.SETUP_CONST,
// xx: BindingTypes.SETUP_MAYBE_REF,
// aa: BindingTypes.SETUP_LET,
// bb: BindingTypes.LITERAL_CONST,
// cc: BindingTypes.SETUP_CONST,
// dd: BindingTypes.SETUP_CONST,
// })
assertCode(content)
})
// Difference with the original is that in TS `x` and `xx` may be types,
// and compiler doesn't know without looking at the usage.
// Since neither are used, they are excluded.
test('should expose top level declarations w/ ts', () => {
const { content } = compile(`
`)
expect(content).toMatch(
` return {
get aa () {
return aa;
},
set aa (v){
aa = v;
},
bb,
cc,
dd,
get a () {
return a;
},
set a (v){
a = v;
},
b,
c,
d
};`,
)
assertCode(content)
})
})
describe('SFC analyze
{{ a }}`,
{
filename: 'FooBar.vue',
},
)
expect(content).toMatch(`export default {
__name: "FooBar"`)
assertCode(content)
})
test('do not overwrite manual name (object)', () => {
const { content } = compile(
`
{{ a }}`,
{
filename: 'FooBar.vue',
},
)
expect(content).not.toMatch(`name: 'FooBar'`)
expect(content).toMatch(`name: 'Baz'`)
assertCode(content)
})
test('do not overwrite manual name (call)', () => {
const { content } = compile(
`
{{ a }}`,
{
filename: 'FooBar.vue',
},
)
expect(content).not.toMatch(`name: 'FooBar'`)
expect(content).toMatch(`name: 'Baz'`)
assertCode(content)
})
})
})
describe('SFC genDefaultAs', () => {
test('normal `,
{
genDefaultAs: '_sfc_',
},
)
expect(content).not.toMatch('export default')
expect(content).toMatch(`const _sfc_ = {\n __name: "anonymous"\n}`)
assertCode(content)
})
test('normal
`,
{
genDefaultAs: '_sfc_',
},
)
expect(content).not.toMatch('export default')
expect(content).not.toMatch('__default__')
expect(content).toMatch(`const _sfc_ = {\n __name: "anonymous"\n}`)
assertCode(content)
})
test('
`,
{
genDefaultAs: '_sfc_',
},
)
expect(content).not.toMatch('export default')
expect(content).toMatch(
// Fervid never produces `Object.assign` because it assumes code downleveling is done by a bundler
// `const _sfc_ = /*#__PURE__*/Object.assign(__default__`,
`const _sfc_ = {`,
)
assertCode(content)
})
test('`,
{
genDefaultAs: '_sfc_',
},
)
expect(content).not.toMatch('export default')
expect(content).toMatch(`const _sfc_ = {\n __name: "anonymous",\n setup`)
assertCode(content)
})
test('`,
{
genDefaultAs: '_sfc_',
},
)
expect(content).not.toMatch('export default')
// TODO https://github.com/phoenix-ru/fervid/issues/23
// expect(content).toMatch(`const _sfc_ = /*#__PURE__*/_defineComponent(`)
expect(content).toMatch(`const _sfc_ = _defineComponent({`)
assertCode(content)
})
test('
`,
{
genDefaultAs: '_sfc_',
},
)
expect(content).not.toMatch('export default')
expect(content).toMatch(
// TODO https://github.com/phoenix-ru/fervid/issues/23
// There is no need for spreading, because Fervid merges trivial objects
// `const _sfc_ = /*#__PURE__*/_defineComponent({\n ...__default__`,
`const _sfc_ = _defineComponent({\n __name:`,
)
assertCode(content)
})
// TODO implement TS-only macros
// This is tested in Rust side
// test('binding type for edge cases', () => {
// const { bindings } = compile(
// ``,
// )
// expect(bindings).toStrictEqual({
// toRef: BindingTypes.SETUP_CONST,
// props: BindingTypes.SETUP_REACTIVE_CONST,
// foo: BindingTypes.SETUP_REF,
// })
// })
// describe('parser plugins', () => {
// Compiler never throws (only during panic)
// test('import attributes', () => {
// const { content } = compile(`
//
// `)
// assertCode(content)
// expect(() =>
// compile(`
// `),
// ).toThrow()
// })
// This is not supported
// test('import attributes (user override for deprecated syntax)', () => {
// const { content } = compile(
// `
//
// `,
// {
// babelParserPlugins: [
// ['importAttributes', { deprecatedAssertSyntax: true }],
// ],
// },
// )
// assertCode(content)
// })
// })
})
// https://github.com/vuejs/core/blob/272ab9fbdcb1af0535108b9f888e80d612f9171d/packages/compiler-sfc/__tests__/utils.ts#L11-L24
function compile(src: string, options?: Partial) {
const normalizedOptions: FervidCompileOptions = {
filename: 'anonymous.vue',
id: mockId,
...options,
}
const compiler = new Compiler()
const result = compiler.compileSync(src, normalizedOptions)
if (result.errors.length) {
console.warn(result.errors[0])
}
return {
content: result.code
}
}
function assertCode(code: string) {
// parse the generated code to make sure it is valid
try {
babelParse(code, {
sourceType: 'module',
plugins: [
'typescript',
['importAttributes', { deprecatedAssertSyntax: true }],
],
})
} catch (e: any) {
console.log(code)
throw e
}
expect(code).toMatchSnapshot()
}