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 */ 15const isType = require('../lite/lite-utils'); 16const rulePath = process.env.RULE_PATH; 17const smartvisionTag = { 18 camera: { 19 events: ['error'], 20 }, 21 video: { 22 events: [ 23 'prepared', 24 'start', 25 'pause', 26 'finish', 27 'error', 28 'seeking', 29 'seeked', 30 'timeupdate', 31 ], 32 attrs: { 33 autoplay: { 34 enum: ['false', 'true'], 35 }, 36 controls: { 37 enum: ['true', 'false'], 38 }, 39 muted: { 40 enum: ['false', 'true'], 41 }, 42 src: { checkPath: true }, 43 }, 44 }, 45}; 46 47const litewearableTag = { 48 'div': {}, 49 'canvas': {}, 50 'stack': {}, 51 'qrcode': { 52 atomic: true, 53 selfClosing: true, 54 uevents: ['click', 'longpress', 'swipe'], 55 attrs: { 56 value: { 57 required: true, 58 }, 59 type: { 60 enum: ['rect', 'circle'], 61 }, 62 }, 63 }, 64 'list': { 65 events: ['scrollend'], 66 children: ['list-item'], 67 }, 68 'list-item': { 69 excludeRoot: true, 70 parents: ['list'], 71 }, 72 'swiper': { 73 unSupportedChildren: ['list'], 74 events: ['change'], 75 attrs: { 76 index: { 77 checkFunc: 'number', 78 }, 79 loop: { 80 enum: ['true', 'false'], 81 }, 82 duration: { 83 checkFunc: 'number', 84 }, 85 vertical: { 86 enum: ['false', 'true'], 87 }, 88 }, 89 }, 90 'tabs': { 91 events: ['change'], 92 children: ['tab-content', 'tab-bar'], 93 }, 94 'tab-bar': { 95 parents: ['tabs'], 96 children: ['text'], 97 attrs: { 98 mode: { 99 enum: ['fixed'], 100 }, 101 }, 102 }, 103 'tab-content': { 104 parents: ['tabs'], 105 children: ['div', 'stack'], // to be checked 106 }, 107 'image-animator': { 108 atomic: true, 109 selfClosing: true, 110 events: ['stop'], 111 attrs: { 112 images: { 113 required: true, 114 }, 115 iteration: {}, 116 reverse: { 117 enum: ['false', 'true'], 118 }, 119 fixedsize: { 120 enum: ['true', 'false'], 121 }, 122 duration: { 123 required: true, 124 }, 125 fillmode: { 126 enum: ['none', 'forwards'], 127 }, 128 }, 129 }, 130 'image': { 131 alias: ['img'], 132 atomic: true, 133 selfClosing: true, 134 attrs: { 135 src: { 136 checkPath: true, 137 }, 138 }, 139 }, 140 'progress': { 141 atomic: true, 142 selfClosing: true, 143 attrs: { 144 type: { 145 enum: ['horizontal', 'arc'], 146 }, 147 percent: { 148 checkFunc: 'number', 149 }, 150 }, 151 }, 152 'text': { 153 atomic: true, 154 textContent: true, 155 attrs: { 156 type: { 157 enum: ['text', 'html'], 158 }, 159 value: {}, 160 }, 161 }, 162 'marquee': { 163 atomic: true, 164 attrs: { 165 scrollamount: { 166 def: 6, 167 checkFunc: 'number', 168 }, 169 }, 170 }, 171 'analog-clock': { 172 attrs: { 173 hour: { 174 checkFunc: 'number', 175 }, 176 min: { 177 checkFunc: 'number', 178 }, 179 sec: { 180 checkFunc: 'number', 181 }, 182 }, 183 }, 184 'clock-hand': { 185 parents: ['analog-clock'], 186 attrs: { 187 type: { 188 enum: ['hour', 'min', 'sec'], 189 }, 190 src: { 191 checkPath: true, 192 }, 193 }, 194 }, 195 'chart': { 196 atomic: true, 197 selfClosing: true, 198 attrs: { 199 type: { 200 enum: ['line', 'bar'], 201 }, 202 datasets: {}, 203 options: {}, 204 }, 205 }, 206 'input': { 207 atomic: true, 208 selfClosing: true, 209 events: ['change'], 210 attrs: { 211 checked: { 212 enum: ['false', 'true'], 213 }, 214 type: { 215 enum: ['button', 'checkbox', 'radio'], 216 }, 217 name: {}, 218 value: {}, 219 }, 220 }, 221 'slider': { 222 atomic: true, 223 selfClosing: true, 224 events: ['change'], 225 attrs: { 226 min: { 227 def: 0, 228 checkFunc: 'number', 229 }, 230 max: { 231 def: 100, 232 checkFunc: 'number', 233 }, 234 value: { 235 def: 0, 236 checkFunc: 'number', 237 }, 238 }, 239 }, 240 'switch': { 241 events: ['change'], 242 atomic: true, 243 selfClosing: true, 244 attrs: { 245 checked: { 246 enum: ['false', 'true'], 247 }, 248 }, 249 }, 250 'picker-view': { 251 atomic: true, 252 selfClosing: true, 253 uevents: ['change'], 254 attrs: { 255 type: { 256 enum: ['text', 'time'], 257 }, 258 range: {}, 259 selected: {}, 260 }, 261 }, 262}; 263 264const liteCommonTag = { 265 events: [ 266 'click', 267 'longpress', 268 'touchstart', 269 'touchmove', 270 'touchcancel', 271 'touchend', 272 'key', 273 'swipe', 274 ], 275 attrs: { 276 id: {}, 277 style: {}, 278 class: {}, 279 ref: {}, 280 if: { 281 excludeRoot: true, 282 def: 'true', 283 }, 284 elif: { 285 def: 'true', 286 }, 287 else: { 288 excludeRoot: true, 289 }, 290 for: { 291 excludeRoot: true, 292 }, 293 tid: {}, 294 show: { 295 excludeRoot: true, 296 def: 'true', 297 }, 298 }, 299}; 300 301/** 302 * Rules for adapting to different environments. If it is `liteWearable` device type, 303 * set to this type of verification rule. 304 * @param {String} deviceType device type. 305 * @return {Object} Validation rules. 306 */ 307function select(deviceType) { 308 tag = { 309 liteWearable: litewearableTag, 310 smartVision: { ...litewearableTag, ...smartvisionTag }, 311 }; 312 return tag[deviceType]; 313} 314let liteNativeTag = select(process.env.DEVICE_TYPE); 315 316/** 317 * Whether the file exists, get customized rules. 318 */ 319(function checkFile() { 320 if (rulePath) { 321 const customTag = require(rulePath); 322 isExtends(customTag); 323 } 324})(); 325 326/** 327 * Get the component types supported by the current verification rule. 328 * @return {Array} Supported component name. 329 */ 330function getKeys() { 331 const res = []; 332 const keys = Object.keys(liteNativeTag); 333 for (let i = 0; i < keys.length; i++) { 334 const key = keys[i]; 335 res.push(key); 336 } 337 res.push('attrs'); 338 return res; 339} 340 341/** 342 * According to user-defined rules, combine into new verification rules. 343 * @param {Object} customTag User-defined rule object. 344 */ 345function isExtends(customTag) { 346 if (customTag.extends == 'recommended') { 347 const nativekeys = getKeys(); 348 merge(liteNativeTag, customTag.rules, nativekeys); 349 } else { 350 liteNativeTag = customTag.rules; 351 } 352} 353/** 354 * Combine the original rules and user-defined rules. 355 * @param {Object} object Original rules. 356 * @param {Object} source user-defined rules. 357 * @param {Array} nativekeys Supported component name. 358 * @return {Array} Merged object. 359 */ 360function merge(object, source, nativekeys) { 361 const keys = Object.keys(source); 362 for (let i = 0; i < keys.length; i++) { 363 const key = keys[i]; 364 const value = source[key]; 365 let target = object[key]; 366 if (target != null && !nativekeys.includes(key)) { 367 console.error( 368 `\u001b[31mError in .literc.js: \n` + 369 `Attribute '${key}' already exists and cannot be modified\u001b[39m`, 370 ); 371 process.exit(1); 372 } else if (isType.isObject(value)) { 373 target = isType.isObject(target) ? target : {}; 374 object[key] = merge(target, value, nativekeys); 375 } else if (!(isType.isNull(value) || isType.isUndefined(value))) { 376 object[key] = value; 377 } 378 } 379 return object; 380} 381 382module.exports = { 383 liteNativeTag: liteNativeTag, 384 liteCommonTag: liteCommonTag, 385}; 386