Skip to content

Commit

Permalink
feat(compiler): vText transform
Browse files Browse the repository at this point in the history
  • Loading branch information
rigor789 committed Apr 1, 2020
1 parent 5a8d058 commit 9832c70
Show file tree
Hide file tree
Showing 9 changed files with 268 additions and 276 deletions.
1 change: 1 addition & 0 deletions apps/test/app/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ const testComp = defineComponent({
<Button text="Hello Button" />
<Label text="Compiled label from template" />
<Label text="Another Compiled label from template" />
<Label v-text="'Label with v-text...!?!?!?'" />
</StackLayout>`
})

Expand Down
3 changes: 2 additions & 1 deletion apps/test/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@
"license": "SEE LICENSE IN <your-license-filename>",
"repository": "<fill-your-repository-here>",
"dependencies": {
"@nativescript/core": "6.5.0"
"@nativescript/core": "6.5.0",
"@vue/shared": "^3.0.0-alpha.10"
},
"devDependencies": {
"@babel/core": "7.8.7",
Expand Down
241 changes: 23 additions & 218 deletions apps/test/yarn.lock

Large diffs are not rendered by default.

81 changes: 81 additions & 0 deletions packages/compiler/__tests__/testUtils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import {
NodeTypes,
ElementNode,
locStub,
Namespaces,
ElementTypes,
VNodeCall
} from '../src'
import { isString, PatchFlags, PatchFlagNames, isArray } from '@vue/shared'

const leadingBracketRE = /^\[/
const bracketsRE = /^\[|\]$/g

// Create a matcher for an object
// where non-static expressions should be wrapped in []
// e.g.
// - createObjectMatcher({ 'foo': '[bar]' }) matches { foo: bar }
// - createObjectMatcher({ '[foo]': 'bar' }) matches { [foo]: "bar" }
export function createObjectMatcher(obj: Record<string, any>) {
return {
type: NodeTypes.JS_OBJECT_EXPRESSION,
properties: Object.keys(obj).map(key => ({
type: NodeTypes.JS_PROPERTY,
key: {
type: NodeTypes.SIMPLE_EXPRESSION,
content: key.replace(bracketsRE, ''),
isStatic: !leadingBracketRE.test(key)
},
value: isString(obj[key])
? {
type: NodeTypes.SIMPLE_EXPRESSION,
content: obj[key].replace(bracketsRE, ''),
isStatic: !leadingBracketRE.test(obj[key])
}
: obj[key]
}))
}
}

export function createElementWithCodegen(
tag: VNodeCall['tag'],
props?: VNodeCall['props'],
children?: VNodeCall['children'],
patchFlag?: VNodeCall['patchFlag'],
dynamicProps?: VNodeCall['dynamicProps']
): ElementNode {
return {
type: NodeTypes.ELEMENT,
loc: locStub,
ns: Namespaces.HTML,
tag: 'div',
tagType: ElementTypes.ELEMENT,
isSelfClosing: false,
props: [],
children: [],
codegenNode: {
type: NodeTypes.VNODE_CALL,
tag,
props,
children,
patchFlag,
dynamicProps,
directives: undefined,
isBlock: false,
isForBlock: false,
loc: locStub
}
}
}

export function genFlagText(flag: PatchFlags | PatchFlags[]) {
if (isArray(flag)) {
let f = 0
flag.forEach(ff => {
f |= ff
})
return `${f} /* ${flag.map(f => PatchFlagNames[f]).join(', ')} */`
} else {
return `${flag} /* ${PatchFlagNames[flag]} */`
}
}
98 changes: 49 additions & 49 deletions packages/compiler/__tests__/transforms/transformStyle.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// todo: uncomment if/when vue-next#907 is merged/released
// todo: uncomment when vue-next#907 is released
test.todo('uncomment when vue-next#907 is released')
// import {
// baseParse as parse,
// transform,
Expand Down Expand Up @@ -26,51 +27,50 @@
// }
// }
//
describe('compiler: style transform', () => {
test.todo('uncomment tests')
// test('should transform into directive node', () => {
// const { node } = transformWithStyleTransform(`<Label style="color: red"/>`)
// expect(node.props[0]).toMatchObject({
// type: NodeTypes.DIRECTIVE,
// name: `bind`,
// arg: {
// type: NodeTypes.SIMPLE_EXPRESSION,
// content: `style`,
// isStatic: true
// },
// exp: {
// type: NodeTypes.SIMPLE_EXPRESSION,
// content: `{"color":"red"}`,
// isStatic: false
// }
// })
// })
//
// test('working with v-bind transform', () => {
// const { node } = transformWithStyleTransform(`<Label style="color: red"/>`, {
// nodeTransforms: [transformStyle, transformElement],
// directiveTransforms: {
// bind: transformBind
// }
// })
// expect((node.codegenNode as VNodeCall).props).toMatchObject({
// type: NodeTypes.JS_OBJECT_EXPRESSION,
// properties: [
// {
// key: {
// type: NodeTypes.SIMPLE_EXPRESSION,
// content: `style`,
// isStatic: true
// },
// value: {
// type: NodeTypes.SIMPLE_EXPRESSION,
// content: `{"color":"red"}`,
// isStatic: false
// }
// }
// ]
// })
// // should not cause the STYLE patchFlag to be attached
// expect((node.codegenNode as VNodeCall).patchFlag).toBeUndefined()
// })
})
// describe('compiler: style transform', () => {
// test('should transform into directive node', () => {
// const { node } = transformWithStyleTransform(`<Label style="color: red"/>`)
// expect(node.props[0]).toMatchObject({
// type: NodeTypes.DIRECTIVE,
// name: `bind`,
// arg: {
// type: NodeTypes.SIMPLE_EXPRESSION,
// content: `style`,
// isStatic: true
// },
// exp: {
// type: NodeTypes.SIMPLE_EXPRESSION,
// content: `{"color":"red"}`,
// isStatic: false
// }
// })
// })
//
// test('working with v-bind transform', () => {
// const { node } = transformWithStyleTransform(`<Label style="color: red"/>`, {
// nodeTransforms: [transformStyle, transformElement],
// directiveTransforms: {
// bind: transformBind
// }
// })
// expect((node.codegenNode as VNodeCall).props).toMatchObject({
// type: NodeTypes.JS_OBJECT_EXPRESSION,
// properties: [
// {
// key: {
// type: NodeTypes.SIMPLE_EXPRESSION,
// content: `style`,
// isStatic: true
// },
// value: {
// type: NodeTypes.SIMPLE_EXPRESSION,
// content: `{"color":"red"}`,
// isStatic: false
// }
// }
// ]
// })
// // should not cause the STYLE patchFlag to be attached
// expect((node.codegenNode as VNodeCall).patchFlag).toBeUndefined()
// })
// })
72 changes: 72 additions & 0 deletions packages/compiler/__tests__/transforms/vText.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
// todo: uncomment when vue-next#907 is released
test.todo('uncomment when vue-next#907 is released')
// import {
// baseParse as parse,
// transform,
// PlainElementNode,
// CompilerOptions,
// transformElement
// } from '@vue/compiler-core'
// import { transformVText } from '../../src/transforms/vText'
// import {
// createObjectMatcher,
// genFlagText
// } from '../testUtils'
// import { PatchFlags } from '@vue/shared'
// import { DOMErrorCodes } from '../../src/errors'
//
// function transformWithVText(template: string, options: CompilerOptions = {}) {
// const ast = parse(template)
// transform(ast, {
// nodeTransforms: [transformElement],
// directiveTransforms: {
// text: transformVText
// },
// ...options
// })
// return ast
// }
//
// describe('compiler: v-text transform', () => {
// it('should convert v-text to text', () => {
// const ast = transformWithVText(`<Label v-text="test"/>`)
// expect((ast.children[0] as PlainElementNode).codegenNode).toMatchObject({
// tag: `_component_Label`,
// props: createObjectMatcher({
// text: `[test]`
// }),
// children: undefined,
// patchFlag: genFlagText(PatchFlags.PROPS),
// dynamicProps: `["text"]`
// })
// })
//
// it('should raise error and ignore children when v-text is present', () => {
// const onError = jest.fn()
// const ast = transformWithVText(`<Label v-text="test">hello</Label>`, {
// onError
// })
// expect(onError.mock.calls).toMatchObject([
// [{ code: DOMErrorCodes.X_V_TEXT_WITH_CHILDREN }]
// ])
// expect((ast.children[0] as PlainElementNode).codegenNode).toMatchObject({
// tag: `_component_Label`,
// props: createObjectMatcher({
// text: `[test]`
// }),
// children: undefined, // <-- children should have been removed
// patchFlag: genFlagText(PatchFlags.PROPS),
// dynamicProps: `["text"]`
// })
// })
//
// it('should raise error if has no expression', () => {
// const onError = jest.fn()
// transformWithVText(`<Label v-text></Label>`, {
// onError
// })
// expect(onError.mock.calls).toMatchObject([
// [{ code: DOMErrorCodes.X_V_TEXT_NO_EXPRESSION }]
// ])
// })
// })
15 changes: 7 additions & 8 deletions packages/compiler/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,10 @@ import {
NodeTransform,
DirectiveTransform
} from '@vue/compiler-core'
// import { parserOptionsMinimal } from './parserOptionsMinimal'
import { parserOptions } from './parserOptions'
// import { transformStyle } from './transforms/transformStyle'
import { transformStyle } from './transforms/transformStyle'
// import { transformVHtml } from './transforms/vHtml'
// import { transformVText } from './transforms/vText'
import { transformVText } from './transforms/vText'
// import { transformModel } from './transforms/vModel'
// import { transformOn } from './transforms/vOn'
// import { transformShow } from './transforms/vShow'
Expand All @@ -23,14 +22,14 @@ import { parserOptions } from './parserOptions'
export { parserOptions }

export const DOMNodeTransforms: NodeTransform[] = [
// transformStyle,
transformStyle
// ...(__DEV__ ? [warnTransitionChildren] : [])
]

export const DOMDirectiveTransforms: Record<string, DirectiveTransform> = {
cloak: noopDirectiveTransform
cloak: noopDirectiveTransform,
// html: transformVHtml,
// text: transformVText,
text: transformVText
// model: transformModel, // override compiler-core
// on: transformOn, // override compiler-core
// show: transformShow
Expand All @@ -48,7 +47,7 @@ export function compile(
...DOMDirectiveTransforms,
...(options.directiveTransforms || {})
}
// transformHoist: __BROWSER__ ? null : stringifyStatic
// transformHoist: stringifyStatic
})
}

Expand All @@ -60,6 +59,6 @@ export function parse(template: string, options: ParserOptions = {}): RootNode {
}

export * from './runtimeHelpers'
// export { transformStyle } from './transforms/transformStyle'
export { transformStyle } from './transforms/transformStyle'
export { createDOMCompilerError, DOMErrorCodes } from './errors'
export * from '@vue/compiler-core'
31 changes: 31 additions & 0 deletions packages/compiler/src/transforms/vText.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import {
DirectiveTransform,
createObjectProperty,
createSimpleExpression
} from '@vue/compiler-core'
import { createDOMCompilerError, DOMErrorCodes } from '../errors'

export const transformVText: DirectiveTransform = (dir, node, context) => {
const { exp, loc } = dir
if (!exp) {
context.onError(
createDOMCompilerError(DOMErrorCodes.X_V_TEXT_NO_EXPRESSION, loc)
)
}
if (node.children.length) {
context.onError(
createDOMCompilerError(DOMErrorCodes.X_V_TEXT_WITH_CHILDREN, loc)
)
node.children.length = 0
}
return {
props: [
createObjectProperty(
// todo: check if we should implement via a generic textContent
// and handle in runtime module?
createSimpleExpression(`text`, true, loc),
exp || createSimpleExpression('', true)
)
]
}
}
2 changes: 2 additions & 0 deletions packages/nativescript-vue/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ function compileToFunction(
...options
})

// console.log(code)
// const render = () => {}
const render = new Function('Vue', code)(runtime) as RenderFunction
return (compileCache[key] = render)
}
Expand Down

0 comments on commit 9832c70

Please sign in to comment.