add pad/map option to sfc parser

This commit is contained in:
Evan You 2016-06-10 13:19:04 -04:00
parent d94225ec84
commit b0b9691efe
10 changed files with 110 additions and 31 deletions

View File

@ -65,7 +65,7 @@ var builds = [
{
entry: 'src/entries/web-compiler.js',
format: 'cjs',
external: ['entities', 'de-indent'],
external: ['entities', 'de-indent', 'source-map'],
out: 'packages/vue-template-compiler/index.js'
},
// Web server renderer (CommonJS).

View File

@ -0,0 +1,29 @@
var path = require('path')
var alias = require('./alias')
module.exports = {
entry: path.resolve(__dirname, '../src/entries/web-compiler.js'),
target: 'node',
output: {
path: path.resolve(__dirname, '../packages/vue-template-compiler'),
filename: 'index.js',
libraryTarget: 'commonjs2'
},
resolve: {
alias: alias
},
externals: {
'entities': true,
'de-indent': true,
'source-map': true
},
module: {
loaders: [
{
test: /\.js/,
loader: 'babel!eslint',
exclude: /node_modules/
}
]
}
}

View File

@ -3,7 +3,7 @@ var alias = require('./alias')
var webpack = require('webpack')
module.exports = {
entry: path.resolve(__dirname, 'dist.dev.entry.js'),
entry: path.resolve(__dirname, 'webpack.dist.dev.entry.js'),
output: {
path: path.resolve(__dirname, '../dist'),
filename: 'vue.js',

View File

@ -2,11 +2,11 @@ var path = require('path')
var alias = require('./alias')
module.exports = {
entry: path.resolve(__dirname, 'ssr.dev.entry.js'),
entry: path.resolve(__dirname, 'webpack.ssr.dev.entry.js'),
target: 'node',
output: {
path: path.resolve(__dirname, '../dist'),
filename: 'server-renderer.js',
path: path.resolve(__dirname, '../packages/vue-server-renderer'),
filename: 'index.js',
libraryTarget: 'commonjs2'
},
resolve: {

View File

@ -133,6 +133,14 @@ declare module 'de-indent' {
}
}
declare module 'source-map' {
declare class SourceMapGenerator {
setSourceContent(filename: string, content: string): void;
addMapping(mapping: Object): void;
toString(): string;
}
}
// an object format describing a single-file component.
declare type SFCDescriptor = {
template: ?SFCBlock,
@ -141,10 +149,12 @@ declare type SFCDescriptor = {
}
declare type SFCBlock = {
type: "template" | "script" | "style",
type: string,
content: string,
start?: number,
end?: number,
lang?: string,
src?: string,
scoped?: boolean,
src?: boolean,
map?: Object
}

View File

@ -15,6 +15,7 @@
"dev": "webpack --watch --config build/webpack.dist.dev.config.js",
"dev:test": "karma start build/karma.dev.config.js",
"dev:ssr": "webpack --watch --config build/webpack.ssr.dev.config.js",
"dev:compiler": "webpack --watch --config build/webpack.compiler.dev.config.js",
"test": "npm run lint && flow check && npm run test:unit && npm run test:e2e && npm run test:ssr",
"ci": "npm run lint && flow check && npm run test:cover && npm run test:ssr",
"build": "NODE_ENV=production node build/build.js",
@ -51,8 +52,6 @@
"chromedriver": "^2.21.2",
"codecov.io": "^0.1.6",
"cross-spawn": "^4.0.0",
"de-indent": "^1.0.2",
"entities": "^1.1.1",
"eslint": "^2.11.0",
"eslint-config-vue": "^1.0.3",
"eslint-loader": "^1.3.0",

View File

@ -19,6 +19,7 @@
"homepage": "https://github.com/vuejs/vue#readme",
"dependencies": {
"de-indent": "^1.0.2",
"entities": "^1.1.1"
"entities": "^1.1.1",
"source-map": "^0.5.6"
}
}

View File

@ -1,64 +1,104 @@
/* @flow */
// this file is used in the vue-template-compiler npm package
// and assumes its dependencies and a Node/CommonJS environment
import deindent from 'de-indent'
import { SourceMapGenerator } from 'source-map'
import { parseHTML } from './html-parser'
import { makeMap } from 'shared/util'
import deindent from 'de-indent'
const splitRE = /\r?\n/g
const isSpecialTag = makeMap('script,style,template', true)
type Attribute = {
name: string,
value: string
}
/**
* Parse a single-file component (*.vue) file into an SFC Descriptor Object.
*/
export function parseComponent (content: string): SFCDescriptor {
export function parseComponent (
content: string,
options?: Object
): SFCDescriptor {
const sfc: SFCDescriptor = {
template: null,
script: null,
styles: []
}
let depth = 0
let currentBlock
let currentBlock: ?SFCBlock = null
function start (tag, attrs) {
function start (tag: string, attrs: Array<Attribute>) {
depth++
if (depth > 1) {
return
}
if (isSpecialTag(tag)) {
const block: SFCBlock = currentBlock = {
currentBlock = {
type: tag,
content: ''
}
for (let i = 0; i < attrs.length; i++) {
const attr = attrs[i]
if (attr.name === 'lang') {
block.lang = attr.value
}
if (attr.name === 'scoped') {
block.scoped = true
}
if (attr.name === 'src') {
block.src = attr.value
}
}
checkAttrs(currentBlock, attrs)
if (tag === 'style') {
sfc.styles.push(block)
sfc.styles.push(currentBlock)
} else {
sfc[tag] = block
sfc[tag] = currentBlock
}
}
}
function checkAttrs (block: SFCBlock, attrs: Array<Attribute>) {
for (let i = 0; i < attrs.length; i++) {
const attr = attrs[i]
if (attr.name === 'lang') {
block.lang = attr.value
}
if (attr.name === 'scoped') {
block.scoped = true
}
if (attr.name === 'src') {
block.src = attr.value
}
}
}
function end () {
depth--
if (currentBlock && options && options.map) {
addSourceMap(currentBlock)
}
currentBlock = null
}
function chars (text) {
function chars (text: string) {
if (currentBlock) {
currentBlock.content = deindent(text)
currentBlock.start = content.indexOf(text)
currentBlock.end = currentBlock.start + text.length
text = deindent(text)
// pad content so that linters and pre-processors can output correct
// line numbers in errors and warnings
if (currentBlock.type !== 'template' && options && options.pad) {
text = padContent(currentBlock) + text
}
currentBlock.content = text
}
}
function padContent (block: SFCBlock) {
const leadingContent = content.slice(0, block.start)
const padChar = block.type === 'script' && !block.lang
? '//\n'
: '\n'
return Array(leadingContent.split(splitRE).length).join(padChar)
}
function addSourceMap (block: SFCBlock) {
}
parseHTML(content, {
isSpecialTag,
start,