1/* 2 * Copyright (c) 2021 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16import path from 'path' 17import fs from 'fs' 18import { 19 getRequireString, 20 jsonLoaders, 21 logWarn 22} 23from './util' 24import { parseFragment } from './parser' 25 26function loader(source) { 27 this.cacheable && this.cacheable() 28 const options = { 29 lang: { 30 sass:['sass-loader'], 31 scss:['sass-loader'], 32 less:['less-loader'] 33 } 34 } 35 const customLang = options.lang || {} 36 const resourcePath = this.resourcePath 37 const fileName = resourcePath.replace(path.extname(resourcePath).toString(), '') 38 let output = '//card_start\n' 39 output += 'var card_template =' + getRequireString(this, jsonLoaders('template'), resourcePath) 40 const styleInfo = findStyleFile(fileName) 41 if (styleInfo.extStyle == true) { 42 output += 'var card_style =' + 43 getRequireString(this, jsonLoaders('style', customLang[styleInfo.type]), styleInfo.styleFileName) 44 } 45 output = addJson(this, output, fileName, '') 46 47 const frag = parseFragment(source) 48 const nameSet = new Set() 49 if (frag.element) { 50 frag.element.forEach(item => { 51 let customElementName 52 if (!item.src) { 53 logWarn(this, [{ 54 reason: `ERROR: The attribute 'src' must be set in the custom element.`, 55 line: item.node.__location.line, 56 column: item.node.__location.col 57 }]) 58 return 59 } 60 if (!item.src.match(/\.hml$/)) { 61 item.src = item.src.concat('.hml') 62 } 63 const compResourcepath = path.join(resourcePath, '..', item.src) 64 if (!fs.existsSync(compResourcepath)) { 65 logWarn(this, [{ 66 reason: `ERROR: The custom element '${compResourcepath}' can not be found.`, 67 line: item.node.__location.line, 68 column: item.node.__location.col 69 }]) 70 return 71 } 72 if (!item.name) { 73 customElementName = path.parse(item.src).name.toLowerCase() 74 } else { 75 customElementName = item.name.toLowerCase() 76 } 77 if (nameSet.has(customElementName)) { 78 logWarn(this, [{ 79 reason: `ERROR: The custom elements cannot have the same attribute 'name' or file name (case insensitive).`, 80 line: item.node.__location.line, 81 column: item.node.__location.col 82 }]) 83 return 84 } else { 85 nameSet.add(customElementName) 86 } 87 const compFileName = compResourcepath.replace(path.extname(compResourcepath).toString(), '') 88 const elementLastName = path.basename(compResourcepath).replace(path.extname(compResourcepath).toString(), '') 89 output += `var card_element_template_${elementLastName} =` + getRequireString(this, jsonLoaders('template'), 90 compResourcepath + `?${customElementName}#${fileName}`) 91 const compStyleInfo = findStyleFile(compFileName) 92 if (compStyleInfo.extStyle == true) { 93 output += `var card_element_style_${elementLastName} =` + 94 getRequireString(this, jsonLoaders('style', customLang[compStyleInfo.type]), 95 compStyleInfo.styleFileName + `?${customElementName}#${fileName}`) 96 } 97 output = addJson(this, output, compFileName, `?${customElementName}#${fileName}`, elementLastName) 98 }) 99 } 100 output = output + '\n//card_end' 101 return output 102} 103 104function findStyleFile (fileName) { 105 let extStyle = false 106 let styleFileName = fileName + '.css' 107 let type = 'css' 108 if (fs.existsSync(styleFileName)) { 109 extStyle = true 110 type = 'css' 111 } else { 112 styleFileName = fileName + '.less' 113 if (fs.existsSync(styleFileName)) { 114 extStyle = true 115 type = 'less' 116 } else { 117 styleFileName = fileName + '.sass' 118 if (fs.existsSync(styleFileName)) { 119 extStyle = true 120 type = 'sass' 121 } else { 122 styleFileName = fileName + '.scss' 123 if (fs.existsSync(styleFileName)) { 124 extStyle = true 125 type = 'sass' 126 } else { 127 extStyle = false 128 } 129 } 130 } 131 } 132 return {extStyle: extStyle, styleFileName: styleFileName, type: type} 133} 134 135function addJson(_this, output, fileName, query, elementLastName) { 136 const content = `${elementLastName ? 'var card_element_json_' + elementLastName : 'var card_json'} =` 137 if (fs.existsSync(fileName + '.json') && !fs.existsSync(fileName + '.js')) { 138 output += content + getRequireString(_this, jsonLoaders('json'), fileName + '.json' + query) 139 } else if (fs.existsSync(fileName + '.js') && !fs.existsSync(fileName + '.json')) { 140 logWarn(_this, [{ 141 reason: `WARNING: The JS file '${fileName}.js' will be discarded in future version, ` + 142 `use the JSON file '${fileName}.json' instead.`, 143 }]) 144 output += content + getRequireString(_this, jsonLoaders('json'), fileName + '.js' + query) 145 } else if (fs.existsSync(fileName + '.json') && fs.existsSync(fileName + '.js')) { 146 logWarn(_this, [{ 147 reason: `WARNING: '${fileName}' cannot have the same name files '.json' and '.js', otherwise '.json' in default.`, 148 }]) 149 output += content + getRequireString(_this, jsonLoaders('json'), fileName + '.json' + query) 150 } 151 return output 152} 153 154module.exports = loader