Prechádzať zdrojové kódy

add pad/map option to sfc parser

Evan You 10 rokov pred
rodič
commit
b0b9691efe

+ 1 - 1
build/build.js

@@ -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).

+ 29 - 0
build/webpack.compiler.dev.config.js

@@ -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/
+      }
+    ]
+  }
+}

+ 1 - 1
build/webpack.dist.dev.config.js

@@ -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',

+ 0 - 0
build/dist.dev.entry.js → build/webpack.dist.dev.entry.js


+ 3 - 3
build/webpack.ssr.dev.config.js

@@ -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: {

+ 0 - 0
build/ssr.dev.entry.js → build/webpack.ssr.dev.entry.js


+ 12 - 2
flow/compiler.js

@@ -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
 }

+ 1 - 2
package.json

@@ -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",

+ 2 - 1
packages/vue-template-compiler/package.json

@@ -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"
   }
 }

+ 61 - 21
src/compiler/parser/sfc-parser.js

@@ -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,