|
|
@@ -1,9 +1,4 @@
|
|
|
-import {
|
|
|
- type RootNode,
|
|
|
- ErrorCodes,
|
|
|
- NodeTypes,
|
|
|
- BindingTypes,
|
|
|
-} from '@vue/compiler-dom'
|
|
|
+import { ErrorCodes, NodeTypes } from '@vue/compiler-dom'
|
|
|
import {
|
|
|
type RootIRNode,
|
|
|
type CompilerOptions,
|
|
|
@@ -13,48 +8,45 @@ import {
|
|
|
transformElement,
|
|
|
IRNodeTypes,
|
|
|
compile as _compile,
|
|
|
+ generate,
|
|
|
} from '../../src'
|
|
|
|
|
|
-function parseWithVBind(
|
|
|
+function compileWithVBind(
|
|
|
template: string,
|
|
|
options: CompilerOptions = {},
|
|
|
-): RootIRNode {
|
|
|
- const ast = parse(template)
|
|
|
+): {
|
|
|
+ ir: RootIRNode
|
|
|
+ code: string
|
|
|
+} {
|
|
|
+ const ast = parse(template, { prefixIdentifiers: true, ...options })
|
|
|
const ir = transform(ast, {
|
|
|
nodeTransforms: [transformElement],
|
|
|
directiveTransforms: {
|
|
|
bind: transformVBind,
|
|
|
},
|
|
|
- ...options,
|
|
|
- })
|
|
|
- return ir
|
|
|
-}
|
|
|
-
|
|
|
-function compile(template: string | RootNode, options: CompilerOptions = {}) {
|
|
|
- let { code } = _compile(template, {
|
|
|
- ...options,
|
|
|
- mode: 'module',
|
|
|
prefixIdentifiers: true,
|
|
|
+ ...options,
|
|
|
})
|
|
|
- return code
|
|
|
+ const { code } = generate(ir, { prefixIdentifiers: true, ...options })
|
|
|
+ return { ir, code }
|
|
|
}
|
|
|
|
|
|
-describe('compiler: transform v-bind', () => {
|
|
|
+describe('compiler v-bind', () => {
|
|
|
test('basic', () => {
|
|
|
- const node = parseWithVBind(`<div v-bind:id="id"/>`)
|
|
|
+ const { ir, code } = compileWithVBind(`<div v-bind:id="id"/>`)
|
|
|
|
|
|
- expect(node.dynamic.children[0]).toMatchObject({
|
|
|
+ expect(ir.dynamic.children[0]).toMatchObject({
|
|
|
id: 1,
|
|
|
referenced: true,
|
|
|
})
|
|
|
- expect(node.template[0]).toMatchObject({
|
|
|
+ expect(ir.template[0]).toMatchObject({
|
|
|
type: IRNodeTypes.TEMPLATE_FACTORY,
|
|
|
template: '<div></div>',
|
|
|
})
|
|
|
- expect(node.effect).lengthOf(1)
|
|
|
- expect(node.effect[0].expressions).lengthOf(1)
|
|
|
- expect(node.effect[0].operations).lengthOf(1)
|
|
|
- expect(node.effect[0]).toMatchObject({
|
|
|
+ expect(ir.effect).lengthOf(1)
|
|
|
+ expect(ir.effect[0].expressions).lengthOf(1)
|
|
|
+ expect(ir.effect[0].operations).lengthOf(1)
|
|
|
+ expect(ir.effect[0]).toMatchObject({
|
|
|
expressions: [
|
|
|
{
|
|
|
type: NodeTypes.SIMPLE_EXPRESSION,
|
|
|
@@ -89,12 +81,15 @@ describe('compiler: transform v-bind', () => {
|
|
|
},
|
|
|
],
|
|
|
})
|
|
|
+
|
|
|
+ expect(code).matchSnapshot()
|
|
|
+ expect(code).contains('_setAttr(n1, "id", undefined, _ctx.id)')
|
|
|
})
|
|
|
|
|
|
test('no expression', () => {
|
|
|
- const node = parseWithVBind(`<div v-bind:id />`)
|
|
|
+ const { ir, code } = compileWithVBind(`<div v-bind:id />`)
|
|
|
|
|
|
- expect(node.effect[0].operations[0]).toMatchObject({
|
|
|
+ expect(ir.effect[0].operations[0]).toMatchObject({
|
|
|
type: IRNodeTypes.SET_PROP,
|
|
|
key: {
|
|
|
content: `id`,
|
|
|
@@ -113,27 +108,35 @@ describe('compiler: transform v-bind', () => {
|
|
|
},
|
|
|
},
|
|
|
})
|
|
|
+
|
|
|
+ expect(code).matchSnapshot()
|
|
|
+ expect(code).contains('_setAttr(n1, "id", undefined, _ctx.id)')
|
|
|
})
|
|
|
|
|
|
test('no expression (shorthand)', () => {
|
|
|
- const node = parseWithVBind(`<div :id />`)
|
|
|
+ const { ir, code } = compileWithVBind(`<div :camel-case />`)
|
|
|
|
|
|
- expect(node.effect[0].operations[0]).toMatchObject({
|
|
|
+ expect(ir.effect[0].operations[0]).toMatchObject({
|
|
|
type: IRNodeTypes.SET_PROP,
|
|
|
key: {
|
|
|
- content: `id`,
|
|
|
+ content: `camel-case`,
|
|
|
isStatic: true,
|
|
|
},
|
|
|
value: {
|
|
|
- content: `id`,
|
|
|
+ content: `camelCase`,
|
|
|
isStatic: false,
|
|
|
},
|
|
|
})
|
|
|
+
|
|
|
+ expect(code).matchSnapshot()
|
|
|
+ expect(code).contains(
|
|
|
+ '_setAttr(n1, "camel-case", undefined, _ctx.camelCase)',
|
|
|
+ )
|
|
|
})
|
|
|
|
|
|
test('dynamic arg', () => {
|
|
|
- const node = parseWithVBind(`<div v-bind:[id]="id"/>`)
|
|
|
- expect(node.effect[0].operations[0]).toMatchObject({
|
|
|
+ const { ir, code } = compileWithVBind(`<div v-bind:[id]="id"/>`)
|
|
|
+ expect(ir.effect[0].operations[0]).toMatchObject({
|
|
|
type: IRNodeTypes.SET_PROP,
|
|
|
element: 1,
|
|
|
key: {
|
|
|
@@ -147,11 +150,17 @@ describe('compiler: transform v-bind', () => {
|
|
|
isStatic: false,
|
|
|
},
|
|
|
})
|
|
|
+
|
|
|
+ expect(code).matchSnapshot()
|
|
|
+ expect(code).contains('_setAttr(n1, _ctx.id, undefined, _ctx.id)')
|
|
|
})
|
|
|
|
|
|
test('should error if empty expression', () => {
|
|
|
const onError = vi.fn()
|
|
|
- const node = parseWithVBind(`<div v-bind:arg="" />`, { onError })
|
|
|
+ const { ir, code } = compileWithVBind(`<div v-bind:arg="" />`, {
|
|
|
+ onError,
|
|
|
+ })
|
|
|
+
|
|
|
expect(onError.mock.calls[0][0]).toMatchObject({
|
|
|
code: ErrorCodes.X_V_BIND_NO_EXPRESSION,
|
|
|
loc: {
|
|
|
@@ -159,15 +168,19 @@ describe('compiler: transform v-bind', () => {
|
|
|
end: { line: 1, column: 19 },
|
|
|
},
|
|
|
})
|
|
|
- expect(node.template[0]).toMatchObject({
|
|
|
+ expect(ir.template[0]).toMatchObject({
|
|
|
type: IRNodeTypes.TEMPLATE_FACTORY,
|
|
|
template: '<div arg=""></div>',
|
|
|
})
|
|
|
+
|
|
|
+ expect(code).matchSnapshot()
|
|
|
+ expect(code).contains(JSON.stringify('<div arg=""></div>'))
|
|
|
})
|
|
|
|
|
|
test('.camel modifier', () => {
|
|
|
- const node = parseWithVBind(`<div v-bind:foo-bar.camel="id"/>`)
|
|
|
- expect(node.effect[0].operations[0]).toMatchObject({
|
|
|
+ const { ir, code } = compileWithVBind(`<div v-bind:foo-bar.camel="id"/>`)
|
|
|
+
|
|
|
+ expect(ir.effect[0].operations[0]).toMatchObject({
|
|
|
key: {
|
|
|
content: `fooBar`,
|
|
|
isStatic: true,
|
|
|
@@ -177,11 +190,15 @@ describe('compiler: transform v-bind', () => {
|
|
|
isStatic: false,
|
|
|
},
|
|
|
})
|
|
|
+
|
|
|
+ expect(code).matchSnapshot()
|
|
|
+ expect(code).contains('_setAttr(n1, "fooBar", undefined, _ctx.id)')
|
|
|
})
|
|
|
|
|
|
test('.camel modifier w/ no expression', () => {
|
|
|
- const node = parseWithVBind(`<div v-bind:foo-bar.camel />`)
|
|
|
- expect(node.effect[0].operations[0]).toMatchObject({
|
|
|
+ const { ir, code } = compileWithVBind(`<div v-bind:foo-bar.camel />`)
|
|
|
+
|
|
|
+ expect(ir.effect[0].operations[0]).toMatchObject({
|
|
|
key: {
|
|
|
content: `fooBar`,
|
|
|
isStatic: true,
|
|
|
@@ -191,11 +208,16 @@ describe('compiler: transform v-bind', () => {
|
|
|
isStatic: false,
|
|
|
},
|
|
|
})
|
|
|
+
|
|
|
+ expect(code).matchSnapshot()
|
|
|
+ expect(code).contains('effect')
|
|
|
+ expect(code).contains('_setAttr(n1, "fooBar", undefined, _ctx.fooBar)')
|
|
|
})
|
|
|
|
|
|
test('.camel modifier w/ dynamic arg', () => {
|
|
|
- const node = parseWithVBind(`<div v-bind:[foo].camel="id"/>`)
|
|
|
- expect(node.effect[0].operations[0]).toMatchObject({
|
|
|
+ const { ir, code } = compileWithVBind(`<div v-bind:[foo].camel="id"/>`)
|
|
|
+
|
|
|
+ expect(ir.effect[0].operations[0]).toMatchObject({
|
|
|
runtimeCamelize: true,
|
|
|
key: {
|
|
|
content: `foo`,
|
|
|
@@ -206,6 +228,12 @@ describe('compiler: transform v-bind', () => {
|
|
|
isStatic: false,
|
|
|
},
|
|
|
})
|
|
|
+
|
|
|
+ expect(code).matchSnapshot()
|
|
|
+ expect(code).contains('effect')
|
|
|
+ expect(code).contains(
|
|
|
+ `_setAttr(n1, _camelize(_ctx.foo), undefined, _ctx.id)`,
|
|
|
+ )
|
|
|
})
|
|
|
|
|
|
test.todo('.camel modifier w/ dynamic arg + prefixIdentifiers')
|
|
|
@@ -219,80 +247,3 @@ describe('compiler: transform v-bind', () => {
|
|
|
test.todo('.attr modifier')
|
|
|
test.todo('.attr modifier w/ no expression')
|
|
|
})
|
|
|
-
|
|
|
-// TODO: combine with above
|
|
|
-describe('compiler: codegen v-bind', () => {
|
|
|
- test('simple expression', () => {
|
|
|
- const code = compile(`<div :id="id"></div>`, {
|
|
|
- bindingMetadata: {
|
|
|
- id: BindingTypes.SETUP_REF,
|
|
|
- },
|
|
|
- })
|
|
|
- expect(code).matchSnapshot()
|
|
|
- })
|
|
|
-
|
|
|
- test('should error if no expression', () => {
|
|
|
- const onError = vi.fn()
|
|
|
- const code = compile(`<div v-bind:arg="" />`, { onError })
|
|
|
-
|
|
|
- expect(onError.mock.calls[0][0]).toMatchObject({
|
|
|
- code: ErrorCodes.X_V_BIND_NO_EXPRESSION,
|
|
|
- loc: {
|
|
|
- start: {
|
|
|
- line: 1,
|
|
|
- column: 6,
|
|
|
- },
|
|
|
- end: {
|
|
|
- line: 1,
|
|
|
- column: 19,
|
|
|
- },
|
|
|
- },
|
|
|
- })
|
|
|
-
|
|
|
- expect(code).matchSnapshot()
|
|
|
- // the arg is static
|
|
|
- expect(code).contains(JSON.stringify('<div arg=""></div>'))
|
|
|
- })
|
|
|
-
|
|
|
- test('no expression', () => {
|
|
|
- const code = compile('<div v-bind:id />', {
|
|
|
- bindingMetadata: {
|
|
|
- id: BindingTypes.SETUP_REF,
|
|
|
- },
|
|
|
- })
|
|
|
-
|
|
|
- expect(code).matchSnapshot()
|
|
|
- expect(code).contains('_setAttr(n1, "id", undefined, _ctx.id)')
|
|
|
- })
|
|
|
-
|
|
|
- test('no expression (shorthand)', () => {
|
|
|
- const code = compile('<div :camel-case />', {
|
|
|
- bindingMetadata: {
|
|
|
- camelCase: BindingTypes.SETUP_REF,
|
|
|
- },
|
|
|
- })
|
|
|
-
|
|
|
- expect(code).matchSnapshot()
|
|
|
- expect(code).contains(
|
|
|
- '_setAttr(n1, "camel-case", undefined, _ctx.camelCase)',
|
|
|
- )
|
|
|
- })
|
|
|
-
|
|
|
- test('dynamic arg', () => {
|
|
|
- const code = compile('<div v-bind:[id]="id"/>', {
|
|
|
- bindingMetadata: {
|
|
|
- id: BindingTypes.SETUP_REF,
|
|
|
- },
|
|
|
- })
|
|
|
-
|
|
|
- expect(code).matchSnapshot()
|
|
|
- expect(code).contains('_setAttr(n1, _ctx.id, undefined, _ctx.id)')
|
|
|
- })
|
|
|
-
|
|
|
- test('.camel modifier', () => {
|
|
|
- const code = compile(`<div v-bind:foo-bar.camel="id"/>`)
|
|
|
-
|
|
|
- expect(code).matchSnapshot()
|
|
|
- expect(code).contains('fooBar')
|
|
|
- })
|
|
|
-})
|