@arkts/image-manager 0.4.2 → 0.5.0

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