@arkts/image-manager 0.4.3 → 0.5.1

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/dist/index.mjs CHANGED
@@ -1,1288 +1,1561 @@
1
- import axios, { AxiosError } from "axios";
2
- import satisfies from "semver/functions/satisfies";
3
1
  import INI from "ini";
4
- import mitt from "mitt";
5
- import progress from "progress-stream";
2
+ import { fromByteArray } from "base64-js";
3
+ import { RelativePattern, WriteableFlags, createNodeFileSystem } from "vscode-fs";
6
4
 
7
5
  //#region package.json
8
- var version = "0.4.3";
6
+ var version = "0.5.1";
9
7
 
10
8
  //#endregion
11
- //#region src/devices/list.ts
12
- let DevModel = /* @__PURE__ */ function(DevModel) {
13
- DevModel["MCHEMU_AL00CN"] = "MCHEMU-AL00CN";
14
- DevModel["PHEMU_FD00"] = "PHEMU-FD00";
15
- DevModel["PHEMU_FD01"] = "PHEMU-FD01";
16
- DevModel["PHEMU_FD02"] = "PHEMU-FD02";
17
- DevModel["PHEMU_FD06"] = "PHEMU-FD06";
18
- DevModel["PCEMU_FD00"] = "PCEMU-FD00";
19
- DevModel["PCEMU_FD05"] = "PCEMU-FD05";
20
- return DevModel;
21
- }({});
22
-
23
- //#endregion
24
- //#region src/emulator-config.ts
25
- let BaseEmulatorConfigItem;
26
- (function(_BaseEmulatorConfigItem) {
27
- function is(value) {
28
- return typeof value === "object" && value !== null && "name" in value && typeof value.name === "string" && "deviceType" in value && typeof value.deviceType === "string" && "api" in value && typeof value.api === "number";
29
- }
30
- _BaseEmulatorConfigItem.is = is;
31
- })(BaseEmulatorConfigItem || (BaseEmulatorConfigItem = {}));
32
- let ParentEmulatorConfigItem;
33
- (function(_ParentEmulatorConfigItem) {
34
- function is(value) {
35
- return BaseEmulatorConfigItem.is(value) && "resolutionWidth" in value && typeof value.resolutionWidth === "number" && "resolutionHeight" in value && typeof value.resolutionHeight === "number" && "physicalWidth" in value && typeof value.physicalWidth === "number" && "physicalHeight" in value && typeof value.physicalHeight === "number" && "diagonalSize" in value && typeof value.diagonalSize === "number" && "density" in value && typeof value.density === "number" && "memoryRamSize" in value && typeof value.memoryRamSize === "number" && "datadiskSize" in value && typeof value.datadiskSize === "number" && "procNumber" in value && typeof value.procNumber === "number" && "api" in value && typeof value.api === "number";
36
- }
37
- _ParentEmulatorConfigItem.is = is;
38
- })(ParentEmulatorConfigItem || (ParentEmulatorConfigItem = {}));
39
- let PhoneAllEmulatorConfigItem;
40
- (function(_PhoneAllEmulatorConfigItem) {
41
- function is(value) {
42
- return ParentEmulatorConfigItem.is(value);
9
+ //#region src/common/serializable-content.ts
10
+ var SerializableContentImpl = class {
11
+ constructor(imageManager, content) {
12
+ this.imageManager = imageManager;
13
+ this.content = content;
43
14
  }
44
- _PhoneAllEmulatorConfigItem.is = is;
45
- })(PhoneAllEmulatorConfigItem || (PhoneAllEmulatorConfigItem = {}));
46
- let GroupPhoneAllEmulatorConfigItem;
47
- (function(_GroupPhoneAllEmulatorConfigItem) {
48
- function is(value) {
49
- return BaseEmulatorConfigItem.is(value) && "children" in value && Array.isArray(value.children) && value.children.every(PhoneAllEmulatorConfigItem.is);
15
+ getImageManager() {
16
+ return this.imageManager;
50
17
  }
51
- _GroupPhoneAllEmulatorConfigItem.is = is;
52
- })(GroupPhoneAllEmulatorConfigItem || (GroupPhoneAllEmulatorConfigItem = {}));
53
- let PCAllEmulatorConfigItem;
54
- (function(_PCAllEmulatorConfigItem) {
55
- function is(value) {
56
- return ParentEmulatorConfigItem.is(value);
18
+ getContent() {
19
+ return this.content;
57
20
  }
58
- _PCAllEmulatorConfigItem.is = is;
59
- })(PCAllEmulatorConfigItem || (PCAllEmulatorConfigItem = {}));
60
- let GroupPCAllEmulatorConfigItem;
61
- (function(_GroupPCAllEmulatorConfigItem) {
62
- function is(value) {
63
- return BaseEmulatorConfigItem.is(value) && "children" in value && Array.isArray(value.children) && value.children.every(PCAllEmulatorConfigItem.is);
21
+ toJSON() {
22
+ return {
23
+ imageManager: this.getImageManager().toJSON(),
24
+ content: this.getContent()
25
+ };
64
26
  }
65
- _GroupPCAllEmulatorConfigItem.is = is;
66
- })(GroupPCAllEmulatorConfigItem || (GroupPCAllEmulatorConfigItem = {}));
27
+ };
67
28
 
68
29
  //#endregion
69
- //#region src/errors/deploy-error.ts
70
- var DeployError = class extends Error {
71
- constructor(code, message, cause) {
72
- super(message, { cause });
73
- this.code = code;
74
- this.message = message;
75
- this.cause = cause;
30
+ //#region src/common/serializable-file.ts
31
+ var SerializableFileImpl = class extends SerializableContentImpl {
32
+ constructor(imageManager, content) {
33
+ super(imageManager, content);
34
+ this.imageManager = imageManager;
35
+ this.content = content;
36
+ }
37
+ getImageManager() {
38
+ return this.imageManager;
76
39
  }
77
- getCode() {
78
- return this.code;
40
+ async writeToFileSystem(uri) {
41
+ const { adapter: { fs, dirname } } = this.imageManager.getOptions();
42
+ const directoryUri = dirname(uri);
43
+ if (!await fs.exists(directoryUri)) await fs.createDirectory(directoryUri);
44
+ const serializedContent = await this.serialize();
45
+ const encodedContent = new TextEncoder().encode(serializedContent);
46
+ await fs.writeFile(uri, encodedContent);
47
+ }
48
+ toJSON() {
49
+ return {
50
+ imageManager: this.getImageManager().toJSON(),
51
+ content: this.getContent()
52
+ };
79
53
  }
80
54
  };
81
- (function(_DeployError) {
82
- _DeployError.Code = /* @__PURE__ */ function(Code) {
83
- Code["DEVICE_ALREADY_DEPLOYED"] = "DEVICE_ALREADY_DEPLOYED";
84
- Code["LIST_JSON_NOT_AN_ARRAY"] = "LIST_JSON_NOT_AN_ARRAY";
85
- Code["CATCHED_ERROR"] = "CATCHED_ERROR";
86
- Code["MAYBE_OPENED_DEVICE_MANAGER_IN_DEVECO_STUDIO"] = "MAYBE_OPENED_DEVICE_MANAGER_IN_DEVECO_STUDIO";
87
- Code["SYMLINK_SDK_PATH_EXISTS"] = "SYMLINK_SDK_PATH_EXISTS";
88
- return Code;
89
- }({});
90
- })(DeployError || (DeployError = {}));
91
55
 
92
56
  //#endregion
93
- //#region src/errors/request-url-error.ts
94
- var RequestUrlError = class extends Error {
95
- constructor(message, code, cause) {
96
- super(message, { cause });
97
- this.message = message;
98
- this.code = code;
99
- this.cause = cause;
57
+ //#region src/configs/config-ini/config-ini.ts
58
+ let ConfigIniFile;
59
+ (function(_ConfigIniFile) {
60
+ function is(value) {
61
+ return value instanceof ConfigIniFileImpl;
62
+ }
63
+ _ConfigIniFile.is = is;
64
+ })(ConfigIniFile || (ConfigIniFile = {}));
65
+ var ConfigIniFileImpl = class extends SerializableFileImpl {
66
+ constructor(device, configIniFilePath, content) {
67
+ super(device.getImageManager(), content);
68
+ this.device = device;
69
+ this.configIniFilePath = configIniFilePath;
70
+ this.content = content;
71
+ }
72
+ getDevice() {
73
+ return this.device;
74
+ }
75
+ static getFileUri(device) {
76
+ const { deployedPath, adapter: { join } } = device.getImageManager().getOptions();
77
+ return join(deployedPath, device.getListsFileItem().getContent().name, "config.ini");
78
+ }
79
+ static async safeReadAndParse(device) {
80
+ const { adapter: { fs } } = device.getImageManager().getOptions();
81
+ try {
82
+ const configIniFileContent = await fs.readFile(this.getFileUri(device)).then((buffer) => buffer.toString(), () => void 0);
83
+ if (!configIniFileContent?.length) return;
84
+ return INI.parse(configIniFileContent);
85
+ } catch {}
86
+ }
87
+ getFileUri() {
88
+ return this.configIniFilePath;
89
+ }
90
+ async serialize() {
91
+ return INI.stringify(Object.fromEntries(Object.entries(this.getContent()).filter(([key, value]) => {
92
+ return value !== void 0 && key.length > 0;
93
+ })));
94
+ }
95
+ async write() {
96
+ return this.writeToFileSystem(this.getFileUri());
97
+ }
98
+ toJSON() {
99
+ return {
100
+ ...super.toJSON(),
101
+ fileUri: this.getFileUri().toJSON()
102
+ };
100
103
  }
101
104
  };
102
105
 
103
106
  //#endregion
104
- //#region src/product-config.ts
105
- let ProductConfigItem;
106
- (function(_ProductConfigItem) {
107
+ //#region src/configs/emulator/emulator-basic-item.ts
108
+ let EmulatorBasicItem;
109
+ (function(_EmulatorBasicItem) {
107
110
  function is(value) {
108
- return typeof value === "object" && value !== null && "name" in value && "screenWidth" in value && "screenHeight" in value && "screenDiagonal" in value && "screenDensity" in value && typeof value.name === "string" && typeof value.screenWidth === "string" && typeof value.screenHeight === "string" && typeof value.screenDiagonal === "string" && typeof value.screenDensity === "string";
111
+ return value instanceof EmulatorBasicItemImpl;
109
112
  }
110
- _ProductConfigItem.is = is;
111
- })(ProductConfigItem || (ProductConfigItem = {}));
112
-
113
- //#endregion
114
- //#region src/types.ts
115
- function isPhoneAllSnakecaseDeviceType(value) {
116
- return value === "phone" || value === "triplefold" || value === "widefold" || value === "foldable";
117
- }
118
- function isPCAllSnakecaseDeviceType(value) {
119
- return value === "2in1_foldable" || value === "2in1";
120
- }
121
-
122
- //#endregion
123
- //#region src/screens/base-screen.ts
124
- var BaseScreenImpl = class {
125
- constructor(options) {
126
- this.options = options;
113
+ _EmulatorBasicItem.is = is;
114
+ function isDeviceType(value) {
115
+ return value === "2in1" || value === "tablet" || value === "tv" || value === "wearable" || value === "phone";
127
116
  }
128
- getWidth() {
129
- return this.options.width;
117
+ _EmulatorBasicItem.isDeviceType = isDeviceType;
118
+ function isContent(value) {
119
+ return typeof value === "object" && value !== null && "name" in value && "deviceType" in value && isDeviceType(value.deviceType);
130
120
  }
131
- setWidth(width) {
132
- this.options.width = width;
133
- return this;
121
+ _EmulatorBasicItem.isContent = isContent;
122
+ })(EmulatorBasicItem || (EmulatorBasicItem = {}));
123
+ var EmulatorBasicItemImpl = class extends SerializableContentImpl {
124
+ constructor(emulatorFile, content) {
125
+ super(emulatorFile.getImageManager(), content);
126
+ this.emulatorFile = emulatorFile;
127
+ this.content = content;
134
128
  }
135
- getHeight() {
136
- return this.options.height;
129
+ getEmulatorFile() {
130
+ return this.emulatorFile;
137
131
  }
138
- setHeight(height) {
139
- this.options.height = height;
140
- return this;
132
+ };
133
+
134
+ //#endregion
135
+ //#region src/configs/emulator/emulator-fold-item.ts
136
+ let EmulatorFoldItem;
137
+ (function(_EmulatorFoldItem) {
138
+ function is(value) {
139
+ return value instanceof EmulatorFoldItemImpl;
141
140
  }
142
- getDiagonal() {
143
- return this.options.diagonal;
141
+ _EmulatorFoldItem.is = is;
142
+ function isDeviceType(value) {
143
+ return value === "foldable" || value === "2in1_foldable" || value === "triplefold" || value === "widefold";
144
144
  }
145
- setDiagonal(diagonal) {
146
- this.options.diagonal = diagonal;
147
- return this;
145
+ _EmulatorFoldItem.isDeviceType = isDeviceType;
146
+ function isContent(value) {
147
+ return typeof value === "object" && value !== null && "name" in value && "deviceType" in value && isDeviceType(value.deviceType);
148
148
  }
149
- toJSON() {
150
- return this.options;
149
+ _EmulatorFoldItem.isContent = isContent;
150
+ })(EmulatorFoldItem || (EmulatorFoldItem = {}));
151
+ var EmulatorFoldItemImpl = class extends SerializableContentImpl {
152
+ constructor(emulatorFile, content) {
153
+ super(emulatorFile.getImageManager(), content);
154
+ this.emulatorFile = emulatorFile;
155
+ this.content = content;
156
+ }
157
+ getEmulatorFile() {
158
+ return this.emulatorFile;
151
159
  }
152
160
  };
153
161
 
154
162
  //#endregion
155
- //#region src/screens/cover-screen.ts
156
- let CoverScreen;
157
- (function(_CoverScreen) {
163
+ //#region src/configs/emulator/emulator-triplefold-item.ts
164
+ let EmulatorTripleFoldItem;
165
+ (function(_EmulatorTripleFoldItem) {
158
166
  function is(value) {
159
- return value instanceof CoverScreenImpl;
167
+ return value instanceof EmulatorTripleFoldItemImpl;
160
168
  }
161
- _CoverScreen.is = is;
162
- })(CoverScreen || (CoverScreen = {}));
163
- var CoverScreenImpl = class extends BaseScreenImpl {
164
- constructor(options, screen) {
165
- super(options);
166
- this.options = options;
167
- this.screen = screen;
169
+ _EmulatorTripleFoldItem.is = is;
170
+ function isDeviceType(value) {
171
+ return value === "triplefold";
168
172
  }
169
- getScreen() {
170
- return this.screen;
173
+ _EmulatorTripleFoldItem.isDeviceType = isDeviceType;
174
+ function isContent(value) {
175
+ return typeof value === "object" && value !== null && "name" in value && "deviceType" in value && isDeviceType(value.deviceType);
176
+ }
177
+ _EmulatorTripleFoldItem.isContent = isContent;
178
+ })(EmulatorTripleFoldItem || (EmulatorTripleFoldItem = {}));
179
+ var EmulatorTripleFoldItemImpl = class extends SerializableContentImpl {
180
+ constructor(emulatorFile, content) {
181
+ super(emulatorFile.getImageManager(), content);
182
+ this.emulatorFile = emulatorFile;
183
+ this.content = content;
184
+ }
185
+ getEmulatorFile() {
186
+ return this.emulatorFile;
171
187
  }
172
188
  };
173
- function createCoverScreen(options, screen) {
174
- return new CoverScreenImpl(options, screen);
175
- }
176
189
 
177
190
  //#endregion
178
- //#region src/screens/double-screen.ts
179
- let DoubleScreen;
180
- (function(_DoubleScreen) {
191
+ //#region src/configs/emulator/group-item.ts
192
+ let EmulatorGroupItem;
193
+ (function(_EmulatorGroupItem) {
181
194
  function is(value) {
182
- return value instanceof DoubleScreenImpl;
183
- }
184
- _DoubleScreen.is = is;
185
- })(DoubleScreen || (DoubleScreen = {}));
186
- var DoubleScreenImpl = class extends BaseScreenImpl {
187
- constructor(options, screen) {
188
- super(options);
189
- this.options = options;
190
- this.screen = screen;
191
- }
192
- getScreen() {
193
- return this.screen;
195
+ return value instanceof EmulatorGroupItemImpl;
196
+ }
197
+ _EmulatorGroupItem.is = is;
198
+ function isContent(value) {
199
+ return typeof value === "object" && value !== null && "name" in value && "deviceType" in value && "api" in value && "children" in value && Array.isArray(value.children) && value.children.every(EmulatorFile.isItemContent);
200
+ }
201
+ _EmulatorGroupItem.isContent = isContent;
202
+ })(EmulatorGroupItem || (EmulatorGroupItem = {}));
203
+ var EmulatorGroupItemImpl = class extends SerializableContentImpl {
204
+ constructor(emulatorFile, content) {
205
+ super(emulatorFile.getImageManager(), content);
206
+ this.emulatorFile = emulatorFile;
207
+ this.content = content;
208
+ }
209
+ getEmulatorFile() {
210
+ return this.emulatorFile;
211
+ }
212
+ getChildren() {
213
+ return this.getContent().children.map((children) => {
214
+ if (EmulatorBasicItem.isContent(children)) return new EmulatorBasicItemImpl(this.emulatorFile, children);
215
+ else if (EmulatorFoldItem.isContent(children)) return new EmulatorFoldItemImpl(this.emulatorFile, children);
216
+ else if (EmulatorTripleFoldItem.isContent(children)) return new EmulatorTripleFoldItemImpl(this.emulatorFile, children);
217
+ }).filter(Boolean);
194
218
  }
195
219
  };
196
- function createDoubleScreen(options, screen) {
197
- return new DoubleScreenImpl(options, screen);
198
- }
199
220
 
200
221
  //#endregion
201
- //#region src/screens/emulator-preset.ts
202
- var EmulatorPresetImpl = class {
203
- constructor(emulatorConfigItem, screenPreset) {
204
- this.emulatorConfigItem = emulatorConfigItem;
205
- this.screenPreset = screenPreset;
222
+ //#region src/configs/emulator/emulator.ts
223
+ let EmulatorFile;
224
+ (function(_EmulatorFile) {
225
+ function is(value) {
226
+ return value instanceof EmulatorFileImpl;
227
+ }
228
+ _EmulatorFile.is = is;
229
+ function isItemContent(value) {
230
+ return typeof value === "object" && value !== null && (EmulatorBasicItem.isContent(value) || EmulatorFoldItem.isContent(value) || EmulatorTripleFoldItem.isContent(value));
231
+ }
232
+ _EmulatorFile.isItemContent = isItemContent;
233
+ function isContentItem(value) {
234
+ return typeof value === "object" && value !== null && (EmulatorGroupItem.isContent(value) || EmulatorFile.isItemContent(value));
235
+ }
236
+ _EmulatorFile.isContentItem = isContentItem;
237
+ })(EmulatorFile || (EmulatorFile = {}));
238
+ var EmulatorFileImpl = class extends SerializableFileImpl {
239
+ async serialize() {
240
+ return JSON.stringify(this.getContent(), null, 2);
241
+ }
242
+ async write() {
243
+ const { emulatorPath, adapter: { join } } = this.getImageManager().getOptions();
244
+ return this.writeToFileSystem(join(emulatorPath, "emulator.json"));
245
+ }
246
+ getItems() {
247
+ return this.getContent().map((item) => {
248
+ if (EmulatorGroupItem.isContent(item)) return new EmulatorGroupItemImpl(this, item);
249
+ else if (EmulatorFile.isItemContent(item)) {
250
+ if (EmulatorBasicItem.isContent(item)) return new EmulatorBasicItemImpl(this, item);
251
+ else if (EmulatorFoldItem.isContent(item)) return new EmulatorFoldItemImpl(this, item);
252
+ else if (EmulatorTripleFoldItem.isContent(item)) return new EmulatorTripleFoldItemImpl(this, item);
253
+ }
254
+ }).filter(Boolean);
255
+ }
256
+ findDeviceItems(options = {}) {
257
+ const items = [];
258
+ const pushDeviceItem = (item) => {
259
+ if (EmulatorBasicItem.is(item)) {
260
+ if (options.apiVersion && item.getContent().api === options.apiVersion && options.deviceType && item.getContent().deviceType === options.deviceType) items.push(item);
261
+ } else if (EmulatorFoldItem.is(item)) {
262
+ if (options.apiVersion && item.getContent().api === options.apiVersion && options.deviceType && item.getContent().deviceType === options.deviceType) items.push(item);
263
+ } else if (EmulatorTripleFoldItem.is(item)) {
264
+ if (options.apiVersion && item.getContent().api === options.apiVersion && options.deviceType && item.getContent().deviceType === options.deviceType) items.push(item);
265
+ }
266
+ };
267
+ for (const item of this.getItems()) if (EmulatorGroupItem.is(item)) for (const child of item.getChildren()) pushDeviceItem(child);
268
+ else pushDeviceItem(item);
269
+ return items;
206
270
  }
207
- getScreenPreset() {
208
- return this.screenPreset;
271
+ findDeviceItem(options = {}) {
272
+ return this.findDeviceItems(options)[0];
273
+ }
274
+ findItems(options = {}) {
275
+ return this.getItems().filter((item) => {
276
+ if (options.apiVersion && item.getContent().api === options.apiVersion && options.fullDeviceType && item.getContent().deviceType === options.fullDeviceType) return true;
277
+ return false;
278
+ });
209
279
  }
210
- getEmulatorConfig() {
211
- return this.emulatorConfigItem;
280
+ findItem(options = {}) {
281
+ return this.findItems(options)[0];
212
282
  }
213
283
  toJSON() {
214
- return { emulatorConfig: this.emulatorConfigItem };
284
+ return {
285
+ ...super.toJSON(),
286
+ items: this.getItems().map((item) => item.toJSON())
287
+ };
215
288
  }
216
289
  };
217
- function createEmulatorPreset(emulatorConfigItem, screenPreset) {
218
- return new EmulatorPresetImpl(emulatorConfigItem, screenPreset);
219
- }
220
290
 
221
291
  //#endregion
222
- //#region src/screens/outer-screen.ts
223
- let OuterScreen;
224
- (function(_OuterScreen) {
292
+ //#region src/configs/lists/item.ts
293
+ let ListsFileItem;
294
+ (function(_ListsFileItem) {
225
295
  function is(value) {
226
- return value instanceof OuterScreenImpl;
227
- }
228
- _OuterScreen.is = is;
229
- })(OuterScreen || (OuterScreen = {}));
230
- var OuterScreenImpl = class extends BaseScreenImpl {
231
- outerDoubleScreen;
232
- constructor(options, screen) {
233
- super(options);
234
- this.options = options;
235
- this.screen = screen;
236
- if (options.double) this.outerDoubleScreen = OuterDoubleScreen.is(options.double) ? options.double : createOuterDoubleScreen(options.double, this);
296
+ return value instanceof ListsFileItemImpl;
237
297
  }
238
- getScreen() {
239
- return this.screen;
298
+ _ListsFileItem.is = is;
299
+ })(ListsFileItem || (ListsFileItem = {}));
300
+ var ListsFileItemImpl = class extends SerializableContentImpl {
301
+ constructor(listsFile, content) {
302
+ super(listsFile.getImageManager(), content);
303
+ this.listsFile = listsFile;
304
+ this.content = content;
240
305
  }
241
- getOuterDoubleScreen() {
242
- return this.outerDoubleScreen;
306
+ getListsFile() {
307
+ return this.listsFile;
243
308
  }
244
- setOuterDoubleScreen(outerDoubleScreen) {
245
- this.outerDoubleScreen = OuterDoubleScreen.is(outerDoubleScreen) ? outerDoubleScreen : createOuterDoubleScreen(outerDoubleScreen, this);
246
- return this;
309
+ getContent() {
310
+ return this.content;
247
311
  }
248
312
  toJSON() {
249
313
  return {
250
- ...super.toJSON(),
251
- double: this.outerDoubleScreen?.toJSON()
314
+ imageManager: this.getImageManager().toJSON(),
315
+ content: this.getContent(),
316
+ listsFile: this.getListsFile().toJSON()
252
317
  };
253
318
  }
254
319
  };
255
- function createOuterScreen(options, screen) {
256
- return new OuterScreenImpl(options, screen);
257
- }
258
320
 
259
321
  //#endregion
260
- //#region src/screens/outer-double-screen.ts
261
- let OuterDoubleScreen;
262
- (function(_OuterDoubleScreen) {
322
+ //#region src/configs/lists/lists.ts
323
+ let ListsFile;
324
+ (function(_ListsFile) {
263
325
  function is(value) {
264
- return value instanceof OuterDoubleScreenImpl;
326
+ return value instanceof ListsFileImpl;
327
+ }
328
+ _ListsFile.is = is;
329
+ })(ListsFile || (ListsFile = {}));
330
+ var ListsFileImpl = class extends SerializableFileImpl {
331
+ _isChanged = false;
332
+ getListsFileItems() {
333
+ return this.getContent().map((item) => new ListsFileItemImpl(this, item));
334
+ }
335
+ removeDuplicateListFileItems(listsFileItems) {
336
+ this.content = listsFileItems.filter((item, index, self) => index === self.findIndex((t) => t.uuid === item.uuid)).filter((item, index, self) => index === self.findIndex((t) => t.name === item.name));
337
+ }
338
+ addListsFileItem(listsFileItem) {
339
+ this.content.push(listsFileItem);
340
+ this.removeDuplicateListFileItems(this.content);
341
+ this._isChanged = true;
342
+ return new ListsFileItemImpl(this, listsFileItem);
343
+ }
344
+ get isChanged() {
345
+ return this._isChanged;
346
+ }
347
+ deleteListsFileItem(listsFileItem) {
348
+ const index = this.content.findIndex((item) => item.uuid === listsFileItem.getContent().uuid);
349
+ if (index === -1) return this;
350
+ this.content.splice(index, 1);
351
+ this._isChanged = true;
352
+ return this;
265
353
  }
266
- _OuterDoubleScreen.is = is;
267
- })(OuterDoubleScreen || (OuterDoubleScreen = {}));
268
- var OuterDoubleScreenImpl = class extends OuterScreenImpl {
269
- constructor(options, outerScreen) {
270
- super(options, outerScreen.getScreen());
271
- this.options = options;
272
- this.outerScreen = outerScreen;
354
+ async serialize() {
355
+ return JSON.stringify(this.getContent(), null, 2);
356
+ }
357
+ async write() {
358
+ if (!this.isChanged) return;
359
+ await this.writeToFileSystem(this.getImageManager().getListsFilePath());
360
+ this._isChanged = false;
273
361
  }
274
- getOuterScreen() {
275
- return this.outerScreen;
362
+ toJSON() {
363
+ return {
364
+ imageManager: this.getImageManager().toJSON(),
365
+ content: this.getContent(),
366
+ listsFileItems: this.getListsFileItems().map((item) => item.toJSON())
367
+ };
276
368
  }
277
369
  };
278
- function createOuterDoubleScreen(options, outerScreen) {
279
- return new OuterDoubleScreenImpl(options, outerScreen);
280
- }
281
370
 
282
371
  //#endregion
283
- //#region src/screens/product-preset.ts
284
- var ProductPresetImpl = class {
285
- constructor(productConfig, deviceType, screenPreset) {
286
- this.productConfig = productConfig;
372
+ //#region src/configs/product/item.ts
373
+ let ProductConfigItem;
374
+ (function(_ProductConfigItem) {
375
+ function is(value) {
376
+ return value instanceof ProductConfigItemImpl;
377
+ }
378
+ _ProductConfigItem.is = is;
379
+ })(ProductConfigItem || (ProductConfigItem = {}));
380
+ var ProductConfigItemImpl = class extends SerializableContentImpl {
381
+ constructor(productConfigFile, content, deviceType) {
382
+ super(productConfigFile.getImageManager(), content);
383
+ this.productConfigFile = productConfigFile;
384
+ this.content = content;
287
385
  this.deviceType = deviceType;
288
- this.screenPreset = screenPreset;
289
386
  }
290
- getProductConfig() {
291
- return this.productConfig;
387
+ getProductConfigFile() {
388
+ return this.productConfigFile;
292
389
  }
293
390
  getDeviceType() {
294
391
  return this.deviceType;
295
392
  }
296
- getScreenPreset() {
297
- return this.screenPreset;
393
+ async serialize() {
394
+ return JSON.stringify(this.getContent(), null, 2);
395
+ }
396
+ getDevModel() {
397
+ switch (this.getDeviceType()) {
398
+ case "Phone":
399
+ case "2in1": return "PHEMU-FD00";
400
+ case "Foldable": return "PHEMU-FD01";
401
+ case "WideFold": return "PHEMU-FD02";
402
+ case "TripleFold": return "PHEMU-FD06";
403
+ case "2in1 Foldable": return "PCEMU-FD05";
404
+ case "Wearable": return "MCHEMU-AL00CN";
405
+ }
298
406
  }
299
407
  toJSON() {
300
408
  return {
301
- product: this.productConfig,
302
- deviceType: this.deviceType
409
+ imageManager: this.getImageManager().toJSON(),
410
+ content: this.getContent(),
411
+ devModel: this.getDevModel(),
412
+ deviceType: this.getDeviceType(),
413
+ productConfigFile: this.getProductConfigFile().toJSON()
303
414
  };
304
415
  }
305
416
  };
306
- function createProductPreset(productConfig, deviceType, screenPreset) {
307
- return new ProductPresetImpl(productConfig, deviceType, screenPreset);
308
- }
309
417
 
310
418
  //#endregion
311
- //#region src/screens/single-screen.ts
312
- let SingleScreen;
313
- (function(_SingleScreen) {
419
+ //#region src/configs/product/product.ts
420
+ let ProductConfigFile;
421
+ (function(_ProductConfigFile) {
314
422
  function is(value) {
315
- return value instanceof SingleScreenImpl;
316
- }
317
- _SingleScreen.is = is;
318
- })(SingleScreen || (SingleScreen = {}));
319
- var SingleScreenImpl = class extends BaseScreenImpl {
320
- constructor(options, screen) {
321
- super(options);
322
- this.options = options;
323
- this.screen = screen;
423
+ return value instanceof ProductConfigFileImpl;
424
+ }
425
+ _ProductConfigFile.is = is;
426
+ })(ProductConfigFile || (ProductConfigFile = {}));
427
+ var ProductConfigFileImpl = class extends SerializableFileImpl {
428
+ async serialize() {
429
+ return JSON.stringify(this.getContent(), null, 2);
430
+ }
431
+ async write() {
432
+ const { imageBasePath, adapter: { join } } = this.getImageManager().getOptions();
433
+ return this.writeToFileSystem(join(imageBasePath, "productConfig.json"));
434
+ }
435
+ findProductConfigItems(options = {}) {
436
+ const content = this.getContent();
437
+ const items = [];
438
+ for (const deviceType of Object.keys(content)) {
439
+ if (options.deviceType && deviceType !== options.deviceType) continue;
440
+ for (const item of content[deviceType]) {
441
+ if (options.name && item.name !== options.name) continue;
442
+ items.push(new ProductConfigItemImpl(this, item, deviceType));
443
+ }
444
+ }
445
+ return items;
324
446
  }
325
- getScreen() {
326
- return this.screen;
447
+ findProductConfigItem(options = {}) {
448
+ return this.findProductConfigItems(options)[0];
327
449
  }
328
450
  };
329
- function createSingleScreen(options, screen) {
330
- return new SingleScreenImpl(options, screen);
331
- }
332
451
 
333
452
  //#endregion
334
- //#region src/screens/screen.ts
335
- let Screen;
336
- (function(_Screen) {
453
+ //#region src/devices/device.ts
454
+ let Device;
455
+ (function(_Device) {
337
456
  function is(value) {
338
- return value instanceof ScreenImpl;
339
- }
340
- _Screen.is = is;
341
- })(Screen || (Screen = {}));
342
- var ScreenImpl = class extends BaseScreenImpl {
343
- outerScreen;
344
- coverScreen;
345
- singleScreen;
346
- doubleScreen;
457
+ return value instanceof DeviceImpl;
458
+ }
459
+ _Device.is = is;
460
+ })(Device || (Device = {}));
461
+ var DeviceImpl = class {
347
462
  constructor(options) {
348
- super(options);
349
463
  this.options = options;
350
- if (options.outer) this.outerScreen = OuterScreen.is(options.outer) ? options.outer : createOuterScreen(options.outer, this);
351
- if (options.cover) this.coverScreen = CoverScreen.is(options.cover) ? options.cover : createCoverScreen(options.cover, this);
352
- if (options.single) this.singleScreen = SingleScreen.is(options.single) ? options.single : createSingleScreen(options.single, this);
353
- if (options.double) this.doubleScreen = DoubleScreen.is(options.double) ? options.double : createDoubleScreen(options.double, this);
354
464
  }
355
465
  getScreen() {
356
- return this;
466
+ return this.options.screen;
357
467
  }
358
- getApiVersion() {
359
- return this.options.apiVersion;
468
+ getListsFile() {
469
+ return this.options.listsFile;
360
470
  }
361
- getSnakecaseDeviceType() {
362
- return this.options.deviceType;
471
+ getListsFileItem() {
472
+ return this.options.listFileItem;
363
473
  }
364
- getOuterScreen() {
365
- return this.outerScreen;
474
+ getImageManager() {
475
+ return this.options.imageManager;
366
476
  }
367
- setOuterScreen(outerScreen) {
368
- this.outerScreen = OuterScreen.is(outerScreen) ? outerScreen : createOuterScreen(outerScreen, this);
477
+ _configIniFile;
478
+ setConfigIniFile(configIniFile) {
479
+ this._configIniFile = configIniFile;
369
480
  return this;
370
481
  }
371
- getCoverScreen() {
372
- return this.coverScreen;
482
+ getConfigIniFile() {
483
+ return this._configIniFile;
373
484
  }
374
- setCoverScreen(coverScreen) {
375
- this.coverScreen = CoverScreen.is(coverScreen) ? coverScreen : createCoverScreen(coverScreen, this);
485
+ _namedIniFile;
486
+ getNamedIniFile() {
487
+ return this._namedIniFile;
488
+ }
489
+ setNamedIniFile(namedIniFile) {
490
+ this._namedIniFile = namedIniFile;
376
491
  return this;
377
492
  }
378
- getSingleScreen() {
379
- return this.singleScreen;
493
+ getExecutableUri() {
494
+ const { emulatorPath, adapter: { join, process } } = this.getImageManager().getOptions();
495
+ return join(emulatorPath, process.platform === "win32" ? "Emulator.exe" : "Emulator");
380
496
  }
381
- setSingleScreen(singleScreen) {
382
- this.singleScreen = SingleScreen.is(singleScreen) ? singleScreen : createSingleScreen(singleScreen, this);
383
- return this;
497
+ getSnapshotUri() {
498
+ const { deployedPath, adapter: { join } } = this.getImageManager().getOptions();
499
+ return join(deployedPath, this.getListsFileItem().getContent().name, "Snapshot.png");
384
500
  }
385
- getDoubleScreen() {
386
- return this.doubleScreen;
501
+ async getSnapshot() {
502
+ const snapshotUri = this.getSnapshotUri();
503
+ const { adapter: { fs } } = this.getImageManager().getOptions();
504
+ return fromByteArray(await fs.readFile(snapshotUri));
387
505
  }
388
- setDoubleScreen(doubleScreen) {
389
- this.doubleScreen = DoubleScreen.is(doubleScreen) ? doubleScreen : createDoubleScreen(doubleScreen, this);
390
- return this;
506
+ getStartCommand() {
507
+ const listFileItemContent = this.getListsFileItem().getContent();
508
+ return [this.getExecutableUri().fsPath, [
509
+ "-hvd",
510
+ listFileItemContent.name,
511
+ "-path",
512
+ this.getImageManager().getOptions().deployedPath.fsPath,
513
+ "-imageRoot",
514
+ this.getImageManager().getOptions().imageBasePath.fsPath
515
+ ]];
516
+ }
517
+ async start() {
518
+ const { emulatorPath, adapter: { child_process } } = this.getImageManager().getOptions();
519
+ const [executableUri, args] = this.getStartCommand();
520
+ return child_process.spawn(executableUri, args, {
521
+ cwd: emulatorPath.fsPath,
522
+ stdio: [
523
+ "ignore",
524
+ "pipe",
525
+ "pipe"
526
+ ]
527
+ });
528
+ }
529
+ getStopCommand() {
530
+ const listFileItemContent = this.getListsFileItem().getContent();
531
+ return [this.getExecutableUri().fsPath, ["-stop", listFileItemContent.name]];
532
+ }
533
+ async stop() {
534
+ const { emulatorPath, adapter: { child_process } } = this.getImageManager().getOptions();
535
+ const [executableUri, args] = this.getStopCommand();
536
+ return child_process.spawn(executableUri, args, {
537
+ cwd: emulatorPath.fsPath,
538
+ stdio: [
539
+ "ignore",
540
+ "pipe",
541
+ "pipe"
542
+ ]
543
+ });
544
+ }
545
+ async delete() {
546
+ const { deployedPath, adapter: { join, fs } } = this.getImageManager().getOptions();
547
+ await Promise.allSettled([
548
+ fs.delete(join(deployedPath, this.getListsFileItem().getContent().name), { recursive: true }),
549
+ fs.delete(join(deployedPath, `${this.getListsFileItem().getContent().name}.ini`), { recursive: false }),
550
+ this.getImageManager().readListsFile().then(async (listsFile) => {
551
+ const listsFileItem = listsFile.getListsFileItems().find((item) => {
552
+ return item.getContent().name === this.getListsFileItem().getContent().name;
553
+ });
554
+ if (!listsFileItem) return;
555
+ await listsFile.deleteListsFileItem(listsFileItem).write();
556
+ })
557
+ ]);
558
+ }
559
+ async getStorageSize() {
560
+ const { deployedPath, adapter: { join, fs } } = this.getImageManager().getOptions();
561
+ return (await fs.stat(join(deployedPath, this.getListsFileItem().getContent().name))).size;
562
+ }
563
+ _watcher;
564
+ async getWatcher() {
565
+ if (this._watcher && !this._watcher.isDisposed) return this._watcher;
566
+ const { deployedPath, adapter: { fs, join } } = this.getImageManager().getOptions();
567
+ this._watcher = await fs.createWatcher(new RelativePattern(join(deployedPath, this.getListsFileItem().getContent().name), "**"));
568
+ return this._watcher;
569
+ }
570
+ toJSON() {
571
+ return {
572
+ screen: this.getScreen(),
573
+ listsFile: this.getListsFile().toJSON(),
574
+ listsFileItem: this.getListsFileItem().toJSON(),
575
+ configIniFile: this.getConfigIniFile().toJSON(),
576
+ namedIniFile: this.getNamedIniFile().toJSON(),
577
+ executableUri: this.getExecutableUri().toJSON(),
578
+ snapshotUri: this.getSnapshotUri().toJSON(),
579
+ startCommand: this.getStartCommand(),
580
+ stopCommand: this.getStopCommand()
581
+ };
582
+ }
583
+ };
584
+
585
+ //#endregion
586
+ //#region src/configs/named-ini/named-ini.ts
587
+ let NamedIniFile;
588
+ (function(_NamedIniFile) {
589
+ function is(value) {
590
+ return value instanceof NamedIniFileImpl;
591
+ }
592
+ _NamedIniFile.is = is;
593
+ })(NamedIniFile || (NamedIniFile = {}));
594
+ var NamedIniFileImpl = class extends SerializableFileImpl {
595
+ constructor(device, namedIniFilePath, content) {
596
+ super(device.getImageManager(), content);
597
+ this.device = device;
598
+ this.namedIniFilePath = namedIniFilePath;
599
+ this.content = content;
600
+ }
601
+ getDevice() {
602
+ return this.device;
603
+ }
604
+ static getFileUri(device) {
605
+ const { deployedPath, adapter: { join } } = device.getImageManager().getOptions();
606
+ return join(deployedPath, `${device.getListsFileItem().getContent().name}.ini`);
607
+ }
608
+ getFileUri() {
609
+ return this.namedIniFilePath;
610
+ }
611
+ static async safeReadAndParse(device) {
612
+ try {
613
+ const { adapter: { fs } } = device.getImageManager().getOptions();
614
+ const namedIniFileUri = this.getFileUri(device);
615
+ const namedIniFileContent = await fs.readFile(namedIniFileUri).then((buffer) => buffer.toString(), () => void 0);
616
+ if (!namedIniFileContent?.length) return;
617
+ return INI.parse(namedIniFileContent);
618
+ } catch {}
619
+ }
620
+ async serialize() {
621
+ return INI.stringify(this.getContent());
622
+ }
623
+ async write() {
624
+ const { deployedPath, adapter: { join } } = this.getImageManager().getOptions();
625
+ return this.writeToFileSystem(join(deployedPath, `${this.getDevice().getListsFileItem().getContent().name}.ini`));
626
+ }
627
+ toJSON() {
628
+ return {
629
+ imageManager: this.getImageManager().toJSON(),
630
+ content: this.getContent(),
631
+ fileUri: this.getFileUri().toJSON()
632
+ };
633
+ }
634
+ };
635
+
636
+ //#endregion
637
+ //#region src/screens/customize-screen.ts
638
+ let CustomizeScreen;
639
+ (function(_CustomizeScreen) {
640
+ function is(value) {
641
+ return value instanceof CustomizeScreenImpl;
642
+ }
643
+ _CustomizeScreen.is = is;
644
+ })(CustomizeScreen || (CustomizeScreen = {}));
645
+ var CustomizeScreenImpl = class {
646
+ constructor(screenPreset, options) {
647
+ this.screenPreset = screenPreset;
648
+ this.options = options;
649
+ }
650
+ getConfigName() {
651
+ return this.options?.configName ?? "Customize_01";
652
+ }
653
+ getDiagonalSize() {
654
+ return this.options?.diagonalSize ?? 0;
655
+ }
656
+ getResolutionWidth() {
657
+ return this.options?.resolutionWidth ?? 0;
658
+ }
659
+ getResolutionHeight() {
660
+ return this.options?.resolutionHeight ?? 0;
391
661
  }
392
662
  getDensity() {
393
- return this.options.density;
663
+ return this.options?.density ?? 0;
394
664
  }
395
- setDensity(density) {
396
- this.options.density = density;
397
- return this;
665
+ getScreenPreset() {
666
+ return this.screenPreset;
667
+ }
668
+ toJSON() {
669
+ return {
670
+ configName: this.getConfigName(),
671
+ diagonalSize: this.getDiagonalSize(),
672
+ resolutionWidth: this.getResolutionWidth(),
673
+ resolutionHeight: this.getResolutionHeight(),
674
+ density: this.getDensity()
675
+ };
676
+ }
677
+ };
678
+
679
+ //#endregion
680
+ //#region src/screens/customize-foldable-screen.ts
681
+ let CustomizeFoldableScreen;
682
+ (function(_CustomizeFoldableScreen) {
683
+ function is(value) {
684
+ return value instanceof CustomizeFoldableScreenImpl;
685
+ }
686
+ _CustomizeFoldableScreen.is = is;
687
+ })(CustomizeFoldableScreen || (CustomizeFoldableScreen = {}));
688
+ var CustomizeFoldableScreenImpl = class extends CustomizeScreenImpl {
689
+ constructor(screenPreset, options, foldableOptions) {
690
+ super(screenPreset, options);
691
+ this.screenPreset = screenPreset;
692
+ this.options = options;
693
+ this.foldableOptions = foldableOptions;
694
+ }
695
+ getCoverResolutionWidth() {
696
+ return this.foldableOptions?.coverResolutionWidth ?? 0;
697
+ }
698
+ getCoverResolutionHeight() {
699
+ return this.foldableOptions?.coverResolutionHeight ?? 0;
700
+ }
701
+ getCoverDiagonalSize() {
702
+ return this.foldableOptions?.coverDiagonalSize ?? 0;
398
703
  }
399
704
  toJSON() {
400
705
  return {
401
706
  ...super.toJSON(),
402
- density: this.options.density,
403
- apiVersion: this.options.apiVersion,
404
- deviceType: this.options.deviceType,
405
- outer: this.outerScreen?.toJSON(),
406
- cover: this.coverScreen?.toJSON(),
407
- single: this.singleScreen?.toJSON()
707
+ coverResolutionWidth: this.getCoverResolutionWidth(),
708
+ coverResolutionHeight: this.getCoverResolutionHeight(),
709
+ coverDiagonalSize: this.getCoverDiagonalSize()
408
710
  };
409
711
  }
410
712
  };
411
- function createScreen(options) {
412
- return new ScreenImpl(options);
413
- }
414
713
 
415
714
  //#endregion
416
715
  //#region src/screens/screen-preset.ts
417
716
  let ScreenPreset;
418
717
  (function(_ScreenPreset) {
419
- let ScreenOptions;
420
- (function(_ScreenOptions) {
421
- function is(value) {
422
- return typeof value === "object" && value !== null && "screen" in value && Screen.is(value.screen);
423
- }
424
- _ScreenOptions.is = is;
425
- })(ScreenOptions || (ScreenOptions = _ScreenPreset.ScreenOptions || (_ScreenPreset.ScreenOptions = {})));
426
- let ProductOptions;
427
- (function(_ProductOptions) {
428
- function is(value) {
429
- return typeof value === "object" && value !== null && "image" in value && "productConfig" in value && ProductConfigItem.is(value.productConfig);
430
- }
431
- _ProductOptions.is = is;
432
- })(ProductOptions || (ProductOptions = _ScreenPreset.ProductOptions || (_ScreenPreset.ProductOptions = {})));
433
- let EmulatorOptions;
434
- (function(_EmulatorOptions) {
435
- function is(value) {
436
- return typeof value === "object" && value !== null && "image" in value && "emulatorConfig" in value;
437
- }
438
- _EmulatorOptions.is = is;
439
- })(EmulatorOptions || (EmulatorOptions = _ScreenPreset.EmulatorOptions || (_ScreenPreset.EmulatorOptions = {})));
440
718
  function is(value) {
441
719
  return value instanceof ScreenPresetImpl;
442
720
  }
443
721
  _ScreenPreset.is = is;
444
722
  })(ScreenPreset || (ScreenPreset = {}));
445
723
  var ScreenPresetImpl = class {
446
- emulatorPreset;
447
- productPreset;
448
724
  constructor(options) {
449
725
  this.options = options;
450
- this._screen = this.getScreen();
451
- this.setEmulatorPreset();
452
- this.setProductPreset();
453
726
  }
454
- _screen;
455
- getScreen() {
456
- if (ScreenPreset.ScreenOptions.is(this.options)) return this.options.screen;
457
- if (this._screen) return this._screen;
458
- if (ScreenPreset.ProductOptions.is(this.options)) {
459
- this._screen = createScreen({
460
- width: Number(this.options.productConfig.screenWidth),
461
- height: Number(this.options.productConfig.screenHeight),
462
- diagonal: Number(this.options.productConfig.screenDiagonal),
463
- density: Number(this.options.productConfig.screenDensity),
464
- apiVersion: Number.parseInt(this.options.image.getApiVersion()),
465
- deviceType: this.options.image.getSnakecaseDeviceType()
466
- });
467
- if (this.options.productConfig.outerScreenWidth && this.options.productConfig.outerScreenHeight && this.options.productConfig.outerScreenDiagonal) this._screen.setOuterScreen(createOuterScreen({
468
- width: Number(this.options.productConfig.outerScreenWidth),
469
- height: Number(this.options.productConfig.outerScreenHeight),
470
- diagonal: Number(this.options.productConfig.outerScreenDiagonal)
471
- }, this._screen));
472
- if (this.options.productConfig.outerDoubleScreenWidth && this.options.productConfig.outerDoubleScreenHeight && this.options.productConfig.outerDoubleScreenDiagonal) this._screen.getOuterScreen()?.setOuterDoubleScreen(createOuterDoubleScreen({
473
- width: Number(this.options.productConfig.outerDoubleScreenWidth),
474
- height: Number(this.options.productConfig.outerDoubleScreenHeight),
475
- diagonal: Number(this.options.productConfig.outerDoubleScreenDiagonal)
476
- }, this._screen.getOuterScreen()));
477
- return this._screen;
478
- }
479
- if (ScreenPreset.EmulatorOptions.is(this.options)) {
480
- this._screen = createScreen({
481
- width: this.options.emulatorConfig.resolutionWidth,
482
- height: this.options.emulatorConfig.resolutionHeight,
483
- diagonal: this.options.emulatorConfig.diagonalSize,
484
- density: this.options.emulatorConfig.density,
485
- apiVersion: Number.parseInt(this.options.image.getApiVersion()),
486
- deviceType: this.options.image.getSnakecaseDeviceType()
487
- });
488
- if (this.options.emulatorConfig.coverResolutionWidth && this.options.emulatorConfig.coverResolutionHeight && this.options.emulatorConfig.coverDiagonalSize) this._screen.setCoverScreen(createCoverScreen({
489
- width: this.options.emulatorConfig.coverResolutionWidth,
490
- height: this.options.emulatorConfig.coverResolutionHeight,
491
- diagonal: this.options.emulatorConfig.coverDiagonalSize
492
- }, this._screen));
493
- if (PhoneAllEmulatorConfigItem.is(this.options.emulatorConfig)) {
494
- if (this.options.emulatorConfig.singleResolutionWidth && this.options.emulatorConfig.singleResolutionHeight && this.options.emulatorConfig.singleDiagonalSize) this._screen.setSingleScreen(createSingleScreen({
495
- width: this.options.emulatorConfig.singleResolutionWidth,
496
- height: this.options.emulatorConfig.singleResolutionHeight,
497
- diagonal: this.options.emulatorConfig.singleDiagonalSize
498
- }, this._screen));
499
- if (this.options.emulatorConfig.doubleResolutionWidth && this.options.emulatorConfig.doubleResolutionHeight && this.options.emulatorConfig.doubleDiagonalSize) this._screen.setDoubleScreen(createDoubleScreen({
500
- width: this.options.emulatorConfig.doubleResolutionWidth,
501
- height: this.options.emulatorConfig.doubleResolutionHeight,
502
- diagonal: this.options.emulatorConfig.doubleDiagonalSize
503
- }, this._screen));
504
- }
505
- return this._screen;
506
- }
507
- throw new Error("Invalid createScreenPreset options.");
508
- }
509
- getProductConfigItemsByScreenOptions() {
510
- if (!ScreenPreset.ScreenOptions.is(this.options)) return;
511
- for (const [pascalCaseDeviceType, productConfigItem] of Object.entries(this.options.productConfig ?? {})) if (pascalCaseDeviceType === "2in1" && this.getScreen().getSnakecaseDeviceType() === "2in1") return [productConfigItem, pascalCaseDeviceType];
512
- else if (pascalCaseDeviceType === "2in1 Foldable" && this.getScreen().getSnakecaseDeviceType() === "2in1_foldable") return [productConfigItem, pascalCaseDeviceType];
513
- else if (pascalCaseDeviceType === "Foldable" && this.getScreen().getSnakecaseDeviceType() === "foldable") return [productConfigItem, pascalCaseDeviceType];
514
- else if (pascalCaseDeviceType === "Phone" && this.getScreen().getSnakecaseDeviceType() === "phone") return [productConfigItem, pascalCaseDeviceType];
515
- else if (pascalCaseDeviceType === "TV" && this.getScreen().getSnakecaseDeviceType() === "tv") return [productConfigItem, pascalCaseDeviceType];
516
- else if (pascalCaseDeviceType === "Tablet" && this.getScreen().getSnakecaseDeviceType() === "tablet") return [productConfigItem, pascalCaseDeviceType];
517
- else if (pascalCaseDeviceType === "TripleFold" && this.getScreen().getSnakecaseDeviceType() === "triplefold") return [productConfigItem, pascalCaseDeviceType];
518
- else if (pascalCaseDeviceType === "Wearable" && this.getScreen().getSnakecaseDeviceType() === "wearable") return [productConfigItem, pascalCaseDeviceType];
519
- else if (pascalCaseDeviceType === "WideFold" && this.getScreen().getSnakecaseDeviceType() === "widefold") return [productConfigItem, pascalCaseDeviceType];
520
- else if (pascalCaseDeviceType.toLowerCase() === this.getScreen().getSnakecaseDeviceType().toLowerCase()) return [productConfigItem, pascalCaseDeviceType];
521
- }
522
- setProductPreset() {
523
- if (ScreenPreset.ScreenOptions.is(this.options)) {
524
- const [productConfigItems = [], pascalCaseDeviceType] = this.getProductConfigItemsByScreenOptions() ?? [];
525
- if (!pascalCaseDeviceType || !productConfigItems.length) return;
526
- for (const productConfigItem of productConfigItems) {
527
- if (this.getScreen().getWidth() !== Number(productConfigItem.screenWidth) || this.getScreen().getHeight() !== Number(productConfigItem.screenHeight) || this.getScreen().getDiagonal() !== Number(productConfigItem.screenDiagonal) || this.getScreen().getDensity() !== Number(productConfigItem.screenDensity)) continue;
528
- if (productConfigItem.outerScreenWidth && productConfigItem.outerScreenHeight && productConfigItem.outerScreenDiagonal) {
529
- const outerScreen = this.getScreen().getOuterScreen();
530
- if (!outerScreen) continue;
531
- if (outerScreen.getWidth() !== Number(productConfigItem.outerScreenWidth) || outerScreen.getHeight() !== Number(productConfigItem.outerScreenHeight) || outerScreen.getDiagonal() !== Number(productConfigItem.outerScreenDiagonal)) continue;
532
- }
533
- if (productConfigItem.outerDoubleScreenWidth && productConfigItem.outerDoubleScreenHeight && productConfigItem.outerDoubleScreenDiagonal) {
534
- const outerDoubleScreen = this.getScreen().getOuterScreen()?.getOuterDoubleScreen();
535
- if (!outerDoubleScreen) continue;
536
- if (outerDoubleScreen.getWidth() !== Number(productConfigItem.outerDoubleScreenWidth) || outerDoubleScreen.getHeight() !== Number(productConfigItem.outerDoubleScreenHeight) || outerDoubleScreen.getDiagonal() !== Number(productConfigItem.outerDoubleScreenDiagonal)) continue;
537
- }
538
- this.productPreset = createProductPreset(productConfigItem, pascalCaseDeviceType, this);
539
- return;
540
- }
541
- } else if (ScreenPreset.ProductOptions.is(this.options)) this.productPreset = createProductPreset(this.options.productConfig, this.options.pascalCaseDeviceType, this);
542
- else if (ScreenPreset.EmulatorOptions.is(this.options)) this.emulatorPreset = createEmulatorPreset(this.options.emulatorConfig, this);
543
- }
544
- setEmulatorPreset() {
545
- if (ScreenPreset.ScreenOptions.is(this.options)) {
546
- if (!this.options.emulatorConfig) return;
547
- for (const parentConfigItem of this.options.emulatorConfig) {
548
- if (parentConfigItem.api !== this.options.screen.getApiVersion()) continue;
549
- if (ParentEmulatorConfigItem.is(parentConfigItem) && parentConfigItem.deviceType === this.options.screen.getSnakecaseDeviceType()) {
550
- this.emulatorPreset = createEmulatorPreset(parentConfigItem, this);
551
- return;
552
- }
553
- if (GroupPhoneAllEmulatorConfigItem.is(parentConfigItem) && isPhoneAllSnakecaseDeviceType(this.options.screen.getSnakecaseDeviceType())) {
554
- for (const childrenConfigItem of parentConfigItem.children) if (PhoneAllEmulatorConfigItem.is(childrenConfigItem) && childrenConfigItem.deviceType === this.options.screen.getSnakecaseDeviceType()) {
555
- this.emulatorPreset = createEmulatorPreset(childrenConfigItem, this);
556
- return;
557
- }
558
- }
559
- if (GroupPCAllEmulatorConfigItem.is(parentConfigItem) && isPCAllSnakecaseDeviceType(this.options.screen.getSnakecaseDeviceType())) {
560
- for (const childrenConfigItem of parentConfigItem.children) if (PCAllEmulatorConfigItem.is(childrenConfigItem) && childrenConfigItem.deviceType === this.options.screen.getSnakecaseDeviceType()) {
561
- this.emulatorPreset = createEmulatorPreset(childrenConfigItem, this);
562
- return;
563
- }
564
- }
565
- }
566
- } else if (ScreenPreset.EmulatorOptions.is(this.options)) this.emulatorPreset = createEmulatorPreset(this.options.emulatorConfig, this);
727
+ getEmulatorDeviceItem() {
728
+ return this.options.emulatorDeviceItem;
567
729
  }
568
- getEmulatorPreset() {
569
- return this.emulatorPreset;
730
+ getProductConfigItem() {
731
+ return this.options.productConfigItem;
570
732
  }
571
- getProductPreset() {
572
- return this.productPreset;
733
+ _customizeScreen;
734
+ getCustomizeScreenConfig() {
735
+ if (this._customizeScreen) return this._customizeScreen;
736
+ if (this.getEmulatorDeviceItem().getContent().deviceType === "foldable" && this.options.productConfigItem.getContent().name === "Customize" && "customizeScreen" in this.options && "customizeFoldableScreen" in this.options) this._customizeScreen = new CustomizeFoldableScreenImpl(this, this.options.customizeScreen, this.options.customizeFoldableScreen);
737
+ else if (this.options.productConfigItem.getContent().name === "Customize" && "customizeScreen" in this.options) this._customizeScreen = new CustomizeScreenImpl(this, this.options.customizeScreen);
738
+ return this._customizeScreen;
573
739
  }
574
740
  toJSON() {
575
741
  return {
576
- emulatorPreset: this.emulatorPreset?.toJSON(),
577
- productPreset: this.productPreset?.toJSON()
742
+ customizeScreenConfig: this.getCustomizeScreenConfig()?.toJSON(),
743
+ emulatorDeviceItem: this.getEmulatorDeviceItem().toJSON(),
744
+ productConfigItem: this.getProductConfigItem().toJSON()
578
745
  };
579
746
  }
580
747
  };
581
- function createScreenPreset(options) {
582
- return new ScreenPresetImpl(options);
583
- }
584
748
 
585
749
  //#endregion
586
- //#region src/devices/device.ts
587
- var DeviceImpl = class {
588
- uuid;
589
- constructor(image, options) {
590
- this.image = image;
591
- this.options = options;
592
- this.uuid = image.getImageManager().getOptions().crypto.randomUUID();
593
- }
594
- getOptions() {
595
- return this.options;
596
- }
597
- getImage() {
598
- return this.image;
599
- }
600
- getScreen() {
601
- if (this.options.screen instanceof ScreenPresetImpl) return this.options.screen.getScreen();
602
- return this.options.screen;
750
+ //#region src/images/base-image.ts
751
+ let BaseImage;
752
+ (function(_BaseImage) {
753
+ function is(value) {
754
+ return value instanceof BaseImageImpl;
603
755
  }
604
- getScreenPreset() {
605
- if (this.options.screen instanceof ScreenPresetImpl) return this.options.screen;
756
+ _BaseImage.is = is;
757
+ })(BaseImage || (BaseImage = {}));
758
+ var BaseImageImpl = class {
759
+ constructor(options) {
760
+ this.options = options;
606
761
  }
607
- setUuid(uuid) {
608
- this.uuid = uuid;
609
- return this;
762
+ getImageManager() {
763
+ return this.options.imageManager;
610
764
  }
611
- getUuid() {
612
- return this.uuid;
765
+ getRelativePath() {
766
+ return this.options.relativePath;
613
767
  }
614
- cachedList = null;
615
- setCachedList(list) {
616
- this.cachedList = list;
617
- return this;
768
+ getFullPath() {
769
+ const { imageBasePath, adapter: { join } } = this.getImageManager().getOptions();
770
+ return join(imageBasePath, this.getRelativePath());
618
771
  }
619
- cachedIni = null;
620
- setCachedIni(ini) {
621
- this.cachedIni = ini;
622
- return this;
772
+ getApiVersion() {
773
+ return this.options.apiVersion;
623
774
  }
624
- buildList() {
625
- if (this.cachedList) return this.cachedList;
626
- const { path, deployedPath, imageBasePath, configPath, logPath } = this.image.getImageManager().getOptions();
627
- const screen = this.getScreen();
628
- const list = {
629
- "name": this.options.name,
630
- "apiVersion": this.image.getApiVersion(),
631
- "cpuNumber": this.options.cpuNumber.toFixed(),
632
- "diagonalSize": screen.getDiagonal().toFixed(2),
633
- "resolutionHeight": screen.getHeight().toFixed(),
634
- "resolutionWidth": screen.getWidth().toFixed(),
635
- "density": screen.getDensity().toFixed(),
636
- "memoryRamSize": this.options.memorySize.toFixed(),
637
- "dataDiskSize": this.options.diskSize.toFixed(),
638
- "path": path.resolve(deployedPath, this.options.name),
639
- "type": this.image.getSnakecaseDeviceType(),
640
- "uuid": this.uuid,
641
- "version": this.image.getVersion(),
642
- "imageDir": this.image.getPath().split(",").join(path.sep) + path.sep,
643
- "showVersion": `${this.image.getTargetOS()} ${this.image.getTargetVersion()}(${this.image.getApiVersion()})`,
644
- "harmonyos.sdk.path": imageBasePath,
645
- "harmonyos.config.path": configPath,
646
- "harmonyos.log.path": logPath,
647
- "hw.apiName": this.image.getTargetVersion(),
648
- "abi": this.image.getArch(),
649
- "harmonyOSVersion": `${this.image.getTargetOS()}-${this.image.getTargetVersion()}`,
650
- "guestVersion": `${this.image.getTargetOS()} ${this.image.getVersion()}(${this.image.getReleaseType()})`
651
- };
652
- if (this.options.screen instanceof ScreenPresetImpl) {
653
- const productConfig = this.options.screen.getProductPreset()?.getProductConfig();
654
- if (productConfig?.devModel) list.devModel = productConfig.devModel;
655
- if (productConfig?.name) list.model = productConfig.name;
656
- }
657
- return list;
658
- }
659
- buildIni(options = {}) {
660
- if (this.cachedIni) return this.cachedIni;
661
- const listConfig = this.buildList();
662
- const screen = this.getScreen();
663
- const is2in1Foldable = listConfig.type === "2in1_foldable";
664
- const screenPreset = this.options.screen instanceof ScreenPresetImpl ? this.options.screen.getProductPreset() : null;
665
- const productConfig = screenPreset?.getProductConfig();
666
- const useDualScreen = is2in1Foldable && productConfig?.outerScreenWidth != null && productConfig?.outerScreenHeight != null && productConfig?.outerScreenDiagonal != null;
667
- const singleDiagonal = useDualScreen ? productConfig.outerScreenDiagonal : screen.getDiagonal().toString();
668
- const singleHeight = useDualScreen ? productConfig.outerScreenHeight : screen.getHeight().toString();
669
- const singleWidth = useDualScreen ? productConfig.outerScreenWidth : screen.getWidth().toString();
670
- const doubleDiagonal = useDualScreen ? productConfig.screenDiagonal : void 0;
671
- const doubleHeight = useDualScreen ? productConfig.screenHeight : void 0;
672
- const doubleWidth = useDualScreen ? productConfig.screenWidth : void 0;
673
- const ini = {
674
- "name": listConfig.name,
675
- "deviceType": listConfig.type,
676
- "deviceModel": listConfig.devModel,
677
- "productModel": listConfig.model,
678
- "vendorCountry": options.vendorCountry ?? "CN",
679
- "uuid": this.uuid,
680
- "configPath": listConfig["harmonyos.config.path"],
681
- "logPath": listConfig["harmonyos.log.path"],
682
- "sdkPath": listConfig["harmonyos.sdk.path"],
683
- "imageSubPath": listConfig.imageDir,
684
- "instancePath": listConfig.path,
685
- "os.osVersion": `${this.image.getTargetOS()} ${this.image.getTargetVersion()}(${this.image.getApiVersion()})`,
686
- "os.apiVersion": this.image.getApiVersion(),
687
- "os.softwareVersion": this.image.getVersion(),
688
- "os.isPublic": options.isPublic ?? true ? "true" : "false",
689
- "hw.cpu.arch": listConfig.abi,
690
- "hw.cpu.ncore": listConfig.cpuNumber,
691
- "hw.lcd.density": screen.getDensity().toFixed(),
692
- "hw.lcd.single.diagonalSize": singleDiagonal,
693
- "hw.lcd.single.height": singleHeight,
694
- "hw.lcd.single.width": singleWidth,
695
- "hw.lcd.number": useDualScreen ? "2" : "1",
696
- "hw.ramSize": listConfig.memoryRamSize,
697
- "hw.dataPartitionSize": listConfig.dataDiskSize,
698
- "isCustomize": screenPreset ? "false" : "true",
699
- "hw.hdc.port": "notset",
700
- ...options.overrides
701
- };
702
- if (useDualScreen && doubleDiagonal != null && doubleHeight != null && doubleWidth != null) {
703
- ini["hw.lcd.double.diagonalSize"] = doubleDiagonal;
704
- ini["hw.lcd.double.height"] = doubleHeight;
705
- ini["hw.lcd.double.width"] = doubleWidth;
706
- }
707
- if (screenPreset && productConfig && !useDualScreen) {
708
- if (productConfig.outerScreenHeight) ini["hw.phy.height"] = productConfig.outerScreenHeight;
709
- if (productConfig.outerScreenWidth) ini["hw.phy.width"] = productConfig.outerScreenWidth;
775
+ async isDownloaded() {
776
+ try {
777
+ return (await this.getImageManager().getLocalImages()).some((localImage) => localImage.getFullPath().toString() === this.getFullPath().toString());
778
+ } catch {
779
+ return false;
710
780
  }
711
- return ini;
712
781
  }
713
- toIniString() {
714
- return `${Object.entries(this.buildIni()).filter(([, value]) => value !== void 0 && value !== null).map(([key, value]) => `${key}=${value}`).join("\n")}\n`;
715
- }
716
- buildDeviceIni() {
782
+ toJSON() {
717
783
  return {
718
- "hvd.ini.encoding": "UTF-8",
719
- "path": this.buildList().path
784
+ imageType: this.imageType,
785
+ imageManager: this.getImageManager().toJSON(),
786
+ relativePath: this.getRelativePath(),
787
+ fullPath: this.getFullPath().toJSON(),
788
+ apiVersion: this.getApiVersion(),
789
+ fullDeviceType: this.getFullDeviceType()
720
790
  };
721
791
  }
722
- buildDeviceIniString() {
723
- return `${Object.entries(this.buildDeviceIni()).filter(([, value]) => value !== void 0 && value !== null).map(([key, value]) => `${key}=${value}`).join("\n")}\n`;
724
- }
725
- async deploy() {
726
- if (await this.isDeployed()) throw new DeployError(DeployError.Code.DEVICE_ALREADY_DEPLOYED, `Image ${this.options.name} already deployed`);
727
- const { fs, path, deployedPath } = this.image.getImageManager().getOptions();
728
- if (!fs.existsSync(deployedPath)) fs.mkdirSync(deployedPath, { recursive: true });
729
- const listsPath = path.join(deployedPath, "lists.json");
730
- const listConfig = this.buildList();
731
- if (!fs.existsSync(listsPath)) return fs.writeFileSync(listsPath, JSON.stringify([listConfig], null, 2));
732
- const lists = JSON.parse(fs.readFileSync(listsPath, "utf-8")) ?? [];
733
- if (!Array.isArray(lists)) throw new DeployError(DeployError.Code.LIST_JSON_NOT_AN_ARRAY, "Lists is not an array");
734
- if (lists.find((item) => item.name === listConfig.name)) throw new DeployError(DeployError.Code.DEVICE_ALREADY_DEPLOYED, `Image ${listConfig.name} already deployed in lists.json`);
735
- lists.push(listConfig);
736
- fs.mkdirSync(listConfig.path, { recursive: true });
737
- fs.writeFileSync(path.join(listConfig.path, "config.ini"), this.toIniString());
738
- fs.writeFileSync(path.join(deployedPath, `${this.options.name}.ini`), this.buildDeviceIniString());
739
- fs.writeFileSync(listsPath, JSON.stringify(lists, null, 2));
792
+ };
793
+
794
+ //#endregion
795
+ //#region src/images/local-image.ts
796
+ let LocalImage;
797
+ (function(_LocalImage) {
798
+ function is(value) {
799
+ return value instanceof LocalImageImpl;
740
800
  }
741
- async delete() {
742
- const { fs, path, deployedPath } = this.image.getImageManager().getOptions();
743
- const listsPath = path.join(deployedPath, "lists.json");
744
- if (!fs.existsSync(listsPath) || !fs.statSync(listsPath).isFile()) throw new Error("Lists file not found");
745
- const lists = JSON.parse(fs.readFileSync(listsPath, "utf-8")) ?? [];
746
- const index = lists.findIndex((item) => item.name === this.options.name);
747
- if (index === -1) throw new Error(`Device ${this.options.name} not found`);
748
- lists.splice(index, 1);
749
- fs.writeFileSync(listsPath, JSON.stringify(lists, null, 2));
750
- fs.rmSync(path.resolve(this.buildList().path), { recursive: true });
751
- fs.rmSync(path.resolve(deployedPath, `${this.options.name}.ini`));
752
- }
753
- async isDeployed() {
754
- const { fs, path, deployedPath } = this.image.getImageManager().getOptions();
755
- const listsPath = path.join(deployedPath, "lists.json");
756
- if (!fs.existsSync(listsPath) || !fs.statSync(listsPath).isFile()) return false;
757
- return (JSON.parse(fs.readFileSync(listsPath, "utf-8")) ?? []).some((item) => item.name === this.options.name && fs.existsSync(path.resolve(item.path, "config.ini")));
801
+ _LocalImage.is = is;
802
+ })(LocalImage || (LocalImage = {}));
803
+ var LocalImageImpl = class extends BaseImageImpl {
804
+ imageType = "local";
805
+ constructor(imageManager, sdkPkgFile, infoFile) {
806
+ super({
807
+ imageManager,
808
+ apiVersion: Number.parseInt(sdkPkgFile?.data?.apiVersion ?? "0"),
809
+ relativePath: sdkPkgFile?.data?.path?.split(",").join("/")
810
+ });
811
+ this.imageManager = imageManager;
812
+ this.sdkPkgFile = sdkPkgFile;
813
+ this.infoFile = infoFile;
814
+ }
815
+ getSdkPkgFile() {
816
+ return this.sdkPkgFile;
817
+ }
818
+ getFullDeviceType() {
819
+ const name = this.getSdkPkgFile().data?.displayName?.split("-");
820
+ return name?.[name.length - 1];
821
+ }
822
+ async createDevice(options) {
823
+ const { deployedPath, imageBasePath, configPath, logPath, adapter: { join } } = this.getImageManager().getOptions();
824
+ const screen = new ScreenPresetImpl(options.screen);
825
+ const emulatorDeviceItem = screen.getEmulatorDeviceItem();
826
+ const productConfigItem = screen.getProductConfigItem();
827
+ const listsFile = await this.getImageManager().readListsFile();
828
+ const uuid = crypto.randomUUID();
829
+ const deviceFolderPath = join(deployedPath, options.name);
830
+ const listFileItem = listsFile.addListsFileItem({
831
+ uuid,
832
+ "name": options.name,
833
+ "apiVersion": this.getApiVersion().toString(),
834
+ "cpuNumber": options.cpuNumber.toString(),
835
+ "path": deviceFolderPath.fsPath,
836
+ "memoryRamSize": options.memoryRamSize.toString(),
837
+ "dataDiskSize": options.dataDiskSize.toString(),
838
+ "version": this.getSdkPkgFile().data?.version ?? "",
839
+ "imageDir": this.getRelativePath(),
840
+ "showVersion": this.getSdkPkgFile().data?.guestVersion ?? "",
841
+ "harmonyos.sdk.path": imageBasePath.fsPath,
842
+ "harmonyos.config.path": configPath.fsPath,
843
+ "harmonyos.log.path": logPath.fsPath,
844
+ "hw.apiName": this.getSdkPkgFile().data?.platformVersion ?? "",
845
+ "abi": this.infoFile.abi,
846
+ "harmonyOSVersion": `${this.getSdkPkgFile().data?.guestVersion?.split(" ")[0]}-${this.getSdkPkgFile().data?.platformVersion}`,
847
+ "guestVersion": this.getSdkPkgFile().data?.guestVersion ?? "",
848
+ "diagonalSize": emulatorDeviceItem.getContent().diagonalSize.toString(),
849
+ "density": emulatorDeviceItem.getContent().density.toString(),
850
+ "resolutionWidth": emulatorDeviceItem.getContent().resolutionWidth.toString(),
851
+ "resolutionHeight": emulatorDeviceItem.getContent().resolutionHeight.toString(),
852
+ "coverResolutionWidth": EmulatorFoldItem.is(emulatorDeviceItem) ? emulatorDeviceItem.getContent().coverResolutionWidth.toString() : void 0,
853
+ "coverResolutionHeight": EmulatorFoldItem.is(emulatorDeviceItem) ? emulatorDeviceItem.getContent().coverResolutionHeight.toString() : void 0,
854
+ "coverDiagonalSize": EmulatorFoldItem.is(emulatorDeviceItem) ? emulatorDeviceItem.getContent().coverDiagonalSize.toString() : void 0,
855
+ "type": emulatorDeviceItem.getContent().deviceType,
856
+ "devModel": productConfigItem.getDevModel(),
857
+ "model": productConfigItem.getContent().name
858
+ });
859
+ const device = new DeviceImpl({
860
+ imageManager: this.getImageManager(),
861
+ listsFile,
862
+ listFileItem,
863
+ screen
864
+ });
865
+ const deviceIniFile = new ConfigIniFileImpl(device, ConfigIniFileImpl.getFileUri(device), {
866
+ "name": listFileItem.getContent().name,
867
+ "deviceType": listFileItem.getContent().type,
868
+ "deviceModel": listFileItem.getContent().devModel,
869
+ "productModel": listFileItem.getContent().model,
870
+ "vendorCountry": options.vendorCountry ?? "CN",
871
+ "uuid": listFileItem.getContent().uuid,
872
+ "configPath": listFileItem.getContent()["harmonyos.config.path"],
873
+ "logPath": listFileItem.getContent()["harmonyos.log.path"],
874
+ "sdkPath": listFileItem.getContent()["harmonyos.sdk.path"],
875
+ "imageSubPath": listFileItem.getContent().imageDir,
876
+ "instancePath": listFileItem.getContent().path,
877
+ "os.osVersion": `${this.getSdkPkgFile().data?.guestVersion?.split(" ")[0]} ${this.getSdkPkgFile().data?.platformVersion}(${this.getApiVersion()})`,
878
+ "os.apiVersion": this.getApiVersion().toString(),
879
+ "os.softwareVersion": this.getSdkPkgFile().data?.version ?? "",
880
+ "os.isPublic": options.isPublic ?? true ? "true" : "false",
881
+ "hw.cpu.arch": listFileItem.getContent().abi,
882
+ "hw.cpu.ncore": listFileItem.getContent().cpuNumber,
883
+ "hw.lcd.density": emulatorDeviceItem.getContent().density.toFixed(),
884
+ "hw.lcd.single.diagonalSize": EmulatorTripleFoldItem.is(emulatorDeviceItem) ? emulatorDeviceItem.getContent().singleDiagonalSize.toString() : void 0,
885
+ "hw.lcd.single.height": EmulatorTripleFoldItem.is(emulatorDeviceItem) ? emulatorDeviceItem.getContent().singleResolutionHeight.toString() : void 0,
886
+ "hw.lcd.single.width": EmulatorTripleFoldItem.is(emulatorDeviceItem) ? emulatorDeviceItem.getContent().singleResolutionWidth.toString() : void 0,
887
+ "hw.lcd.double.diagonalSize": EmulatorTripleFoldItem.is(emulatorDeviceItem) ? emulatorDeviceItem.getContent().doubleDiagonalSize.toString() : void 0,
888
+ "hw.lcd.double.height": EmulatorTripleFoldItem.is(emulatorDeviceItem) ? emulatorDeviceItem.getContent().doubleResolutionHeight.toString() : void 0,
889
+ "hw.lcd.double.width": EmulatorTripleFoldItem.is(emulatorDeviceItem) ? emulatorDeviceItem.getContent().doubleResolutionWidth.toString() : void 0,
890
+ "hw.lcd.phy.height": emulatorDeviceItem.getContent().physicalHeight.toString(),
891
+ "hw.lcd.phy.width": emulatorDeviceItem.getContent().physicalWidth.toString(),
892
+ "hw.lcd.number": EmulatorTripleFoldItem.is(emulatorDeviceItem) || EmulatorFoldItem.is(emulatorDeviceItem) ? "2" : "1",
893
+ "hw.ramSize": listFileItem.getContent().memoryRamSize,
894
+ "hw.dataPartitionSize": listFileItem.getContent().dataDiskSize,
895
+ "isCustomize": "true",
896
+ "hw.hdc.port": "notset"
897
+ });
898
+ device.setConfigIniFile(deviceIniFile);
899
+ const namedIniFile = new NamedIniFileImpl(device, NamedIniFileImpl.getFileUri(device), {
900
+ "hvd.ini.encoding": "UTF-8",
901
+ "path": listFileItem.getContent().path
902
+ });
903
+ device.setNamedIniFile(namedIniFile);
904
+ await namedIniFile.write();
905
+ await deviceIniFile.write();
906
+ await listsFile.write();
907
+ return device;
758
908
  }
759
909
  toJSON() {
760
910
  return {
761
- ...this.options,
762
- list: this.buildList(),
763
- ini: this.buildIni()
911
+ ...super.toJSON(),
912
+ sdkPkgFile: this.getSdkPkgFile()
764
913
  };
765
914
  }
766
915
  };
767
- function createDevice(image, options) {
768
- return new DeviceImpl(image, options);
769
- }
770
916
 
771
917
  //#endregion
772
- //#region src/image-downloader.ts
773
- var ImageDownloaderImpl = class {
774
- emitter = mitt();
775
- all = this.emitter.all;
776
- on(type, handler) {
777
- this.emitter.on(type, handler);
918
+ //#region src/errors/request-error.ts
919
+ var RemoteImageRequestError = class extends Error {
920
+ constructor(message, code, cause) {
921
+ super(message, { cause });
922
+ this.message = message;
923
+ this.code = code;
924
+ this.cause = cause;
778
925
  }
779
- off(type, handler) {
780
- this.emitter.off(type, handler);
926
+ };
927
+
928
+ //#endregion
929
+ //#region src/event-emitter.ts
930
+ var EventEmitter = class {
931
+ _listeners = [];
932
+ /**
933
+ * The event listeners can subscribe to.
934
+ */
935
+ event = (listener, thisArgs, disposables) => {
936
+ this._listeners.push([
937
+ listener,
938
+ thisArgs,
939
+ disposables
940
+ ]);
941
+ return { dispose: () => {
942
+ this._listeners = this._listeners.filter((l) => l[0] !== listener && l[1] !== thisArgs && l[2] !== disposables);
943
+ disposables?.forEach((disposable) => disposable.dispose());
944
+ } };
945
+ };
946
+ /**
947
+ * Notify all subscribers of the {@link EventEmitter.event event}. Failure
948
+ * of one or more listener will not fail this function call.
949
+ *
950
+ * @param data The event object.
951
+ */
952
+ fire(data) {
953
+ this._listeners.forEach((listener) => {
954
+ if (listener[1] !== void 0) listener[1].call(listener[2], data);
955
+ else listener[0](data);
956
+ });
781
957
  }
782
- emit(type, event) {
783
- this.emitter.emit(type, event);
958
+ /**
959
+ * Dispose this object and free resources.
960
+ */
961
+ dispose() {
962
+ this._listeners.forEach((listener) => listener[2]?.forEach((disposable) => disposable.dispose()));
963
+ this._listeners = [];
784
964
  }
785
- constructor(image, url) {
786
- this.image = image;
965
+ };
966
+
967
+ //#endregion
968
+ //#region src/image-downloader.ts
969
+ var ImageDownloaderImpl = class {
970
+ constructor(remoteImage, url, abortController = new AbortController()) {
971
+ this.remoteImage = remoteImage;
787
972
  this.url = url;
973
+ this.abortController = abortController;
788
974
  }
789
- getImage() {
790
- return this.image;
975
+ downloadProgressEmitter = new EventEmitter();
976
+ extractProgressEmitter = new EventEmitter();
977
+ checksumProgressEmitter = new EventEmitter();
978
+ onDownloadProgress = this.downloadProgressEmitter.event;
979
+ onExtractProgress = this.extractProgressEmitter.event;
980
+ onChecksumProgress = this.checksumProgressEmitter.event;
981
+ getRemoteImage() {
982
+ return this.remoteImage;
791
983
  }
792
984
  getUrl() {
793
985
  return this.url;
794
986
  }
795
- getCacheFsPath() {
796
- const { path, cachePath } = this.image.getImageManager().getOptions();
797
- return path.resolve(cachePath, path.basename(this.url));
987
+ getCacheUri() {
988
+ const { cachePath, adapter: { URI, join, basename } } = this.remoteImage.getImageManager().getOptions();
989
+ return join(cachePath, basename(URI.parse(this.url)));
798
990
  }
799
- async makeRequest(signal, startByte = 0, retried416 = false) {
800
- const { fs } = this.image.getImageManager().getOptions();
801
- const cacheFsPath = this.getCacheFsPath();
802
- const transformProgress = this.createProgressTransformer(startByte);
991
+ async makeRequest(startByte = 0, retried416 = false) {
992
+ const { adapter: { fs, axios, isAxiosError } } = this.remoteImage.getImageManager().getOptions();
993
+ const cacheUri = this.getCacheUri();
803
994
  try {
804
995
  return await axios.get(this.url, {
805
996
  headers: startByte > 0 ? { Range: `bytes=${startByte}-` } : {},
806
997
  responseType: "stream",
807
998
  validateStatus: (status) => status === 200 || status === 206,
808
- onDownloadProgress: (progress) => this.emit("download-progress", transformProgress(progress)),
809
- signal
999
+ signal: this.abortController.signal
810
1000
  });
811
1001
  } catch (err) {
812
- if (err instanceof AxiosError && err.response?.status === 416 && !retried416) {
813
- if (fs.existsSync(cacheFsPath)) fs.rmSync(cacheFsPath, { force: true });
814
- return this.makeRequest(signal, startByte, true);
1002
+ if (isAxiosError(err) && err.response?.status === 416 && !retried416) {
1003
+ if (await fs.exists(cacheUri)) await fs.delete(cacheUri, { recursive: true });
1004
+ return this.makeRequest(startByte, true);
815
1005
  }
816
1006
  throw err;
817
1007
  }
818
1008
  }
819
- async startDownload(signal, retried416 = false) {
820
- const { fs, cachePath } = this.image.getImageManager().getOptions();
821
- const cacheFsPath = this.getCacheFsPath();
822
- if (!fs.existsSync(cachePath)) fs.mkdirSync(cachePath, { recursive: true });
823
- const startByte = fs.existsSync(cacheFsPath) ? fs.statSync(cacheFsPath).size : 0;
824
- const response = await this.makeRequest(signal, startByte, retried416);
825
- const isPartialContent = response.status === 206;
826
- const start = startByte > 0 && isPartialContent ? startByte : 0;
827
- const flags = start > 0 ? "a" : "w";
828
- if (startByte > 0 && !isPartialContent) fs.rmSync(cacheFsPath, { force: true });
829
- const writeStream = fs.createWriteStream(cacheFsPath, {
830
- flags,
831
- start
832
- });
833
- response.data.pipe(writeStream);
834
- await new Promise((resolve, reject) => {
835
- let settled = false;
836
- const onError = (err) => {
837
- if (settled) return;
838
- settled = true;
839
- response.data.destroy();
840
- writeStream.destroy();
841
- reject(err);
842
- };
843
- const onFinish = () => {
844
- if (settled) return;
845
- settled = true;
846
- resolve();
847
- };
848
- response.data.on("error", onError);
849
- writeStream.on("error", onError);
850
- response.data.on("end", () => writeStream.end());
851
- writeStream.on("finish", onFinish);
1009
+ /** 获取文件总大小。206 时从 Content-Range total,200 时从 Content-Length 取。 */
1010
+ parseTotalBytes(response) {
1011
+ const contentRange = response.headers["content-range"];
1012
+ if (contentRange) {
1013
+ const match = contentRange.match(/bytes \d+-\d+\/(\d+)/);
1014
+ if (match) return Number.parseInt(match[1], 10);
1015
+ }
1016
+ const contentLength = response.headers["content-length"];
1017
+ if (contentLength) return Number.parseInt(contentLength, 10);
1018
+ return null;
1019
+ }
1020
+ createDownloadProgressTransformer(startByte, totalBytes) {
1021
+ let receivedBytes = startByte;
1022
+ let lastReportedBytes = startByte;
1023
+ let lastReportedProgress = totalBytes != null && totalBytes > 0 ? Math.round(startByte / totalBytes * 1e4) / 100 : 0;
1024
+ let lastReportTime = performance.now();
1025
+ const reportThreshold = 64 * 1024;
1026
+ const report = () => {
1027
+ const now = performance.now();
1028
+ const bytesSinceLastReport = receivedBytes - lastReportedBytes;
1029
+ const timeDeltaSec = (now - lastReportTime) / 1e3;
1030
+ lastReportedBytes = receivedBytes;
1031
+ lastReportTime = now;
1032
+ const progress = totalBytes != null && totalBytes > 0 ? Math.min(100, Math.round(receivedBytes / totalBytes * 1e4) / 100) : 0;
1033
+ const increment = Math.round((progress - lastReportedProgress) * 100) / 100;
1034
+ lastReportedProgress = progress;
1035
+ const speedKBps = timeDeltaSec > 0 && bytesSinceLastReport > 0 ? bytesSinceLastReport / 1024 / timeDeltaSec : 0;
1036
+ const unit = speedKBps >= 1024 ? "MB" : "KB";
1037
+ const network = unit === "MB" ? speedKBps / 1024 : speedKBps;
1038
+ const roundedProgress = Math.round(progress * 100) / 100;
1039
+ const clampedIncrement = Math.max(0, Math.min(100, increment));
1040
+ if (clampedIncrement > 0) this.downloadProgressEmitter.fire({
1041
+ progressType: "download",
1042
+ increment: clampedIncrement,
1043
+ progress: roundedProgress,
1044
+ network: Math.round(network * 100) / 100,
1045
+ unit
1046
+ });
1047
+ };
1048
+ return new TransformStream({
1049
+ transform: (chunk, controller) => {
1050
+ receivedBytes += chunk.length;
1051
+ controller.enqueue(chunk);
1052
+ if (receivedBytes - lastReportedBytes >= reportThreshold) report();
1053
+ },
1054
+ flush: () => {
1055
+ if (receivedBytes !== lastReportedBytes) report();
1056
+ }
852
1057
  });
853
1058
  }
854
- async checkChecksum(signal) {
855
- const { crypto, fs } = this.image.getImageManager().getOptions();
856
- const checksum = this.image.getChecksum();
857
- const hash = crypto.createHash("sha256", { signal });
858
- const stream = fs.createReadStream(this.getCacheFsPath(), { signal });
859
- stream.on("data", (chunk) => hash.update(chunk));
860
- await new Promise((resolve, reject) => stream.on("end", resolve).on("error", reject));
861
- return hash.digest("hex") === checksum;
862
- }
863
- async extract(signal, symlinkOpenHarmonySdk = true) {
864
- const unzipper = await import("unzipper");
865
- const { fs, path, imageBasePath, sdkPath } = this.image.getImageManager().getOptions();
866
- const cacheFsPath = this.getCacheFsPath();
867
- const stream = fs.createReadStream(cacheFsPath, { signal });
868
- const progressStream = progress({ length: fs.statSync(cacheFsPath).size });
869
- const extractStream = unzipper.Extract({ path: this.image.getFsPath() });
870
- progressStream.on("progress", (progress) => this.emitter.emit("extract-progress", progress));
871
- stream.pipe(progressStream).pipe(extractStream);
872
- await extractStream.promise();
873
- if (symlinkOpenHarmonySdk) {
874
- const symlinkSdkPath = path.resolve(imageBasePath, "default", "openharmony");
875
- if (!fs.existsSync(path.dirname(symlinkSdkPath))) fs.mkdirSync(path.dirname(symlinkSdkPath), { recursive: true });
876
- if (!fs.existsSync(symlinkSdkPath)) fs.symlinkSync(sdkPath, symlinkSdkPath, "dir");
1059
+ async startDownload(retried416 = false) {
1060
+ const { adapter: { fs, toWeb, dirname } } = this.remoteImage.getImageManager().getOptions();
1061
+ const cacheUri = this.getCacheUri();
1062
+ if (!await fs.exists(dirname(cacheUri))) await fs.createDirectory(dirname(cacheUri));
1063
+ const startByte = await fs.stat(cacheUri).then((stat) => stat.size ?? 0, () => 0);
1064
+ const response = await this.makeRequest(startByte, retried416);
1065
+ const totalBytes = this.parseTotalBytes(response);
1066
+ if (startByte > 0 && totalBytes != null && totalBytes > 0) {
1067
+ const startProgress = Math.round(startByte / totalBytes * 1e4) / 100;
1068
+ this.downloadProgressEmitter.fire({
1069
+ progressType: "download",
1070
+ increment: 0,
1071
+ progress: Math.min(100, startProgress),
1072
+ network: 0,
1073
+ unit: "KB",
1074
+ reset: true
1075
+ });
877
1076
  }
878
- }
879
- async clean() {
880
- const { fs } = this.image.getImageManager().getOptions();
881
- const cacheFsPath = this.getCacheFsPath();
882
- if (fs.existsSync(cacheFsPath)) fs.rmSync(cacheFsPath, { recursive: true });
883
- }
884
- createProgressTransformer(startByte) {
885
- let previousPercentage = 0;
886
- const bytesPerKB = 1024;
887
- const bytesPerMB = bytesPerKB * 1024;
888
- return (progress) => {
889
- const rangeTotal = progress.total ?? 0;
890
- const rangeLoaded = progress.loaded ?? 0;
891
- const total = startByte + rangeTotal;
892
- const loaded = startByte + rangeLoaded;
893
- const percentage = total > 0 ? loaded / total * 100 : 0;
894
- const increment = Math.max(0, percentage - previousPercentage);
895
- previousPercentage = percentage;
896
- const rate = progress.rate ?? 0;
897
- const unit = rate >= bytesPerMB ? "MB" : "KB";
898
- const network = unit === "MB" ? rate / bytesPerMB : rate / bytesPerKB;
899
- return {
900
- ...progress,
901
- total,
902
- loaded,
903
- network,
904
- unit,
905
- increment
906
- };
1077
+ const writableStream = await fs.createWritableStream(cacheUri, startByte > 0 ? { flags: WriteableFlags.Append } : void 0);
1078
+ const webReadable = toWeb(response.data);
1079
+ const progressTransform = this.createDownloadProgressTransformer(startByte, totalBytes);
1080
+ await webReadable.pipeThrough(progressTransform).pipeTo(writableStream);
1081
+ }
1082
+ createChecksumProgressTransformer(totalBytes, hash) {
1083
+ let readBytes = 0;
1084
+ let lastReportedBytes = 0;
1085
+ let lastReportedProgress = 0;
1086
+ const reportThreshold = 64 * 1024;
1087
+ const report = () => {
1088
+ const progress = totalBytes > 0 ? Math.min(100, Math.round(readBytes / totalBytes * 1e4) / 100) : 0;
1089
+ const increment = Math.round((progress - lastReportedProgress) * 100) / 100;
1090
+ lastReportedBytes = readBytes;
1091
+ lastReportedProgress = progress;
1092
+ const clampedIncrement = Math.max(0, Math.min(100, increment));
1093
+ if (clampedIncrement > 0) this.checksumProgressEmitter.fire({
1094
+ progressType: "checksum",
1095
+ increment: clampedIncrement,
1096
+ progress: Math.round(progress * 100) / 100
1097
+ });
907
1098
  };
1099
+ return new TransformStream({
1100
+ transform: (chunk, controller) => {
1101
+ const chunkLength = chunk ? chunk.byteLength ?? chunk.length ?? 0 : 0;
1102
+ if (chunk) hash.update(chunk);
1103
+ readBytes += chunkLength;
1104
+ controller.enqueue(chunk);
1105
+ if (readBytes - lastReportedBytes >= reportThreshold) report();
1106
+ },
1107
+ flush: () => {
1108
+ if (readBytes !== lastReportedBytes) report();
1109
+ }
1110
+ });
1111
+ }
1112
+ async checkChecksum() {
1113
+ const { adapter: { fs, crypto } } = this.remoteImage.getImageManager().getOptions();
1114
+ const cacheUri = this.getCacheUri();
1115
+ const totalBytes = await fs.stat(cacheUri).then((stat) => stat.size ?? 0, () => 0);
1116
+ const readableStream = await fs.createReadableStream(cacheUri);
1117
+ const hash = crypto.createHash("sha256");
1118
+ const progressTransform = this.createChecksumProgressTransformer(totalBytes, hash);
1119
+ await readableStream.pipeThrough(progressTransform).pipeTo(new WritableStream(), { signal: this.abortController.signal });
1120
+ return hash.digest("hex") === this.getRemoteImage().getRemoteImageSDK().archive?.complete?.checksum;
1121
+ }
1122
+ async extract() {
1123
+ const { adapter: { fs, unzipper, fromWeb } } = this.remoteImage.getImageManager().getOptions();
1124
+ const cacheUri = this.getCacheUri();
1125
+ const totalBytes = await fs.stat(cacheUri).then((stat) => stat.size ?? 0, () => 0);
1126
+ const extract = unzipper.Extract({ path: this.getRemoteImage().getFullPath().fsPath });
1127
+ const webReadable = await fs.createReadableStream(cacheUri);
1128
+ let readBytes = 0;
1129
+ let lastReportedBytes = 0;
1130
+ let lastReportedProgress = 0;
1131
+ const reportThreshold = 64 * 1024;
1132
+ const copyAndProgressTransform = new TransformStream({
1133
+ transform: (chunk, controller) => {
1134
+ const chunkLength = chunk?.length ?? 0;
1135
+ if (chunkLength <= 0) return;
1136
+ readBytes += chunkLength;
1137
+ if (readBytes - lastReportedBytes >= reportThreshold) {
1138
+ const progress = totalBytes > 0 ? Math.min(100, Math.round(readBytes / totalBytes * 1e4) / 100) : 0;
1139
+ const increment = Math.round((progress - lastReportedProgress) * 100) / 100;
1140
+ lastReportedBytes = readBytes;
1141
+ lastReportedProgress = progress;
1142
+ const clampedIncrement = Math.max(0, Math.min(100, increment));
1143
+ if (clampedIncrement > 0) this.extractProgressEmitter.fire({
1144
+ progressType: "extract",
1145
+ increment: clampedIncrement,
1146
+ progress: Math.round(progress * 100) / 100
1147
+ });
1148
+ }
1149
+ controller.enqueue(chunk.slice(0));
1150
+ },
1151
+ flush: () => {
1152
+ if (readBytes !== lastReportedBytes) {
1153
+ const increment = Math.round((100 - lastReportedProgress) * 100) / 100;
1154
+ const clampedIncrement = Math.max(0, Math.min(100, increment));
1155
+ if (clampedIncrement > 0) this.extractProgressEmitter.fire({
1156
+ progressType: "extract",
1157
+ increment: clampedIncrement,
1158
+ progress: 100
1159
+ });
1160
+ }
1161
+ }
1162
+ });
1163
+ const readable = fromWeb(webReadable.pipeThrough(copyAndProgressTransform));
1164
+ const abortHandler = () => readable.destroy(new DOMException("Aborted", "AbortError"));
1165
+ this.abortController.signal.addEventListener("abort", abortHandler);
1166
+ readable.pipe(extract);
1167
+ await extract.promise().finally(() => this.abortController.signal.removeEventListener("abort", abortHandler));
908
1168
  }
909
1169
  };
910
- function createImageDownloader(image, url) {
911
- return new ImageDownloaderImpl(image, url);
912
- }
913
1170
 
914
1171
  //#endregion
915
- //#region src/images/image.ts
916
- var ImageBase = class {
917
- constructor(response, imageManager, resolvedFsPath) {
918
- this.response = response;
919
- this.imageManager = imageManager;
920
- this.resolvedFsPath = resolvedFsPath;
921
- }
922
- getImageManager() {
923
- return this.imageManager;
924
- }
925
- getArch() {
926
- const [, , deviceTypeWithArch] = this.getPath()?.split(",") ?? [];
927
- const split = deviceTypeWithArch?.split("_") ?? [];
928
- return split[split.length - 1];
929
- }
930
- getPath() {
931
- return this.response?.path;
932
- }
933
- getChecksum() {
934
- return this.response?.archive?.complete?.checksum;
935
- }
936
- getReleaseType() {
937
- return this.response?.releaseType;
938
- }
939
- getFsPath() {
940
- return this.resolvedFsPath;
941
- }
942
- async isDownloaded() {
943
- return this.imageManager.getOptions().fs.existsSync(this.getFsPath()) && this.imageManager.getOptions().fs.statSync(this.getFsPath()).isDirectory();
944
- }
945
- getVersion() {
946
- return this.response?.version;
947
- }
948
- getApiVersion() {
949
- return this.response?.apiVersion;
950
- }
951
- getTargetOS() {
952
- const [, systemNameWithVersion] = this.getPath()?.split(",") ?? [];
953
- const [systemName] = systemNameWithVersion?.split("-") ?? [];
954
- return systemName ?? "";
1172
+ //#region src/images/remote-image.ts
1173
+ let RemoteImage;
1174
+ (function(_RemoteImage) {
1175
+ function is(value) {
1176
+ return value instanceof RemoteImageImpl;
955
1177
  }
956
- getTargetVersion() {
957
- const [, systemNameWithVersion] = this.getPath()?.split(",") ?? [];
958
- const [, version] = systemNameWithVersion?.split("-") ?? [];
959
- return version ?? "";
1178
+ _RemoteImage.is = is;
1179
+ })(RemoteImage || (RemoteImage = {}));
1180
+ var RemoteImageImpl = class extends BaseImageImpl {
1181
+ imageType = "remote";
1182
+ constructor(imageManager, remoteImageSDK = {}) {
1183
+ super({
1184
+ imageManager,
1185
+ relativePath: remoteImageSDK.path?.split(",").join("/") ?? "",
1186
+ apiVersion: remoteImageSDK.apiVersion ? Number.parseInt(remoteImageSDK.apiVersion) : 0
1187
+ });
1188
+ this.imageManager = imageManager;
1189
+ this.remoteImageSDK = remoteImageSDK;
960
1190
  }
961
- getDeviceType() {
962
- const [, , deviceTypeWithArch] = this.getPath()?.split(",") ?? [];
963
- const [deviceType] = deviceTypeWithArch?.split("_") ?? [];
964
- return deviceType ?? "";
1191
+ getRemoteImageSDK() {
1192
+ return this.remoteImageSDK;
965
1193
  }
966
- getSnakecaseDeviceType() {
967
- const deviceType = this.getDeviceType();
968
- if (deviceType === "pc") return "2in1_foldable";
969
- return deviceType.toLowerCase();
1194
+ getFullDeviceType() {
1195
+ const name = this.getRemoteImageSDK().displayName?.split("-");
1196
+ return name?.[name.length - 1];
970
1197
  }
971
- async createDownloader() {
972
- const url = await this.getUrl();
973
- if (url instanceof RequestUrlError) return url;
974
- return createImageDownloader(this, url);
1198
+ _localImage;
1199
+ async getLocalImage(force = false) {
1200
+ if (!force && this._localImage) return this._localImage;
1201
+ this._localImage = (await this.getImageManager().getLocalImages()).find((localImage) => localImage.getFullPath().toString() === this.getFullPath().toString());
1202
+ return this._localImage;
975
1203
  }
976
- async getUrl() {
1204
+ async createDownloader(signals) {
1205
+ const { adapter: { axios, isAxiosError } } = this.imageManager.getOptions();
977
1206
  try {
978
1207
  const response = await axios.post("https://devecostudio-drcn.deveco.dbankcloud.com/sdkmanager/v7/hos/download", {
979
- osArch: this.imageManager.getArch(),
980
- osType: this.imageManager.getOS(),
1208
+ osArch: this.getImageManager().getArch(),
1209
+ osType: this.getImageManager().getOperatingSystem(),
981
1210
  path: {
982
- path: this.getPath(),
983
- version: this.getVersion()
1211
+ path: this.getRemoteImageSDK().path,
1212
+ version: this.getRemoteImageSDK().version
984
1213
  },
985
1214
  imei: "d490a470-8719-4baf-9cc4-9c78d40d"
986
1215
  });
987
- if (typeof response.data?.url !== "string") return new RequestUrlError(response.data?.body, response.data?.code);
988
- return response.data.url;
1216
+ if (typeof response.data?.url !== "string") throw new RemoteImageRequestError(response.data?.body, response.data?.code);
1217
+ return new ImageDownloaderImpl(this, response.data.url, signals);
989
1218
  } catch (error) {
990
- return new RequestUrlError(error.message, error.code, error);
1219
+ if (isAxiosError(error)) throw new RemoteImageRequestError(error.message, Number(error.code), error);
1220
+ if (error instanceof Error) throw new RemoteImageRequestError(error.message, -1, error);
1221
+ throw new RemoteImageRequestError("Unknown request error.", -1, error);
991
1222
  }
992
1223
  }
993
1224
  toJSON() {
994
1225
  return {
995
- imageType: this.imageType,
996
- arch: this.getArch(),
997
- path: this.getPath(),
998
- checksum: this.getChecksum(),
999
- fsPath: this.getFsPath(),
1000
- version: this.getVersion(),
1001
- apiVersion: this.getApiVersion(),
1002
- targetOS: this.getTargetOS(),
1003
- targetVersion: this.getTargetVersion(),
1004
- deviceType: this.getDeviceType(),
1005
- snakecaseDeviceType: this.getSnakecaseDeviceType()
1226
+ ...super.toJSON(),
1227
+ remoteImageSDK: this.getRemoteImageSDK()
1006
1228
  };
1007
1229
  }
1008
1230
  };
1009
1231
 
1010
1232
  //#endregion
1011
- //#region src/images/local-image.ts
1012
- var LocalImageImpl = class extends ImageBase {
1013
- imageType = "local";
1014
- createDevice(options) {
1015
- return createDevice(this, options);
1016
- }
1017
- async getPascalCaseDeviceType() {
1018
- const deviceType = this.getDeviceType().toLowerCase();
1019
- if (!deviceType) return;
1020
- if (deviceType === "pc") return "2in1 Foldable";
1021
- const key = [
1022
- "phone",
1023
- "tablet",
1024
- "2in1",
1025
- "foldable",
1026
- "widefold",
1027
- "triplefold",
1028
- "2in1 foldable",
1029
- "tv",
1030
- "wearable"
1031
- ].find((key) => key === deviceType);
1032
- if (key) return key;
1033
- }
1034
- async getProductConfig(usingDefaultProductConfig = false) {
1035
- const productConfig = usingDefaultProductConfig ? (await import("./default-product-config.mjs")).default : await this.getImageManager().getProductConfig();
1036
- const deviceType = this.getDeviceType().toLowerCase();
1037
- if (!deviceType) return [];
1038
- if (deviceType === "pc") return productConfig["2in1 Foldable"] ?? [];
1039
- const key = Object.keys(productConfig).find((key) => key.toLowerCase() === deviceType);
1040
- if (key) return productConfig[key] ?? [];
1041
- return [];
1042
- }
1043
- async delete() {
1044
- const { fs } = this.getImageManager().getOptions();
1045
- const path = this.getFsPath();
1046
- if (!fs.existsSync(path) || !fs.statSync(path).isDirectory()) return /* @__PURE__ */ new Error("Image path does not exist");
1047
- fs.rmSync(path, { recursive: true });
1048
- const devices = await this.getDevices();
1049
- const error = await Promise.allSettled(devices.map((device) => device.delete())).then((results) => results.find((result) => result.status === "rejected"));
1050
- if (error) return error.reason;
1051
- }
1052
- getExecutablePath() {
1053
- const { emulatorPath, process, path } = this.getImageManager().getOptions();
1054
- return process.platform === "win32" ? path.join(emulatorPath, "Emulator.exe") : path.join(emulatorPath, "Emulator");
1055
- }
1056
- async buildStartCommand(device) {
1057
- const config = device.buildList();
1058
- return `${this.getExecutablePath()} ${[
1059
- "-hvd",
1060
- `"${config.name.replace(/"/g, "\\\"")}"`,
1061
- "-path",
1062
- `"${this.getImageManager().getOptions().deployedPath.replace(/"/g, "\\\"")}"`,
1063
- "-imageRoot",
1064
- `"${this.getImageManager().getOptions().imageBasePath.replace(/"/g, "\\\"")}"`
1065
- ].join(" ")}`;
1066
- }
1067
- async start(deployer) {
1068
- const { child_process, emulatorPath } = this.getImageManager().getOptions();
1069
- return child_process.exec(await this.buildStartCommand(deployer), { cwd: emulatorPath });
1070
- }
1071
- async buildStopCommand(device) {
1072
- const config = device.buildList();
1073
- return `${this.getExecutablePath()} ${["-stop", `"${config.name.replace(/"/g, "\\\"")}"`].join(" ")}`;
1074
- }
1075
- async stop(device) {
1076
- const { child_process, emulatorPath } = this.getImageManager().getOptions();
1077
- return child_process.exec(await this.buildStopCommand(device), { cwd: emulatorPath });
1078
- }
1079
- async createScreenLike(listsJsonItem) {
1080
- const productConfig = await this.getImageManager().getProductConfig();
1081
- const pascalCaseDeviceType = await this.getPascalCaseDeviceType();
1082
- const screen = createScreen({
1083
- diagonal: Number(listsJsonItem.diagonalSize),
1084
- height: Number(listsJsonItem.resolutionHeight),
1085
- width: Number(listsJsonItem.resolutionWidth),
1086
- density: Number(listsJsonItem.density),
1087
- deviceType: listsJsonItem.type,
1088
- apiVersion: Number(listsJsonItem.apiVersion),
1089
- cover: listsJsonItem.coverResolutionWidth && listsJsonItem.coverResolutionHeight && listsJsonItem.coverDiagonalSize ? {
1090
- height: Number(listsJsonItem.coverResolutionHeight),
1091
- width: Number(listsJsonItem.coverResolutionWidth),
1092
- diagonal: Number(listsJsonItem.coverDiagonalSize)
1093
- } : void 0
1094
- });
1095
- if (pascalCaseDeviceType) {
1096
- const productConfigItem = productConfig[pascalCaseDeviceType]?.find((item) => item.name === listsJsonItem.model);
1097
- if (productConfigItem && productConfigItem.outerScreenWidth && productConfigItem.outerScreenHeight && productConfigItem.outerScreenDiagonal) screen.setOuterScreen(createOuterScreen({
1098
- width: Number(productConfigItem.outerScreenWidth),
1099
- height: Number(productConfigItem.outerScreenHeight),
1100
- diagonal: Number(productConfigItem.outerScreenDiagonal)
1101
- }, screen));
1102
- if (productConfigItem && productConfigItem.outerDoubleScreenWidth && productConfigItem.outerDoubleScreenHeight && productConfigItem.outerDoubleScreenDiagonal) screen.getOuterScreen()?.setOuterDoubleScreen(createOuterDoubleScreen({
1103
- width: Number(productConfigItem.outerDoubleScreenWidth),
1104
- height: Number(productConfigItem.outerDoubleScreenHeight),
1105
- diagonal: Number(productConfigItem.outerDoubleScreenDiagonal)
1106
- }, screen.getOuterScreen()));
1233
+ //#region src/options.ts
1234
+ let OptionsResolver;
1235
+ (function(_OptionsResolver) {
1236
+ async function resolveAdapter(adapter) {
1237
+ const mergedAdapter = {
1238
+ os: adapter?.os ?? await import("node:os"),
1239
+ process: adapter?.process ?? await import("node:process"),
1240
+ crypto: adapter?.crypto ?? await import("node:crypto"),
1241
+ child_process: adapter?.child_process ?? await import("node:child_process"),
1242
+ axios: adapter?.axios ?? (await import("axios")).default,
1243
+ fs: adapter?.fs ?? await createNodeFileSystem(),
1244
+ join: adapter?.join ?? (await import("vscode-uri")).Utils.joinPath,
1245
+ URI: adapter?.URI ?? (await import("vscode-uri")).URI,
1246
+ dirname: adapter?.dirname ?? (await import("vscode-uri")).Utils.dirname,
1247
+ basename: adapter?.basename ?? (await import("vscode-uri")).Utils.basename,
1248
+ toWeb: adapter?.toWeb ?? (await import("node:stream")).Readable.toWeb,
1249
+ fromWeb: adapter?.fromWeb ?? (await import("node:stream")).Readable.fromWeb,
1250
+ unzipper: adapter?.unzipper ?? await import("unzipper")
1251
+ };
1252
+ if (adapter?.isAxiosError) mergedAdapter.isAxiosError = adapter.isAxiosError;
1253
+ else {
1254
+ const axios = await import("axios");
1255
+ mergedAdapter.isAxiosError = (error) => axios.isAxiosError(error);
1107
1256
  }
1108
- const screenPreset = new ScreenPresetImpl({
1109
- screen,
1110
- productConfig,
1111
- emulatorConfig: await this.getImageManager().getEmulatorConfig()
1112
- });
1113
- if (screenPreset.getProductPreset() || screenPreset.getEmulatorPreset()) return screenPreset;
1114
- else return screen;
1115
- }
1116
- async getDevices() {
1117
- const { path, fs, deployedPath, imageBasePath } = this.getImageManager().getOptions();
1118
- const listsJsonPath = path.resolve(deployedPath, "lists.json");
1119
- if (!fs.existsSync(listsJsonPath) || !fs.statSync(listsJsonPath).isFile()) return [];
1120
- const listsJson = JSON.parse(fs.readFileSync(listsJsonPath, "utf-8"));
1121
- if (!Array.isArray(listsJson) || this.imageType !== "local") return [];
1122
- const devices = [];
1123
- for (const listsJsonItem of listsJson) {
1124
- if (path.resolve(imageBasePath, listsJsonItem.imageDir) !== this.getFsPath()) continue;
1125
- const iniFilePath = path.resolve(listsJsonItem.path, "config.ini");
1126
- if (!fs.existsSync(iniFilePath) || !fs.statSync(iniFilePath).isFile()) continue;
1127
- const device = this.createDevice({
1128
- name: listsJsonItem.name,
1129
- cpuNumber: Number(listsJsonItem.cpuNumber),
1130
- diskSize: Number(listsJsonItem.dataDiskSize),
1131
- memorySize: Number(listsJsonItem.memoryRamSize),
1132
- screen: await this.createScreenLike(listsJsonItem)
1133
- });
1134
- device.setUuid(listsJsonItem.uuid).setCachedList(listsJsonItem).setCachedIni(INI.parse(fs.readFileSync(iniFilePath, "utf-8")));
1135
- if (!fs.existsSync(listsJsonItem.path) || !fs.statSync(listsJsonItem.path).isDirectory()) continue;
1136
- devices.push(device);
1257
+ return mergedAdapter;
1258
+ }
1259
+ _OptionsResolver.resolveAdapter = resolveAdapter;
1260
+ async function resolveImageManagerOptions(options) {
1261
+ const adapter = await resolveAdapter(options.adapter);
1262
+ const { os, join, process, URI } = adapter;
1263
+ function resolveDefaultImageBasePath() {
1264
+ switch (process.platform) {
1265
+ case "win32": return typeof process.env.APPDATA === "string" && process.env.APPDATA.length > 0 ? join(URI.file(process.env.APPDATA), "Local", "Huawei", "Sdk") : join(URI.file(os.homedir()), "AppData", "Local", "Huawei", "Sdk");
1266
+ case "darwin": return join(URI.file(os.homedir()), "Library", "Huawei", "Sdk");
1267
+ default: return join(URI.file(os.homedir()), ".huawei", "Sdk");
1268
+ }
1137
1269
  }
1138
- return devices;
1139
- }
1140
- toJSON() {
1270
+ function resolveDefaultDeployedPath() {
1271
+ switch (process.platform) {
1272
+ case "win32": return typeof process.env.APPDATA === "string" && process.env.APPDATA.length > 0 ? join(URI.file(process.env.APPDATA), "Local", "Huawei", "Emulator", "deployed") : join(URI.file(os.homedir()), "AppData", "Local", "Huawei", "Emulator", "deployed");
1273
+ default: return join(URI.file(os.homedir()), ".huawei", "Emulator", "deployed");
1274
+ }
1275
+ }
1276
+ function resolveDefaultSdkPath() {
1277
+ switch (process.platform) {
1278
+ case "darwin": return URI.file("/Applications/DevEco-Studio.app/Contents/sdk/default/openharmony");
1279
+ case "win32": return URI.file("C:\\Program Files\\Huawei\\DevEco Studio\\sdk\\default\\openharmony");
1280
+ default: return join(URI.file(os.homedir()), ".huawei", "Sdk", "default", "openharmony");
1281
+ }
1282
+ }
1283
+ function resolveDefaultConfigPath() {
1284
+ switch (process.platform) {
1285
+ case "darwin": return join(URI.file(os.homedir()), "Library", "Application Support", "Huawei", "DevEcoStudio6.0");
1286
+ case "win32": return join(URI.file(process.env.APPDATA ?? os.homedir()), "Roaming", "Huawei", "DevEcoStudio6.0");
1287
+ default: return join(URI.file(os.homedir()), ".huawei", "DevEcoStudio6.0");
1288
+ }
1289
+ }
1290
+ function resolveDefaultLogPath() {
1291
+ switch (process.platform) {
1292
+ case "darwin": return join(URI.file(os.homedir()), "Library", "Logs", "Huawei", "DevEcoStudio6.0");
1293
+ case "win32": return join(URI.file(process.env.APPDATA ?? os.homedir()), "Local", "Huawei", "DevEcoStudio6.0", "log");
1294
+ default: return join(URI.file(os.homedir()), ".huawei", "DevEcoStudio6.0", "log");
1295
+ }
1296
+ }
1297
+ function resolveDefaultEmulatorPath() {
1298
+ switch (process.platform) {
1299
+ case "darwin": return URI.file("/Applications/DevEco-Studio.app/Contents/tools/emulator");
1300
+ case "win32": return URI.file("C:\\Program Files\\Huawei\\DevEco Studio\\tools\\emulator");
1301
+ default: return join(URI.file(os.homedir()), ".huawei", "Emulator");
1302
+ }
1303
+ }
1304
+ const imageBasePath = typeof options.imageBasePath === "string" ? URI.file(options.imageBasePath) : options.imageBasePath || resolveDefaultImageBasePath();
1305
+ const cachePath = typeof options.cachePath === "string" ? URI.file(options.cachePath) : options.cachePath || join(imageBasePath, "cache");
1141
1306
  return {
1142
- ...super.toJSON(),
1143
- executablePath: this.getExecutablePath()
1307
+ imageBasePath,
1308
+ deployedPath: typeof options.deployedPath === "string" ? URI.file(options.deployedPath) : options.deployedPath || resolveDefaultDeployedPath(),
1309
+ cachePath,
1310
+ sdkPath: typeof options.sdkPath === "string" ? URI.file(options.sdkPath) : options.sdkPath || resolveDefaultSdkPath(),
1311
+ configPath: typeof options.configPath === "string" ? URI.file(options.configPath) : options.configPath || resolveDefaultConfigPath(),
1312
+ logPath: typeof options.logPath === "string" ? URI.file(options.logPath) : options.logPath || resolveDefaultLogPath(),
1313
+ emulatorPath: typeof options.emulatorPath === "string" ? URI.file(options.emulatorPath) : options.emulatorPath || resolveDefaultEmulatorPath(),
1314
+ adapter
1144
1315
  };
1145
1316
  }
1146
- };
1317
+ _OptionsResolver.resolveImageManagerOptions = resolveImageManagerOptions;
1318
+ })(OptionsResolver || (OptionsResolver = {}));
1147
1319
 
1148
1320
  //#endregion
1149
- //#region src/images/remote-image.ts
1150
- var RemoteImageImpl = class extends ImageBase {
1151
- imageType = "remote";
1152
- toJSON() {
1153
- return super.toJSON();
1321
+ //#region src/sdk-list.ts
1322
+ let SDKList;
1323
+ (function(_SDKList) {
1324
+ function isOKResponse(result) {
1325
+ return "data" in result && Array.isArray(result.data);
1326
+ }
1327
+ _SDKList.isOKResponse = isOKResponse;
1328
+ class SDKListError extends Error {
1329
+ constructor(code, message, cause) {
1330
+ super(message);
1331
+ this.code = code;
1332
+ this.message = message;
1333
+ this.cause = cause;
1334
+ }
1154
1335
  }
1155
- };
1336
+ _SDKList.SDKListError = SDKListError;
1337
+ (function(_SDKListError) {
1338
+ _SDKListError.Code = /* @__PURE__ */ function(Code) {
1339
+ Code[Code["VALIDATION_ERROR"] = 400] = "VALIDATION_ERROR";
1340
+ Code[Code["REQUEST_ERROR"] = 500] = "REQUEST_ERROR";
1341
+ return Code;
1342
+ }({});
1343
+ })(SDKListError || (SDKListError = _SDKList.SDKListError || (_SDKList.SDKListError = {})));
1344
+ })(SDKList || (SDKList = {}));
1156
1345
 
1157
1346
  //#endregion
1158
- //#region src/options.ts
1159
- async function resolveImageManagerOptions(options) {
1160
- const os = options.os ?? await import("node:os");
1161
- const path = options.path ?? await import("node:path");
1162
- const process = options.process ?? await import("node:process");
1163
- function resolveDefaultImageBasePath() {
1164
- switch (process.platform) {
1165
- case "win32": return typeof process.env.APPDATA === "string" && process.env.APPDATA.length > 0 ? path.resolve(process.env.APPDATA, "Local", "Huawei", "Sdk") : path.resolve(os.homedir(), "AppData", "Local", "Huawei", "Sdk");
1166
- case "darwin": return path.resolve(os.homedir(), "Library", "Huawei", "Sdk");
1167
- default: return path.resolve(os.homedir(), ".huawei", "Sdk");
1168
- }
1169
- }
1170
- function resolveDefaultDeployedPath() {
1171
- switch (process.platform) {
1172
- case "win32": return typeof process.env.APPDATA === "string" && process.env.APPDATA.length > 0 ? path.resolve(process.env.APPDATA, "Local", "Huawei", "Emulator", "deployed") : path.resolve(os.homedir(), "AppData", "Local", "Huawei", "Emulator", "deployed");
1173
- default: return path.resolve(os.homedir(), ".huawei", "Emulator", "deployed");
1174
- }
1175
- }
1176
- function resolveDefaultSdkPath() {
1177
- switch (process.platform) {
1178
- case "darwin": return "/Applications/DevEco-Studio.app/Contents/sdk/default/openharmony";
1179
- case "win32": return "C:\\Program Files\\Huawei\\DevEco Studio\\sdk\\default\\openharmony";
1180
- default: return path.resolve(os.homedir(), ".huawei", "Sdk", "default", "openharmony");
1181
- }
1182
- }
1183
- function resolveDefaultConfigPath() {
1184
- switch (process.platform) {
1185
- case "darwin": return path.resolve(os.homedir(), "Library", "Application Support", "Huawei", "DevEcoStudio6.0");
1186
- case "win32": return path.resolve(process.env.APPDATA ?? os.homedir(), "Roaming", "Huawei", "DevEcoStudio6.0");
1187
- default: return path.resolve(os.homedir(), ".huawei", "DevEcoStudio6.0");
1347
+ //#region src/utils/devicetype-converter.ts
1348
+ let DeviceTypeConverter;
1349
+ (function(_DeviceTypeConverter) {
1350
+ function snakecaseToCamelcase(snakecaseDeviceType) {
1351
+ switch (snakecaseDeviceType) {
1352
+ case "phone": return "Phone";
1353
+ case "2in1": return "2in1";
1354
+ case "2in1_foldable": return "2in1 Foldable";
1355
+ case "foldable": return "Foldable";
1356
+ case "tablet": return "Tablet";
1357
+ case "triplefold": return "TripleFold";
1358
+ case "tv": return "TV";
1359
+ case "wearable": return "Wearable";
1360
+ case "widefold": return "WideFold";
1361
+ default: return snakecaseDeviceType.toLowerCase().split("_").join(" ");
1188
1362
  }
1189
1363
  }
1190
- function resolveDefaultLogPath() {
1191
- switch (process.platform) {
1192
- case "darwin": return path.resolve(os.homedir(), "Library", "Logs", "Huawei", "DevEcoStudio6.0");
1193
- case "win32": return path.resolve(process.env.APPDATA ?? os.homedir(), "Local", "Huawei", "DevEcoStudio6.0", "log");
1194
- default: return path.resolve(os.homedir(), ".huawei", "DevEcoStudio6.0", "log");
1195
- }
1196
- }
1197
- function resolveDefaultEmulatorPath() {
1198
- switch (process.platform) {
1199
- case "darwin": return "/Applications/DevEco-Studio.app/Contents/tools/emulator";
1200
- case "win32": return "C:\\Program Files\\Huawei\\DevEco Studio\\tools\\emulator";
1201
- default: return path.resolve(os.homedir(), ".huawei", "Emulator");
1202
- }
1203
- }
1204
- const imageBasePath = options.imageBasePath || resolveDefaultImageBasePath();
1205
- const cachePath = options.cachePath || path.resolve(imageBasePath, "cache");
1206
- return {
1207
- imageBasePath,
1208
- deployedPath: options.deployedPath || resolveDefaultDeployedPath(),
1209
- cachePath,
1210
- sdkPath: options.sdkPath || resolveDefaultSdkPath(),
1211
- configPath: options.configPath || resolveDefaultConfigPath(),
1212
- logPath: options.logPath || resolveDefaultLogPath(),
1213
- emulatorPath: options.emulatorPath || resolveDefaultEmulatorPath(),
1214
- path,
1215
- os,
1216
- fs: options.fs ?? await import("node:fs"),
1217
- process: options.process ?? await import("node:process"),
1218
- crypto: options.crypto ?? await import("node:crypto"),
1219
- child_process: options.child_process ?? await import("node:child_process")
1220
- };
1221
- }
1364
+ _DeviceTypeConverter.snakecaseToCamelcase = snakecaseToCamelcase;
1365
+ })(DeviceTypeConverter || (DeviceTypeConverter = {}));
1222
1366
 
1223
1367
  //#endregion
1224
1368
  //#region src/image-manager.ts
1225
1369
  var ImageManagerImpl = class {
1226
- constructor(resolvedOptions) {
1227
- this.resolvedOptions = resolvedOptions;
1370
+ constructor(options) {
1371
+ this.options = options;
1228
1372
  }
1229
1373
  getOptions() {
1230
- return this.resolvedOptions;
1374
+ return this.options;
1231
1375
  }
1232
- getOS() {
1233
- switch (this.resolvedOptions.process.platform) {
1376
+ getOperatingSystem() {
1377
+ switch (this.options.adapter.process.platform) {
1234
1378
  case "win32": return "windows";
1235
1379
  case "darwin": return "mac";
1236
1380
  default: return "linux";
1237
1381
  }
1238
1382
  }
1239
1383
  getArch() {
1240
- if (this.resolvedOptions.process.arch.toLowerCase().includes("arm")) return "arm64";
1384
+ if (this.options.adapter.process.arch.toLowerCase().includes("arm")) return "arm64";
1241
1385
  return "x86";
1242
1386
  }
1243
- async getImages(supportVersion = "6.0-hos-single-9") {
1244
- const response = await axios.post("https://devecostudio-drcn.deveco.dbankcloud.com/sdkmanager/v8/hos/getSdkList", {
1245
- osArch: this.getArch(),
1246
- osType: this.getOS(),
1247
- supportVersion
1248
- });
1249
- if (!Array.isArray(response.data)) return [];
1250
- const images = [];
1251
- for (const responseItem of response.data) {
1252
- const resolvedFsPath = this.resolvedOptions.path.resolve(this.resolvedOptions.imageBasePath, ...responseItem.path.split(","));
1253
- if (this.resolvedOptions.fs.existsSync(resolvedFsPath) && this.resolvedOptions.fs.statSync(resolvedFsPath).isDirectory()) images.push(new LocalImageImpl(responseItem, this, resolvedFsPath));
1254
- else images.push(new RemoteImageImpl(responseItem, this, resolvedFsPath));
1387
+ async requestSdkList(supportVersion = "6.0-hos-single-9") {
1388
+ const { adapter: { axios } } = this.getOptions();
1389
+ try {
1390
+ return await axios.post("https://devecostudio-drcn.deveco.dbankcloud.com/sdkmanager/v8/hos/getSdkList", {
1391
+ osArch: this.getArch(),
1392
+ osType: this.getOperatingSystem(),
1393
+ supportVersion
1394
+ });
1395
+ } catch (error) {
1396
+ return error;
1397
+ }
1398
+ }
1399
+ async safeReadAndParseSdkPkgFile(sdkPkgFileUri) {
1400
+ const { adapter: { fs } } = this.getOptions();
1401
+ try {
1402
+ const sdkPkgFileContent = await fs.readFile(sdkPkgFileUri).then((buffer) => buffer.toString());
1403
+ if (!sdkPkgFileContent.length) return void 0;
1404
+ return JSON.parse(sdkPkgFileContent);
1405
+ } catch {
1406
+ return;
1407
+ }
1408
+ }
1409
+ async safeReadAndParseInfoFile(infoFileUri) {
1410
+ const { adapter: { fs } } = this.getOptions();
1411
+ try {
1412
+ const infoFileContent = await fs.readFile(infoFileUri).then((buffer) => buffer.toString());
1413
+ if (!infoFileContent.length) return void 0;
1414
+ return JSON.parse(infoFileContent);
1415
+ } catch {
1416
+ return;
1255
1417
  }
1256
- return images;
1257
1418
  }
1258
- async getProductConfig() {
1259
- const productConfigPath = this.resolvedOptions.path.resolve(this.resolvedOptions.imageBasePath, "productConfig.json");
1260
- if (!this.resolvedOptions.fs.existsSync(productConfigPath) || !this.resolvedOptions.fs.statSync(productConfigPath).isFile()) return (await import("./default-product-config.mjs")).default;
1261
- return JSON.parse(this.resolvedOptions.fs.readFileSync(productConfigPath, "utf-8"));
1419
+ async getLocalImages() {
1420
+ const { adapter: { fs, join } } = this.getOptions();
1421
+ const localImages = [];
1422
+ const systemImagePath = join(this.options.imageBasePath, "system-image");
1423
+ const sdkPkgFiles = await fs.glob(new RelativePattern(systemImagePath, "**/sdk-pkg.json"), { deep: 3 });
1424
+ for (const sdkPkgFileUri of sdkPkgFiles) {
1425
+ const sdkPkgFile = await this.safeReadAndParseSdkPkgFile(sdkPkgFileUri);
1426
+ if (!sdkPkgFile) continue;
1427
+ const infoFile = await this.safeReadAndParseInfoFile(sdkPkgFileUri.with({ path: sdkPkgFileUri.path.replace("sdk-pkg.json", "info.json") }));
1428
+ if (!infoFile) continue;
1429
+ localImages.push(new LocalImageImpl(this, sdkPkgFile, infoFile));
1430
+ }
1431
+ return localImages;
1432
+ }
1433
+ async getRemoteImages(supportVersion = "6.0-hos-single-9") {
1434
+ const remoteImages = [];
1435
+ const { adapter: { isAxiosError } } = this.getOptions();
1436
+ const resultOrError = await this.requestSdkList(supportVersion);
1437
+ if (isAxiosError(resultOrError)) return new SDKList.SDKListError(SDKList.SDKListError.Code.REQUEST_ERROR, "Request failed with image sdk list.", resultOrError);
1438
+ if (!Array.isArray(resultOrError.data)) return new SDKList.SDKListError(SDKList.SDKListError.Code.REQUEST_ERROR, "Request failed with image sdk list.", resultOrError);
1439
+ for (const item of resultOrError.data) {
1440
+ if (typeof item !== "object" || item === null || Array.isArray(item)) continue;
1441
+ remoteImages.push(new RemoteImageImpl(this, item));
1442
+ }
1443
+ return remoteImages;
1444
+ }
1445
+ async getDownloadedRemoteImages(supportVersion) {
1446
+ const remoteImages = await this.getRemoteImages(supportVersion);
1447
+ if (remoteImages instanceof SDKList.SDKListError) return remoteImages;
1448
+ const downloadedRemoteImages = [];
1449
+ for (const remoteImage of remoteImages) {
1450
+ if (!await remoteImage.getLocalImage()) continue;
1451
+ downloadedRemoteImages.push(remoteImage);
1452
+ }
1453
+ return downloadedRemoteImages;
1262
1454
  }
1263
- async getEmulatorConfig() {
1264
- const emulatorConfigPath = this.resolvedOptions.path.resolve(this.resolvedOptions.emulatorPath, "emulator.json");
1265
- if (!this.resolvedOptions.fs.existsSync(emulatorConfigPath) || !this.resolvedOptions.fs.statSync(emulatorConfigPath).isFile()) return (await import("./default-emulator-config.mjs")).default;
1266
- return JSON.parse(this.resolvedOptions.fs.readFileSync(emulatorConfigPath, "utf-8"));
1455
+ getListsFilePath() {
1456
+ const { deployedPath, adapter: { join } } = this.getOptions();
1457
+ return join(deployedPath, "lists.json");
1458
+ }
1459
+ async readListsFile() {
1460
+ try {
1461
+ const { adapter: { fs } } = this.getOptions();
1462
+ const listsFilePath = this.getListsFilePath();
1463
+ const listsFileContent = await fs.readFile(listsFilePath).then((buffer) => buffer.toString());
1464
+ if (!listsFileContent.length) return new ListsFileImpl(this, []);
1465
+ return new ListsFileImpl(this, JSON.parse(listsFileContent));
1466
+ } catch {
1467
+ return new ListsFileImpl(this, []);
1468
+ }
1469
+ }
1470
+ async readEmulatorFile() {
1471
+ try {
1472
+ const { adapter: { fs, join } } = this.getOptions();
1473
+ const emulatorFilePath = join(this.options.emulatorPath, "emulator.json");
1474
+ const emulatorFileContent = await fs.readFile(emulatorFilePath).then((buffer) => buffer.toString());
1475
+ if (!emulatorFileContent.length) return new EmulatorFileImpl(this, (await import("./default-emulator-config.mjs")).default);
1476
+ return new EmulatorFileImpl(this, JSON.parse(emulatorFileContent));
1477
+ } catch {
1478
+ return new EmulatorFileImpl(this, (await import("./default-emulator-config.mjs")).default);
1479
+ }
1480
+ }
1481
+ async readProductConfigFile() {
1482
+ try {
1483
+ const { adapter: { fs, join } } = this.getOptions();
1484
+ const productConfigFilePath = join(this.options.emulatorPath, "product-config.json");
1485
+ const productConfigFileContent = await fs.readFile(productConfigFilePath).then((buffer) => buffer.toString());
1486
+ if (!productConfigFileContent.length) return new ProductConfigFileImpl(this, (await import("./default-product-config.mjs")).default);
1487
+ return new ProductConfigFileImpl(this, JSON.parse(productConfigFileContent));
1488
+ } catch {
1489
+ return new ProductConfigFileImpl(this, (await import("./default-product-config.mjs")).default);
1490
+ }
1267
1491
  }
1268
- async writeDefaultProductConfig(existSkip = false) {
1269
- const productConfigPath = this.resolvedOptions.path.resolve(this.resolvedOptions.imageBasePath, "productConfig.json");
1270
- if (existSkip && this.resolvedOptions.fs.existsSync(productConfigPath)) return;
1271
- this.resolvedOptions.fs.writeFileSync(productConfigPath, JSON.stringify((await import("./default-product-config.mjs")).default, null, 2));
1492
+ async getDeployedDevices() {
1493
+ const deployedDevices = [];
1494
+ const listsFile = await this.readListsFile();
1495
+ const productConfigFile = await this.readProductConfigFile();
1496
+ const emulatorFile = await this.readEmulatorFile();
1497
+ for (const listFileItem of listsFile.getListsFileItems()) {
1498
+ const productConfigItem = productConfigFile.findProductConfigItem({
1499
+ deviceType: DeviceTypeConverter.snakecaseToCamelcase(listFileItem.getContent().type),
1500
+ name: listFileItem.getContent().model
1501
+ });
1502
+ if (!productConfigItem) continue;
1503
+ const emulatorDeviceItem = emulatorFile.findDeviceItem({
1504
+ deviceType: listFileItem.getContent().type,
1505
+ apiVersion: Number(listFileItem.getContent().apiVersion)
1506
+ });
1507
+ if (!emulatorDeviceItem) continue;
1508
+ const screen = new ScreenPresetImpl({
1509
+ productConfigItem,
1510
+ emulatorDeviceItem
1511
+ });
1512
+ const device = new DeviceImpl({
1513
+ imageManager: this,
1514
+ listsFile,
1515
+ listFileItem,
1516
+ screen
1517
+ });
1518
+ const configIniFileUri = ConfigIniFileImpl.getFileUri(device);
1519
+ const parsedConfigIniFile = await ConfigIniFileImpl.safeReadAndParse(device);
1520
+ if (!parsedConfigIniFile) {
1521
+ listsFile.deleteListsFileItem(listFileItem);
1522
+ continue;
1523
+ }
1524
+ device.setConfigIniFile(new ConfigIniFileImpl(device, configIniFileUri, parsedConfigIniFile));
1525
+ const namedIniFileUri = NamedIniFileImpl.getFileUri(device);
1526
+ const parsedNamedIniFile = await NamedIniFileImpl.safeReadAndParse(device);
1527
+ if (!parsedNamedIniFile) {
1528
+ listsFile.deleteListsFileItem(listFileItem);
1529
+ continue;
1530
+ }
1531
+ device.setNamedIniFile(new NamedIniFileImpl(device, namedIniFileUri, parsedNamedIniFile));
1532
+ deployedDevices.push(device);
1533
+ }
1534
+ if (listsFile.isChanged) listsFile.write();
1535
+ return deployedDevices;
1536
+ }
1537
+ toJSON() {
1538
+ return {
1539
+ options: this.getOptions(),
1540
+ operatingSystem: this.getOperatingSystem(),
1541
+ arch: this.getArch(),
1542
+ listsFilePath: this.getListsFilePath()
1543
+ };
1272
1544
  }
1273
1545
  async isCompatible() {
1274
- const { fs, path, emulatorPath } = this.resolvedOptions;
1275
- const sdkPkgPath = path.resolve(emulatorPath, "sdk-pkg.json");
1276
- if (!fs.existsSync(sdkPkgPath) || !fs.statSync(sdkPkgPath).isFile()) return false;
1277
- const sdkPkg = JSON.parse(fs.readFileSync(sdkPkgPath, "utf-8"));
1546
+ const { emulatorPath, adapter: { fs, join, URI } } = this.getOptions();
1547
+ const sdkPkgPath = join(emulatorPath, "sdk-pkg.json").fsPath;
1548
+ if (!await fs.isFile(URI.file(sdkPkgPath))) return false;
1549
+ const sdkPkg = JSON.parse(await fs.readFile(URI.file(sdkPkgPath)).then((buffer) => buffer.toString()));
1278
1550
  if (!sdkPkg?.data?.version || typeof sdkPkg.data.version !== "string") return false;
1279
1551
  const [major, minor, patch] = sdkPkg.data.version.split(".").map(Number);
1552
+ const satisfies = (await import("semver/functions/satisfies")).default;
1280
1553
  return satisfies(`${major}.${minor}.${patch}`, ">=6.0.2");
1281
1554
  }
1282
1555
  };
1283
- async function createImageManager(options = {}) {
1284
- return new ImageManagerImpl(await resolveImageManagerOptions(options));
1556
+ async function createImageManager(options) {
1557
+ return new ImageManagerImpl(await OptionsResolver.resolveImageManagerOptions(options));
1285
1558
  }
1286
1559
 
1287
1560
  //#endregion
1288
- export { BaseEmulatorConfigItem, DeployError, DevModel, GroupPCAllEmulatorConfigItem, GroupPhoneAllEmulatorConfigItem, PCAllEmulatorConfigItem, ParentEmulatorConfigItem, PhoneAllEmulatorConfigItem, ProductConfigItem, RequestUrlError, createCoverScreen, createDoubleScreen, createImageManager, createOuterDoubleScreen, createOuterScreen, createScreen, createScreenPreset, createSingleScreen, version };
1561
+ export { BaseImage, ConfigIniFile, CustomizeFoldableScreen, CustomizeScreen, Device, EmulatorBasicItem, EmulatorFile, EmulatorFoldItem, EmulatorGroupItem, EmulatorTripleFoldItem, ListsFile, ListsFileItem, LocalImage, ProductConfigFile, ProductConfigItem, RemoteImage, SDKList, ScreenPreset, createImageManager, version };