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 `, { filename: 'FooBar.vue', }, ) expect(content).toMatch(`export default { __name: "FooBar"`) assertCode(content) }) test('do not overwrite manual name (object)', () => { const { content } = compile( ` `, { 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( ` `, { 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() }