diff options
Diffstat (limited to 'node_modules/vue/src/sfc/parser.js')
| -rw-r--r-- | node_modules/vue/src/sfc/parser.js | 116 |
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 +} |
