Roppongi.vue #5
Core Team Member of Vue.js
Vetur > Experimental: Template Interpolation Service
npm install -g vti
vti diagnostics
https://vuejs.github.io/vetur/vti.html
<template>
<div>{{ message }}</div>
</template>
<template>
<div>{{ message }}</div>
</template>
{
type: 'VElement',
range: [ 13, 37 ],
name: 'div',
startTag: {
type: 'VStartTag',
range: [ 13, 18 ],
selfClosing: false,
attributes: []
},
children: [{
type: 'VExpressionContainer',
range: [ 18, 31 ],
expression: {
type: 'Identifier',
range: [ 21, 28 ],
name: 'message'
}
}],
endTag: {
type: 'VEndTag',
range: [ 31, 37 ]
}
}
{
type: 'VElement',
range: [ 13, 37 ],
name: 'div',
startTag: {
type: 'VStartTag',
range: [ 13, 18 ],
selfClosing: false,
attributes: []
},
children: [{
type: 'VExpressionContainer',
range: [ 18, 31 ],
expression: {
type: 'Identifier',
range: [ 21, 28 ],
name: 'message'
}
}],
endTag: {
type: 'VEndTag',
range: [ 31, 37 ]
}
}
<div>
{{ message }}
</div>
import __Component from "./Test.vue";
import { __vlsRenderHelper, __vlsComponentHelper,
__vlsIterationHelper } from "vue-editor-bridge";
__vlsRenderHelper(__Component, function () {
__vlsComponentHelper(this, "div", {
props: {},
on: {},
directives: []
}, [
this.message
]);
});
{
type: 'VElement',
range: [ 13, 37 ],
name: 'div',
startTag: {
type: 'VStartTag',
range: [ 13, 18 ],
selfClosing: false,
attributes: []
},
children: [{
type: 'VExpressionContainer',
range: [ 18, 31 ],
expression: {
type: 'Identifier',
range: [ 21, 28 ],
name: 'message'
}
}],
endTag: {
type: 'VEndTag',
range: [ 31, 37 ]
}
}
TypeScript Code
{
"pos": -1,
"end": -1,
"kind": 195,
"expression": {
"pos": -1,
"end": -1,
"kind": 75,
"escapedText": "___vlsRenderHelper"
},
"arguments": [
{
"pos": -1,
"end": -1,
"kind": 75,
"escapedText": "___Component"
},
{
"pos": -1,
"end": -1,
"kind": 200,
"parameters": [],
"body": {
"pos": -1,
"end": -1,
"kind": 222,
"statements": []
}
}
]
}
TypeScript AST
import __Component from "./Test.vue";
import { __vlsRenderHelper, __vlsComponentHelper,
__vlsIterationHelper } from "vue-editor-bridge";
__vlsRenderHelper(__Component, function () {
__vlsComponentHelper(this, "div", {
props: {},
on: {},
directives: []
}, [
this.message
]);
});
<div> </div>
{{ message }}
import __Component from "./Test.vue";
import { __vlsRenderHelper, __vlsComponentHelper,
__vlsIterationHelper } from "vue-editor-bridge";
__vlsRenderHelper(__Component, function () {
__vlsComponentHelper(this, "div", {
props: {},
on: {},
directives: []
}, [
this.message
]);
});
import __Component from "./Test.vue";
import { __vlsRenderHelper, __vlsComponentHelper,
__vlsIterationHelper } from "vue-editor-bridge";
__vlsRenderHelper(__Component, function () {
__vlsComponentHelper(this, "div", {
props: {},
on: {},
directives: []
}, [
this.message
]);
});
{
"pos": -1,
"end": -1,
"kind": 195,
"expression": {
"pos": -1,
"end": -1,
"kind": 75,
"escapedText": "___vlsRenderHelper"
},
"arguments": [
{
"pos": -1,
"end": -1,
"kind": 75,
"escapedText": "___Component"
},
{
"pos": -1,
"end": -1,
"kind": 200,
"parameters": [],
"body": {
"pos": -1,
"end": -1,
"kind": 222,
"statements": []
}
}
]
}
import __Component from "./Test.vue";
import { __vlsRenderHelper, __vlsComponentHelper,
__vlsIterationHelper } from "vue-editor-bridge";
__vlsRenderHelper(__Component, function () {
__vlsComponentHelper(this, "div", {
props: {},
on: {},
directives: []
}, [
this.message
]);
});
<template>
<div>{{ message }}</div>
</template>
message: 21–28
message: 256–268
{
"pos": -1,
"end": -1,
"kind": 195,
"expression": {
"pos": -1,
"end": -1,
"kind": 75,
"escapedText": "___vlsRenderHelper"
},
"arguments": [
{
"pos": -1,
"end": -1,
"kind": 75,
"escapedText": "___Component"
},
{
"pos": -1,
"end": -1,
"kind": 200,
"parameters": [],
"body": {
"pos": -1,
"end": -1,
"kind": 222,
"statements": []
}
}
]
}
{
type: 'VElement',
range: [ 13, 37 ],
name: 'div',
startTag: {
type: 'VStartTag',
range: [ 13, 18 ],
selfClosing: false,
attributes: []
},
children: [{
type: 'VExpressionContainer',
range: [ 18, 31 ],
expression: {
type: 'Identifier',
range: [ 21, 28 ],
name: 'message'
}
}],
endTag: {
type: 'VEndTag',
range: [ 31, 37 ]
}
}
vue-eslint-parser AST
TypeScript AST
ts.setSourceMapRange(tsNode, {
pos: 13,
end: 37
});
import __Component from "./Test.vue";
import { __vlsRenderHelper, __vlsComponentHelper,
__vlsIterationHelper } from "vue-editor-bridge";
__vlsRenderHelper(__Component, function () {
__vlsComponentHelper(this, "div", {
props: {},
on: {},
directives: []
}, [
this.message
]);
});
{
"pos": -1,
"end": -1,
"kind": 195,
"expression": {
"pos": -1,
"end": -1,
"kind": 75,
"escapedText": "___vlsRenderHelper"
},
"arguments": [
{
"pos": -1,
"end": -1,
"kind": 75,
"escapedText": "___Component"
},
{
"pos": -1,
"end": -1,
"kind": 200,
"parameters": [],
"body": {
"pos": -1,
"end": -1,
"kind": 222,
"statements": []
}
}
]
}
{
"pos": 139,
"end": 308,
"kind": 195,
"expression": {
"pos": 139,
"end": 158,
"kind": 75,
"escapedText": "___vlsRenderHelper"
},
"arguments": [
{
"pos": 159,
"end": 170,
"kind": 75,
"escapedText": "___Component"
},
{
"pos": 171,
"end": 307,
"kind": 200,
"parameters": [],
"body": {
"pos": 183,
"end": 307,
"kind": 222,
"statements": []
}
}
]
}
正しい Location を持つ AST
Location を持たない AST
{
"pos": -1,
"end": -1,
"kind": 195,
"expression": {
"pos": -1,
"end": -1,
"kind": 75,
"escapedText": "___vlsRenderHelper"
},
"arguments": [
{
"pos": -1,
"end": -1,
"kind": 75,
"escapedText": "___Component"
},
{
"pos": -1,
"end": -1,
"kind": 200,
"parameters": [],
"body": {
"pos": -1,
"end": -1,
"kind": 222,
"statements": []
}
}
]
}
{
"pos": 139,
"end": 308,
"kind": 195,
"expression": {
"pos": 139,
"end": 158,
"kind": 75,
"escapedText": "___vlsRenderHelper"
},
"arguments": [
{
"pos": 159,
"end": 170,
"kind": 75,
"escapedText": "___Component"
},
{
"pos": 171,
"end": 307,
"kind": 200,
"parameters": [],
"body": {
"pos": 183,
"end": 307,
"kind": 222,
"statements": []
}
}
]
}
元の Location を持つ AST
変換後の Location を持つ AST
ts.getSourceMapRange(tsNode)
'Hello'+message
'Hello' + message
[0, 15] – [0, 17]
[8, 15] – [10, 17]
[0, 7] – [0, 7]
'Hello'+message
'Hello' + message
[0, 15] – [0, 17]
[0, 1, 2, 3, 4, 5, 6, 7]
– [0, 1, 2, 3, 4, 5, 6, 7]
[8, 9, 10, 11, 12, 13, 14, 15]
– [10, 11, 12, 13, 14, 15, 16, 17]
<template>
<div v-if="post">
<button @click="onClick(post)">Click</button>
</div>
</template>
<script lang="ts">
import Vue from 'vue'
import { Post } from './post'
export default Vue.extend({
data() {
return {
post: null as Post | null
}
},
methods: {
onClick(post: Post): void { /* ... */}
}
})
</script>
Post | null ✅
Post ✅
Post | null ❌