hcordova 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +204 -0
- package/README.md +346 -0
- package/bin/hcordova +27 -0
- package/package.json +39 -0
- package/src/base-cli.js +1181 -0
- package/src/utils/DependencyChecker.js +382 -0
- package/src/utils/PlatformProject.js +452 -0
- package/src/utils/PluginConfigParser.js +408 -0
- package/src/utils/PluginDownloader.js +181 -0
- package/src/utils/PluginHandler.js +1097 -0
- package/src/utils/VariableValidator.js +369 -0
- package/src/utils/args-processor.js +79 -0
- package/templates/project/AppScope/app.json5 +10 -0
- package/templates/project/AppScope/resources/base/element/string.json +8 -0
- package/templates/project/AppScope/resources/base/media/background.png +0 -0
- package/templates/project/AppScope/resources/base/media/foreground.png +0 -0
- package/templates/project/AppScope/resources/base/media/layered_image.json +7 -0
- package/templates/project/build-profile.json5 +46 -0
- package/templates/project/code-linter.json5 +32 -0
- package/templates/project/entry/build-profile.json5 +28 -0
- package/templates/project/entry/hvigorfile.ts +6 -0
- package/templates/project/entry/obfuscation-rules.txt +23 -0
- package/templates/project/entry/oh-package.json5 +12 -0
- package/templates/project/entry/src/main/ets/entryability/EntryAbility.ets +62 -0
- package/templates/project/entry/src/main/ets/entrybackupability/EntryBackupAbility.ets +32 -0
- package/templates/project/entry/src/main/ets/pages/Index.ets +40 -0
- package/templates/project/entry/src/main/module.json5 +52 -0
- package/templates/project/entry/src/main/resources/base/element/color.json +8 -0
- package/templates/project/entry/src/main/resources/base/element/float.json +8 -0
- package/templates/project/entry/src/main/resources/base/element/string.json +16 -0
- package/templates/project/entry/src/main/resources/base/media/background.png +0 -0
- package/templates/project/entry/src/main/resources/base/media/foreground.png +0 -0
- package/templates/project/entry/src/main/resources/base/media/layered_image.json +7 -0
- package/templates/project/entry/src/main/resources/base/media/startIcon.png +0 -0
- package/templates/project/entry/src/main/resources/base/profile/backup_config.json +3 -0
- package/templates/project/entry/src/main/resources/base/profile/main_pages.json +5 -0
- package/templates/project/entry/src/main/resources/dark/element/color.json +8 -0
- package/templates/project/entry/src/main/resources/rawfile/config.xml +26 -0
- package/templates/project/entry/src/main/resources/rawfile/www/cordova.js +1925 -0
- package/templates/project/entry/src/main/resources/rawfile/www/css/index.css +158 -0
- package/templates/project/entry/src/main/resources/rawfile/www/img/cordova.png +0 -0
- package/templates/project/entry/src/main/resources/rawfile/www/img/logo.png +0 -0
- package/templates/project/entry/src/main/resources/rawfile/www/index.html +110 -0
- package/templates/project/entry/src/main/resources/rawfile/www/js/index.js +68 -0
- package/templates/project/entry/src/mock/mock-config.json5 +2 -0
- package/templates/project/entry/src/ohosTest/ets/test/Ability.test.ets +35 -0
- package/templates/project/entry/src/ohosTest/ets/test/List.test.ets +5 -0
- package/templates/project/entry/src/ohosTest/module.json5 +13 -0
- package/templates/project/entry/src/test/List.test.ets +5 -0
- package/templates/project/entry/src/test/LocalUnit.test.ets +33 -0
- package/templates/project/hvigor/hvigor-config.json5 +22 -0
- package/templates/project/hvigorfile.ts +6 -0
- package/templates/project/local.properties +9 -0
- package/templates/project/oh-package-lock.json5 +27 -0
- package/templates/project/oh-package.json5 +10 -0
|
@@ -0,0 +1,382 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) 2025 Huawei Device, Inc. Ltd. and <马弓手>.
|
|
3
|
+
*
|
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
* you may not use this file except in compliance with the License.
|
|
6
|
+
* You may obtain a copy of the License at
|
|
7
|
+
*
|
|
8
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
*
|
|
10
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
* See the License for the specific language governing permissions and
|
|
14
|
+
* limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
class DependencyChecker {
|
|
18
|
+
constructor(api) {
|
|
19
|
+
this.api = api;
|
|
20
|
+
this.events = api.events;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* 检查插件依赖是否满足要求
|
|
25
|
+
* @param {Object} pluginPackage - 插件的package.json内容
|
|
26
|
+
* @param {Object} projectInfo - 项目信息
|
|
27
|
+
* @returns {Object} 检查结果
|
|
28
|
+
*/
|
|
29
|
+
checkDependencies(pluginPackage, projectInfo) {
|
|
30
|
+
this.events.emit('verbose', `Checking dependencies for plugin: ${pluginPackage.name}`);
|
|
31
|
+
|
|
32
|
+
const results = {
|
|
33
|
+
satisfied: true,
|
|
34
|
+
errors: [],
|
|
35
|
+
warnings: []
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
// 检查平台支持
|
|
39
|
+
if (!this._checkPlatformSupport(pluginPackage, results)) {
|
|
40
|
+
return results;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// 检查引擎依赖
|
|
44
|
+
this._checkEngineDependencies(pluginPackage, projectInfo, results);
|
|
45
|
+
|
|
46
|
+
return results;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* 检查平台支持
|
|
51
|
+
*/
|
|
52
|
+
_checkPlatformSupport(pluginPackage, results) {
|
|
53
|
+
const cordovaConfig = pluginPackage.cordova;
|
|
54
|
+
|
|
55
|
+
if (!cordovaConfig || !cordovaConfig.platforms) {
|
|
56
|
+
results.warnings.push(`Plugin ${pluginPackage.name} does not specify supported platforms in cordova.platforms`);
|
|
57
|
+
return true;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const supportedPlatforms = cordovaConfig.platforms;
|
|
61
|
+
|
|
62
|
+
// 检查是否支持鸿蒙平台
|
|
63
|
+
const isSupported = supportedPlatforms.includes('ohos') ||
|
|
64
|
+
supportedPlatforms.includes('harmonyos') ||
|
|
65
|
+
supportedPlatforms.includes('harmony') ||
|
|
66
|
+
supportedPlatforms.includes('openharmony');
|
|
67
|
+
|
|
68
|
+
if (!isSupported) {
|
|
69
|
+
results.satisfied = false;
|
|
70
|
+
results.errors.push(
|
|
71
|
+
`Plugin ${pluginPackage.name} does not support HarmonyOS platform. ` +
|
|
72
|
+
`Supported platforms: ${supportedPlatforms.join(', ')}`
|
|
73
|
+
);
|
|
74
|
+
return false;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
this.events.emit('verbose', `Plugin ${pluginPackage.name} supports HarmonyOS platform`);
|
|
78
|
+
return true;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* 检查引擎依赖
|
|
83
|
+
*/
|
|
84
|
+
_checkEngineDependencies(pluginPackage, projectInfo, results) {
|
|
85
|
+
const engines = pluginPackage.engines;
|
|
86
|
+
|
|
87
|
+
if (!engines) {
|
|
88
|
+
this.events.emit('verbose', `No engine dependencies specified for plugin ${pluginPackage.name}`);
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// 检查 cordovaDependencies
|
|
93
|
+
if (engines.cordovaDependencies) {
|
|
94
|
+
this._checkCordovaVersionDependencies(engines.cordovaDependencies, pluginPackage, projectInfo, results);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// 检查平台特定依赖
|
|
98
|
+
if (engines['cordova-openharmony']) {
|
|
99
|
+
this._checkPlatformEngine('cordova-openharmony', engines['cordova-openharmony'], projectInfo, results);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// 检查Node.js版本
|
|
103
|
+
if (engines.node) {
|
|
104
|
+
this._checkNodeVersion(engines.node, results);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// 检查npm版本
|
|
108
|
+
if (engines.npm) {
|
|
109
|
+
this._checkNpmVersion(engines.npm, results);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* 检查Cordova版本依赖
|
|
115
|
+
*/
|
|
116
|
+
_checkCordovaVersionDependencies(cordovaDependencies, pluginPackage, projectInfo, results) {
|
|
117
|
+
const pluginVersion = pluginPackage.version;
|
|
118
|
+
|
|
119
|
+
// 查找适用于当前插件版本的依赖规则
|
|
120
|
+
let dependencyRules = null;
|
|
121
|
+
|
|
122
|
+
// 按版本号排序,找到适用的规则
|
|
123
|
+
const versions = Object.keys(cordovaDependencies).sort(this._versionCompareReverse);
|
|
124
|
+
for (const version of versions) {
|
|
125
|
+
if (this._versionSatisfies(pluginVersion, version)) {
|
|
126
|
+
dependencyRules = cordovaDependencies[version];
|
|
127
|
+
break;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// 如果没有找到特定版本的规则,使用默认规则
|
|
132
|
+
if (!dependencyRules && cordovaDependencies) {
|
|
133
|
+
dependencyRules = cordovaDependencies;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
if (dependencyRules) {
|
|
137
|
+
this.events.emit('verbose', `Found dependency rules for plugin version ${pluginVersion}`);
|
|
138
|
+
|
|
139
|
+
// 检查各个依赖
|
|
140
|
+
for (const [engine, requirement] of Object.entries(dependencyRules)) {
|
|
141
|
+
this._checkPlatformEngine(engine, requirement, projectInfo, results);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* 检查平台引擎版本
|
|
148
|
+
*/
|
|
149
|
+
_checkPlatformEngine(engine, requirement, projectInfo, results) {
|
|
150
|
+
let currentVersion;
|
|
151
|
+
|
|
152
|
+
switch (engine) {
|
|
153
|
+
case 'cordova-openharmony':
|
|
154
|
+
case 'cordova-harmonyos':
|
|
155
|
+
case 'ohos':
|
|
156
|
+
case 'harmony':
|
|
157
|
+
case 'harmonyos':
|
|
158
|
+
currentVersion = projectInfo.cordovaHarmonyVersion;
|
|
159
|
+
break;
|
|
160
|
+
case 'cordova':
|
|
161
|
+
currentVersion = projectInfo.cordovaVersion;
|
|
162
|
+
break;
|
|
163
|
+
default:
|
|
164
|
+
results.warnings.push(`Unknown engine dependency: ${engine}`);
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
if (!currentVersion) {
|
|
169
|
+
results.warnings.push(`Current version of ${engine} is not available`);
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
if (!this._versionSatisfies(currentVersion, requirement)) {
|
|
174
|
+
results.satisfied = false;
|
|
175
|
+
results.errors.push(
|
|
176
|
+
`Plugin requires ${engine} ${requirement}, but current version is ${currentVersion}`
|
|
177
|
+
);
|
|
178
|
+
} else {
|
|
179
|
+
this.events.emit('verbose', `✓ ${engine} version ${currentVersion} satisfies requirement ${requirement}`);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* 检查Node.js版本
|
|
185
|
+
*/
|
|
186
|
+
_checkNodeVersion(requirement, results) {
|
|
187
|
+
const currentNodeVersion = process.version.replace('v', '');
|
|
188
|
+
|
|
189
|
+
if (!this._versionSatisfies(currentNodeVersion, requirement)) {
|
|
190
|
+
results.warnings.push(
|
|
191
|
+
`Plugin recommends Node.js ${requirement}, but current version is ${currentNodeVersion}`
|
|
192
|
+
);
|
|
193
|
+
} else {
|
|
194
|
+
this.events.emit('verbose', `✓ Node.js version ${currentNodeVersion} satisfies requirement ${requirement}`);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* 检查npm版本
|
|
200
|
+
*/
|
|
201
|
+
_checkNpmVersion(requirement, results) {
|
|
202
|
+
try {
|
|
203
|
+
const { execSync } = require('child_process');
|
|
204
|
+
const npmVersion = execSync('npm --version', { encoding: 'utf8' }).trim();
|
|
205
|
+
|
|
206
|
+
if (!this._versionSatisfies(npmVersion, requirement)) {
|
|
207
|
+
results.warnings.push(
|
|
208
|
+
`Plugin recommends npm ${requirement}, but current version is ${npmVersion}`
|
|
209
|
+
);
|
|
210
|
+
} else {
|
|
211
|
+
this.events.emit('verbose', `✓ npm version ${npmVersion} satisfies requirement ${requirement}`);
|
|
212
|
+
}
|
|
213
|
+
} catch (error) {
|
|
214
|
+
results.warnings.push(`Could not check npm version: ${error.message}`);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* 简单的版本比较函数
|
|
220
|
+
* @param {string} version - 当前版本
|
|
221
|
+
* @param {string} requirement - 版本要求
|
|
222
|
+
* @returns {boolean} 是否满足要求
|
|
223
|
+
*/
|
|
224
|
+
_versionSatisfies(version, requirement) {
|
|
225
|
+
if (!version || !requirement) {
|
|
226
|
+
return false;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
// 处理通配符
|
|
230
|
+
if (requirement === '*' || requirement === 'latest' || requirement === '') {
|
|
231
|
+
return true;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
// 清理版本号
|
|
235
|
+
const cleanVersion = this._cleanVersion(version);
|
|
236
|
+
const cleanRequirement = this._cleanVersion(requirement);
|
|
237
|
+
|
|
238
|
+
try {
|
|
239
|
+
// 处理范围操作符
|
|
240
|
+
if (requirement.startsWith('^')) {
|
|
241
|
+
// ^1.2.3 表示 >=1.2.3 <2.0.0
|
|
242
|
+
return this._caretSatisfies(cleanVersion, cleanRequirement);
|
|
243
|
+
} else if (requirement.startsWith('~')) {
|
|
244
|
+
// ~1.2.3 表示 >=1.2.3 <1.3.0
|
|
245
|
+
return this._tildeSatisfies(cleanVersion, cleanRequirement);
|
|
246
|
+
} else if (requirement.startsWith('>=')) {
|
|
247
|
+
// >=1.2.3
|
|
248
|
+
return this._compareVersions(cleanVersion, cleanRequirement) >= 0;
|
|
249
|
+
} else if (requirement.startsWith('<=')) {
|
|
250
|
+
// <=1.2.3
|
|
251
|
+
return this._compareVersions(cleanVersion, cleanRequirement) <= 0;
|
|
252
|
+
} else if (requirement.startsWith('>')) {
|
|
253
|
+
// >1.2.3
|
|
254
|
+
return this._compareVersions(cleanVersion, cleanRequirement) > 0;
|
|
255
|
+
} else if (requirement.startsWith('<')) {
|
|
256
|
+
// <1.2.3
|
|
257
|
+
return this._compareVersions(cleanVersion, cleanRequirement) < 0;
|
|
258
|
+
} else {
|
|
259
|
+
// 精确匹配 1.2.3
|
|
260
|
+
return this._compareVersions(cleanVersion, cleanRequirement) === 0;
|
|
261
|
+
}
|
|
262
|
+
} catch (error) {
|
|
263
|
+
// 如果版本比较失败,默认返回 true 避免阻塞安装
|
|
264
|
+
this.events.emit('verbose', `Version comparison failed: ${version} vs ${requirement}, defaulting to true`);
|
|
265
|
+
return true;
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
/**
|
|
270
|
+
* 处理 ^ 操作符
|
|
271
|
+
*/
|
|
272
|
+
_caretSatisfies(version, requirement) {
|
|
273
|
+
const versionParts = version.split('.').map(Number);
|
|
274
|
+
const reqParts = requirement.split('.').map(Number);
|
|
275
|
+
|
|
276
|
+
// 主版本必须相等
|
|
277
|
+
if (versionParts[0] !== reqParts[0]) {
|
|
278
|
+
return false;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
// 次版本和修订版本必须 >= 要求版本
|
|
282
|
+
return this._compareVersions(version, requirement) >= 0;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
/**
|
|
286
|
+
* 处理 ~ 操作符
|
|
287
|
+
*/
|
|
288
|
+
_tildeSatisfies(version, requirement) {
|
|
289
|
+
const versionParts = version.split('.').map(Number);
|
|
290
|
+
const reqParts = requirement.split('.').map(Number);
|
|
291
|
+
|
|
292
|
+
// 主版本和次版本必须相等
|
|
293
|
+
if (versionParts[0] !== reqParts[0] || versionParts[1] !== reqParts[1]) {
|
|
294
|
+
return false;
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
// 修订版本必须 >= 要求版本
|
|
298
|
+
return this._compareVersions(version, requirement) >= 0;
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
/**
|
|
302
|
+
* 比较两个版本号
|
|
303
|
+
* @param {string} v1 - 版本1
|
|
304
|
+
* @param {string} v2 - 版本2
|
|
305
|
+
* @returns {number} -1: v1 < v2, 0: v1 = v2, 1: v1 > v2
|
|
306
|
+
*/
|
|
307
|
+
_compareVersions(v1, v2) {
|
|
308
|
+
const parts1 = v1.split('.').map(part => {
|
|
309
|
+
const num = parseInt(part, 10);
|
|
310
|
+
return isNaN(num) ? 0 : num;
|
|
311
|
+
});
|
|
312
|
+
const parts2 = v2.split('.').map(part => {
|
|
313
|
+
const num = parseInt(part, 10);
|
|
314
|
+
return isNaN(num) ? 0 : num;
|
|
315
|
+
});
|
|
316
|
+
|
|
317
|
+
const maxLength = Math.max(parts1.length, parts2.length);
|
|
318
|
+
|
|
319
|
+
for (let i = 0; i < maxLength; i++) {
|
|
320
|
+
const p1 = parts1[i] || 0;
|
|
321
|
+
const p2 = parts2[i] || 0;
|
|
322
|
+
|
|
323
|
+
if (p1 < p2) return -1;
|
|
324
|
+
if (p1 > p2) return 1;
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
return 0;
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
/**
|
|
331
|
+
* 反向版本比较(用于排序)
|
|
332
|
+
*/
|
|
333
|
+
_versionCompareReverse(a, b) {
|
|
334
|
+
return -this._compareVersions(a, b);
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
/**
|
|
338
|
+
* 清理版本号,移除操作符
|
|
339
|
+
*/
|
|
340
|
+
_cleanVersion(version) {
|
|
341
|
+
// 移除 ^ ~ > >= < <= 等操作符
|
|
342
|
+
return version.replace(/[\^~><=]/g, '');
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
/**
|
|
346
|
+
* 获取项目信息
|
|
347
|
+
*/
|
|
348
|
+
getProjectInfo(cordovaHarmonyVersion) {
|
|
349
|
+
return {
|
|
350
|
+
cordovaVersion: this._getCordovaVersion(),
|
|
351
|
+
cordovaHarmonyVersion: cordovaHarmonyVersion,
|
|
352
|
+
nodeVersion: process.version.replace('v', ''),
|
|
353
|
+
npmVersion: this._getNpmVersion()
|
|
354
|
+
};
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
/**
|
|
358
|
+
* 获取Cordova版本
|
|
359
|
+
*/
|
|
360
|
+
_getCordovaVersion() {
|
|
361
|
+
try {
|
|
362
|
+
const { execSync } = require('child_process');
|
|
363
|
+
return execSync('cordova --version', { encoding: 'utf8' }).trim();
|
|
364
|
+
} catch (error) {
|
|
365
|
+
return 'unknown';
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
/**
|
|
370
|
+
* 获取npm版本
|
|
371
|
+
*/
|
|
372
|
+
_getNpmVersion() {
|
|
373
|
+
try {
|
|
374
|
+
const { execSync } = require('child_process');
|
|
375
|
+
return execSync('npm --version', { encoding: 'utf8' }).trim();
|
|
376
|
+
} catch (error) {
|
|
377
|
+
return 'unknown';
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
module.exports = DependencyChecker;
|