• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
16const path = require('path')
17const { Compilation } = require('webpack')
18
19class AfterEmitPlugin {
20  constructor() {
21  }
22
23  apply(compiler) {
24    compiler.hooks.thisCompilation.tap('card', (compilation) => {
25      compilation.hooks.processAssets.tapAsync(
26        {
27          name: 'MyPlugin',
28          stage: Compilation.PROCESS_ASSETS_STAGE_REPOR,
29        },
30        (assets, back) => {
31          const keys = Object.keys(assets)
32          keys.forEach(key => {
33            if ('./' + process.env.abilityType + '.js' !== key) {
34              sourceChange(key, assets, compilation);
35            }
36          });
37          back && back();
38        }
39      );
40    })
41  }
42}
43
44function sourceChange(key, assets, compilation) {
45  try {
46    const extName = path.extname(key);
47    if (extName === '.js') {
48      const jsonOut = {};
49      const source = assets[key].source();
50      const str = source.match(/card_start((\s||\S)*)card_end/)[1];
51      const array = str.split('\n');
52      array.forEach(element => {
53        elementChange(element, source, jsonOut);
54      });
55      const assetReplace = {};
56      Object.keys(jsonOut).forEach(function (jsonOutKey) {
57        toAddJson(assetReplace, jsonOutKey, JSON.parse(jsonOut[jsonOutKey]), compilation, path.join(process.env.projectPath, key));
58      });
59      assets[key.replace(extName, '') + '.json'] = {
60        source: function () {
61          return JSON.stringify(assetReplace, null, 2);
62        },
63        size: function () {
64          return JSON.stringify(assetReplace, null, 2).size;
65        }
66      }
67      delete assets[key];
68    }
69  } catch (e) {
70    compilation.errors.push({ message: 'errorStartERROR File:' + key +
71      '\n' + ` ${e.message}` + 'errorEnd' });
72  }
73}
74
75function elementChange(element, source, jsonOut) {
76  if (element.trim() === '' || element.trim() === '//') {
77  } else {
78    const key = element.match(/var ((\s||\S)*) =/)[1];
79    const value = element.match(/"((\s||\S)*)"/)[1];
80    const replaceSource = source.replace(element, '').toString();
81    const partStart = replaceSource.indexOf(value);
82    const subSource = replaceSource.substr(partStart);
83    const partEnd = subSource.indexOf('/***/ })');
84    let out = subSource.substr(0, partEnd).match(/module\.exports \= ((\s||\S)*)/)[1].trim();
85    if (out.indexOf('JSON.parse(') === 0) {
86      out = JSON.stringify(eval(out));
87    }
88    if (out.substr(out.length - 1, 1) === ';') {
89      out = out.substr(0, out.length - 1);
90    }
91    jsonOut[key] = out;
92  }
93}
94
95function toAddJson(assetReplace, key, value, compilation, sourceKey) {
96  assetReplace['template'] = assetReplace['template'] || {};
97  assetReplace['styles'] = assetReplace['styles'] || {};
98  assetReplace['data'] = assetReplace['data'] || {};
99  assetReplace['actions'] = assetReplace['actions'] || {};
100  assetReplace['apiVersion'] = assetReplace['apiVersion'] || {};
101
102  switch(key) {
103    case 'card_template':
104      assetReplace['template'] = value;
105      break;
106    case 'card_style':
107      assetReplace['styles'] = value;
108      break;
109    case 'card_json':
110      if (value) {
111        if (value.data) {
112          assetReplace['data'] = validateData(value.data, compilation, sourceKey);
113        }
114        if (value.actions) {
115          assetReplace['actions'] = processActions(value.actions, compilation, sourceKey);
116        }
117        if (value.apiVersion) {
118          assetReplace['apiVersion'] = validateData(value.apiVersion, compilation, sourceKey);
119        }
120        if (value.props) {
121          assetReplace['props'] = replacePropsArray(value.propsValue, compilation, sourceKey);
122        }
123      }
124      break;
125    default:
126      addElement(assetReplace, key, value, compilation, sourceKey);
127      break;
128  }
129}
130
131function addElement(assetReplace, key, value, compilation, sourceKey) {
132  const keyName = key.substr(key.lastIndexOf('_') + 1, key.length - key.lastIndexOf('_') + 1);
133  assetReplace[keyName] = assetReplace[keyName] || {};
134  assetReplace[keyName]['template'] = assetReplace[keyName]['template'] || {};
135  assetReplace[keyName]['styles'] = assetReplace[keyName]['styles'] || {};
136  assetReplace[keyName]['data'] = assetReplace[keyName]['data'] || {};
137  assetReplace[keyName]['actions'] = assetReplace[keyName]['actions'] || {};
138  assetReplace[keyName]['apiVersion'] = assetReplace[keyName]['apiVersion'] || {};
139
140  switch(key.replace(keyName, '')) {
141    case 'card_element_template_':
142      assetReplace[keyName]['template'] = value;
143      break;
144    case 'card_element_style_':
145      assetReplace[keyName]['styles'] = value;
146      break;
147    case 'card_element_json_':
148      if (value) {
149        if (value.data) {
150          assetReplace[keyName]['data'] = validateData(value.data, compilation, sourceKey);
151        }
152        if (value.actions) {
153          assetReplace[keyName]['actions'] = processActions(value.actions, compilation, sourceKey);
154        }
155        if (value.apiVersion) {
156          assetReplace[keyName]['apiVersion'] = validateData(value.apiVersion, compilation, sourceKey);
157        }
158        if (value.props) {
159          assetReplace[keyName]['props'] = replacePropsArray(value.propsValue, compilation, sourceKey);
160        }
161      }
162      break;
163    default:
164      break;
165  }
166}
167
168function replacePropsArray(propsValue, _this, key) {
169  if (!propsValue) {
170    return propsValue;
171  }
172  if (Array.isArray(propsValue)) {
173    const propsObject = {};
174    propsValue.forEach(item => {
175      if (typeof(item) !== 'string') {
176        _this.warnings.push({message: 'warnStartWARNING File:' + key +
177          '\n' + `The props value type should be 'string', not '${typeof(item)}' in props array in custom elements.` + 'warnEnd'});
178      }
179      propsObject[item] = { 'default': '' };
180    });
181    propsValue = propsObject;
182  } else if (Object.prototype.toString.call(propsValue) === '[object Object]') {
183    Object.keys(propsValue).forEach(item => {
184      if (Object.prototype.toString.call(propsValue[item]) !== '[object Object]') {
185        _this.warnings.push({message: 'warnStartWARNING File:' + key +
186          '\n' + 'The props default value type can only be Object in custom elements.' + 'warnEnd'});
187      }
188      if (!propsValue[item].hasOwnProperty('default')) {
189        propsValue[item] = { 'default': '' }
190      }
191    });
192  } else {
193    _this.warnings.push({message: 'warnStartWARNING File:' + key +
194      '\n' + 'The props type can only be Array or Object in custom elements.' + 'warnEnd'});
195  }
196  return propsValue;
197}
198
199function processActions(actionsValue, _this, key) {
200  if (Object.prototype.toString.call(actionsValue) === '[object Object]') {
201    Object.keys(actionsValue).forEach(item => {
202      if (actionsValue[item].method) {
203        if (typeof(actionsValue[item].method) === 'string') {
204          if (actionsValue[item].method.toLowerCase() !== actionsValue[item].method) {
205            _this.warnings.push({message: 'warnStartWARNING File:' + key +
206              '\n' + `WARNING: The key method '${actionsValue[item].method}' in the actions don't support uppercase letters.` + 'warnEnd'});
207            actionsValue[item].method = actionsValue[item].method.toLowerCase();
208          }
209        } else {
210          _this.warnings.push({message: 'warnStartWARNING File:' + key +
211            '\n' + `WARNING: The key method type in the actions should be 'string', not '${typeof(actionsValue[item].method)}'.` + 'warnEnd'});
212        }
213      }
214    })
215  } else {
216    if (actionsValue) {
217      _this.warnings.push({message: 'warnStartWARNING File:' + key +
218        '\n' + 'WARNING: The actions value type can only be Object.' + 'warnEnd'});
219    }
220  }
221  return actionsValue;
222}
223
224function validateData(dataValue, _this, key) {
225  if (dataValue && Object.prototype.toString.call(dataValue) !== '[object Object]') {
226    _this.warnings.push({message: 'warnStartWARNING File:' + key +
227      '\n' + 'WARNING: The data value type can only be Object.' + 'warnEnd'});
228  }
229  return dataValue;
230}
231
232module.exports = {
233  AfterEmitPlugin: AfterEmitPlugin
234}