• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements.  See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership.  The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License.  You may obtain a copy of the License at
9 *
10 *   http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied.  See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19
20import * as parse5 from 'parse5'
21import templater from './templater'
22import styler from './styler'
23import scripter from './scripter'
24import { checkTagName } from './templater/component_validator'
25
26import {
27  FUNC_START_REG,
28  FUNC_END_REG,
29  stringifyFunction
30} from './util'
31
32function getAttribute (node, name) {
33  if (node.attrs) {
34    let i = node.attrs.length
35    let attr
36    while (i--) {
37      attr = node.attrs[i]
38      if (attr.name === name) {
39        return attr.value
40      }
41    }
42  }
43}
44
45function extractDependencies (node, deps) {
46  if (node.childNodes) {
47    node.childNodes.forEach(child => {
48      checkTagName(child, {
49        result: {},
50        deps,
51        log: []
52      })
53      extractDependencies(child, deps)
54    })
55  }
56}
57
58export function parseFragment (source) {
59  const fragment = parse5.parseFragment(source, {
60    locationInfo: true
61  })
62
63  const output = {
64    deps: [],
65    element: [],
66    template: [],
67    style: [],
68    script: [],
69    data: [],
70    config: []
71  }
72
73  fragment.childNodes.forEach(node => {
74    let type
75
76    if (node.tagName === 'script') {
77      type = getAttribute(node, 'type')
78      if (type !== 'data' && type !== 'config') {
79        type = 'script'
80      }
81    }
82    else {
83      type = node.tagName
84    }
85    if (type === 'we-element') {
86      console.warn(`<we-element name="${getAttribute(node, 'name')}"> is deprecated, please use <element> instead.`)
87      type = 'element'
88    }
89
90    if (!output[type]) {
91      return
92    }
93
94    const name = getAttribute(node, 'name')
95    const src = getAttribute(node, 'src')
96    const lang = getAttribute(node, 'lang')
97
98    output[type].push({
99      name,
100      src,
101      lang,
102      node
103    })
104
105    if (type === 'template') {
106      const deps = []
107      extractDependencies(node.content, deps)
108      output.deps = deps
109    }
110  })
111
112  return output
113}
114
115export function parseTemplate (source, resourcePath) {
116  return new Promise((resolve, reject) => {
117    templater.parse(source, (err, obj) => {
118      if (err) {
119        reject(err)
120      }
121      else {
122        // parse json to string and treat function specially
123        let parsed = JSON.stringify(obj.jsonTemplate, stringifyFunction, '  ')
124        parsed = parsed.replace(FUNC_START_REG, '').replace(FUNC_END_REG, '')
125        resolve({ parsed, log: obj.log })
126      }
127    }, resourcePath)
128  })
129}
130
131export function parseStyle (source, resourcePath) {
132  return new Promise((resolve, reject) => {
133    styler.parse(source, (err, obj) => {
134      if (err) {
135        reject(err)
136      }
137      else {
138        const parsed = JSON.stringify(obj.jsonStyle, null, 2)
139        resolve({ parsed, log: obj.log })
140      }
141    }, resourcePath)
142  })
143}
144
145export function parseScript (source) {
146  return new Promise((resolve, reject) => {
147    const parsed = scripter.fix(source)
148    resolve({ parsed })
149  })
150}
151