aboutsummaryrefslogtreecommitdiff
path: root/node_modules/vue/src/sfc/parser.js
diff options
context:
space:
mode:
Diffstat (limited to 'node_modules/vue/src/sfc/parser.js')
-rw-r--r--node_modules/vue/src/sfc/parser.js116
1 files changed, 116 insertions, 0 deletions
diff --git a/node_modules/vue/src/sfc/parser.js b/node_modules/vue/src/sfc/parser.js
new file mode 100644
index 00000000..868a43ca
--- /dev/null
+++ b/node_modules/vue/src/sfc/parser.js
@@ -0,0 +1,116 @@
+/* @flow */
+
+import deindent from 'de-indent'
+import { parseHTML } from 'compiler/parser/html-parser'
+import { makeMap } from 'shared/util'
+
+const splitRE = /\r?\n/g
+const replaceRE = /./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,
+ options?: Object = {}
+): SFCDescriptor {
+ const sfc: SFCDescriptor = {
+ template: null,
+ script: null,
+ styles: [],
+ customBlocks: []
+ }
+ let depth = 0
+ let currentBlock: ?SFCBlock = null
+
+ function start (
+ tag: string,
+ attrs: Array<Attribute>,
+ unary: boolean,
+ start: number,
+ end: number
+ ) {
+ if (depth === 0) {
+ currentBlock = {
+ type: tag,
+ content: '',
+ start: end,
+ attrs: attrs.reduce((cumulated, { name, value }) => {
+ cumulated[name] = value || true
+ return cumulated
+ }, {})
+ }
+ if (isSpecialTag(tag)) {
+ checkAttrs(currentBlock, attrs)
+ if (tag === 'style') {
+ sfc.styles.push(currentBlock)
+ } else {
+ sfc[tag] = currentBlock
+ }
+ } else { // custom blocks
+ sfc.customBlocks.push(currentBlock)
+ }
+ }
+ if (!unary) {
+ depth++
+ }
+ }
+
+ 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 === 'module') {
+ block.module = attr.value || true
+ }
+ if (attr.name === 'src') {
+ block.src = attr.value
+ }
+ }
+ }
+
+ function end (tag: string, start: number, end: number) {
+ if (depth === 1 && currentBlock) {
+ currentBlock.end = start
+ let text = deindent(content.slice(currentBlock.start, currentBlock.end))
+ // pad content so that linters and pre-processors can output correct
+ // line numbers in errors and warnings
+ if (currentBlock.type !== 'template' && options.pad) {
+ text = padContent(currentBlock, options.pad) + text
+ }
+ currentBlock.content = text
+ currentBlock = null
+ }
+ depth--
+ }
+
+ function padContent (block: SFCBlock, pad: true | "line" | "space") {
+ if (pad === 'space') {
+ return content.slice(0, block.start).replace(replaceRE, ' ')
+ } else {
+ const offset = content.slice(0, block.start).split(splitRE).length
+ const padChar = block.type === 'script' && !block.lang
+ ? '//\n'
+ : '\n'
+ return Array(offset).join(padChar)
+ }
+ }
+
+ parseHTML(content, {
+ start,
+ end
+ })
+
+ return sfc
+}