appium 3.2.2 → 3.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (250) hide show
  1. package/build/lib/appium.d.ts +147 -205
  2. package/build/lib/appium.d.ts.map +1 -1
  3. package/build/lib/appium.js +169 -282
  4. package/build/lib/appium.js.map +1 -1
  5. package/build/lib/bidi-commands.d.ts.map +1 -1
  6. package/build/lib/bidi-commands.js +11 -11
  7. package/build/lib/bidi-commands.js.map +1 -1
  8. package/build/lib/bootstrap/appium-initializer.d.ts +21 -0
  9. package/build/lib/bootstrap/appium-initializer.d.ts.map +1 -0
  10. package/build/lib/bootstrap/appium-initializer.js +146 -0
  11. package/build/lib/bootstrap/appium-initializer.js.map +1 -0
  12. package/build/lib/bootstrap/appium-main-runner.d.ts +22 -0
  13. package/build/lib/bootstrap/appium-main-runner.d.ts.map +1 -0
  14. package/build/lib/bootstrap/appium-main-runner.js +109 -0
  15. package/build/lib/bootstrap/appium-main-runner.js.map +1 -0
  16. package/build/lib/bootstrap/config-file.d.ts +37 -0
  17. package/build/lib/bootstrap/config-file.d.ts.map +1 -0
  18. package/build/lib/{config-file.js → bootstrap/config-file.js} +62 -138
  19. package/build/lib/bootstrap/config-file.js.map +1 -0
  20. package/build/lib/bootstrap/grid-v3-register.d.ts +20 -0
  21. package/build/lib/bootstrap/grid-v3-register.d.ts.map +1 -0
  22. package/build/lib/bootstrap/grid-v3-register.js +185 -0
  23. package/build/lib/bootstrap/grid-v3-register.js.map +1 -0
  24. package/build/lib/bootstrap/init-types.d.ts +16 -0
  25. package/build/lib/bootstrap/init-types.d.ts.map +1 -0
  26. package/build/lib/bootstrap/init-types.js +3 -0
  27. package/build/lib/bootstrap/init-types.js.map +1 -0
  28. package/build/lib/bootstrap/main-helpers.d.ts +55 -0
  29. package/build/lib/bootstrap/main-helpers.d.ts.map +1 -0
  30. package/build/lib/bootstrap/main-helpers.js +187 -0
  31. package/build/lib/bootstrap/main-helpers.js.map +1 -0
  32. package/build/lib/bootstrap/node-helpers.d.ts +32 -0
  33. package/build/lib/bootstrap/node-helpers.d.ts.map +1 -0
  34. package/build/lib/bootstrap/node-helpers.js +201 -0
  35. package/build/lib/bootstrap/node-helpers.js.map +1 -0
  36. package/build/lib/bootstrap/startup-config.d.ts +22 -0
  37. package/build/lib/bootstrap/startup-config.d.ts.map +1 -0
  38. package/build/lib/bootstrap/startup-config.js +111 -0
  39. package/build/lib/bootstrap/startup-config.js.map +1 -0
  40. package/build/lib/cli/args.d.ts +16 -12
  41. package/build/lib/cli/args.d.ts.map +1 -1
  42. package/build/lib/cli/args.js +20 -40
  43. package/build/lib/cli/args.js.map +1 -1
  44. package/build/lib/cli/driver-command.d.ts +51 -93
  45. package/build/lib/cli/driver-command.d.ts.map +1 -1
  46. package/build/lib/cli/driver-command.js +11 -66
  47. package/build/lib/cli/driver-command.js.map +1 -1
  48. package/build/lib/cli/extension-command.d.ts +173 -377
  49. package/build/lib/cli/extension-command.d.ts.map +1 -1
  50. package/build/lib/cli/extension-command.js +387 -656
  51. package/build/lib/cli/extension-command.js.map +1 -1
  52. package/build/lib/cli/extension.d.ts +10 -15
  53. package/build/lib/cli/extension.d.ts.map +1 -1
  54. package/build/lib/cli/extension.js +15 -33
  55. package/build/lib/cli/extension.js.map +1 -1
  56. package/build/lib/cli/parser.d.ts +37 -66
  57. package/build/lib/cli/parser.d.ts.map +1 -1
  58. package/build/lib/cli/parser.js +69 -104
  59. package/build/lib/cli/parser.js.map +1 -1
  60. package/build/lib/cli/plugin-command.d.ts +50 -90
  61. package/build/lib/cli/plugin-command.d.ts.map +1 -1
  62. package/build/lib/cli/plugin-command.js +11 -63
  63. package/build/lib/cli/plugin-command.js.map +1 -1
  64. package/build/lib/cli/setup-command.d.ts +21 -26
  65. package/build/lib/cli/setup-command.d.ts.map +1 -1
  66. package/build/lib/cli/setup-command.js +19 -61
  67. package/build/lib/cli/setup-command.js.map +1 -1
  68. package/build/lib/cli/utils.d.ts +33 -35
  69. package/build/lib/cli/utils.d.ts.map +1 -1
  70. package/build/lib/cli/utils.js +48 -50
  71. package/build/lib/cli/utils.js.map +1 -1
  72. package/build/lib/constants.d.ts +23 -23
  73. package/build/lib/constants.d.ts.map +1 -1
  74. package/build/lib/constants.js +10 -15
  75. package/build/lib/constants.js.map +1 -1
  76. package/build/lib/doctor/doctor.d.ts +40 -57
  77. package/build/lib/doctor/doctor.d.ts.map +1 -1
  78. package/build/lib/doctor/doctor.js +31 -62
  79. package/build/lib/doctor/doctor.js.map +1 -1
  80. package/build/lib/extension/driver-config.d.ts +18 -77
  81. package/build/lib/extension/driver-config.d.ts.map +1 -1
  82. package/build/lib/extension/driver-config.js +37 -125
  83. package/build/lib/extension/driver-config.js.map +1 -1
  84. package/build/lib/extension/extension-config.d.ts +103 -210
  85. package/build/lib/extension/extension-config.d.ts.map +1 -1
  86. package/build/lib/extension/extension-config.js +180 -342
  87. package/build/lib/extension/extension-config.js.map +1 -1
  88. package/build/lib/extension/index.d.ts +12 -29
  89. package/build/lib/extension/index.d.ts.map +1 -1
  90. package/build/lib/extension/index.js +33 -75
  91. package/build/lib/extension/index.js.map +1 -1
  92. package/build/lib/extension/manifest-migrations.d.ts +3 -20
  93. package/build/lib/extension/manifest-migrations.d.ts.map +1 -1
  94. package/build/lib/extension/manifest-migrations.js +20 -101
  95. package/build/lib/extension/manifest-migrations.js.map +1 -1
  96. package/build/lib/extension/manifest.d.ts +61 -107
  97. package/build/lib/extension/manifest.d.ts.map +1 -1
  98. package/build/lib/extension/manifest.js +181 -356
  99. package/build/lib/extension/manifest.js.map +1 -1
  100. package/build/lib/extension/package-changed.d.ts +1 -3
  101. package/build/lib/extension/package-changed.d.ts.map +1 -1
  102. package/build/lib/extension/package-changed.js +8 -15
  103. package/build/lib/extension/package-changed.js.map +1 -1
  104. package/build/lib/extension/plugin-config.d.ts +10 -52
  105. package/build/lib/extension/plugin-config.d.ts.map +1 -1
  106. package/build/lib/extension/plugin-config.js +11 -63
  107. package/build/lib/extension/plugin-config.js.map +1 -1
  108. package/build/lib/helpers/build.d.ts +22 -0
  109. package/build/lib/helpers/build.d.ts.map +1 -0
  110. package/build/lib/helpers/build.js +109 -0
  111. package/build/lib/helpers/build.js.map +1 -0
  112. package/build/lib/helpers/capability.d.ts +38 -0
  113. package/build/lib/helpers/capability.d.ts.map +1 -0
  114. package/build/lib/helpers/capability.js +128 -0
  115. package/build/lib/helpers/capability.js.map +1 -0
  116. package/build/lib/helpers/network.d.ts +14 -0
  117. package/build/lib/helpers/network.d.ts.map +1 -0
  118. package/build/lib/helpers/network.js +35 -0
  119. package/build/lib/helpers/network.js.map +1 -0
  120. package/build/lib/insecure-features.js +6 -6
  121. package/build/lib/insecure-features.js.map +1 -1
  122. package/build/lib/inspector-commands.d.ts +6 -0
  123. package/build/lib/inspector-commands.d.ts.map +1 -1
  124. package/build/lib/inspector-commands.js +6 -0
  125. package/build/lib/inspector-commands.js.map +1 -1
  126. package/build/lib/logger.d.ts +2 -3
  127. package/build/lib/logger.d.ts.map +1 -1
  128. package/build/lib/logger.js +2 -3
  129. package/build/lib/logger.js.map +1 -1
  130. package/build/lib/logsink.d.ts +13 -22
  131. package/build/lib/logsink.d.ts.map +1 -1
  132. package/build/lib/logsink.js +48 -103
  133. package/build/lib/logsink.js.map +1 -1
  134. package/build/lib/main.d.ts +15 -58
  135. package/build/lib/main.d.ts.map +1 -1
  136. package/build/lib/main.js +25 -425
  137. package/build/lib/main.js.map +1 -1
  138. package/build/lib/schema/arg-spec.d.ts +32 -107
  139. package/build/lib/schema/arg-spec.d.ts.map +1 -1
  140. package/build/lib/schema/arg-spec.js +11 -107
  141. package/build/lib/schema/arg-spec.js.map +1 -1
  142. package/build/lib/schema/cli-args-guards.d.ts +34 -0
  143. package/build/lib/schema/cli-args-guards.d.ts.map +1 -0
  144. package/build/lib/schema/cli-args-guards.js +49 -0
  145. package/build/lib/schema/cli-args-guards.js.map +1 -0
  146. package/build/lib/schema/cli-args.d.ts +3 -15
  147. package/build/lib/schema/cli-args.d.ts.map +1 -1
  148. package/build/lib/schema/cli-args.js +17 -107
  149. package/build/lib/schema/cli-args.js.map +1 -1
  150. package/build/lib/schema/cli-transformers.d.ts +15 -12
  151. package/build/lib/schema/cli-transformers.d.ts.map +1 -1
  152. package/build/lib/schema/cli-transformers.js +15 -45
  153. package/build/lib/schema/cli-transformers.js.map +1 -1
  154. package/build/lib/schema/format-errors.d.ts +28 -0
  155. package/build/lib/schema/format-errors.d.ts.map +1 -0
  156. package/build/lib/schema/format-errors.js +29 -0
  157. package/build/lib/schema/format-errors.js.map +1 -0
  158. package/build/lib/schema/index.d.ts +4 -2
  159. package/build/lib/schema/index.d.ts.map +1 -1
  160. package/build/lib/schema/index.js +2 -0
  161. package/build/lib/schema/index.js.map +1 -1
  162. package/build/lib/schema/keywords.d.ts +12 -20
  163. package/build/lib/schema/keywords.d.ts.map +1 -1
  164. package/build/lib/schema/keywords.js +6 -51
  165. package/build/lib/schema/keywords.js.map +1 -1
  166. package/build/lib/schema/schema.d.ts +106 -231
  167. package/build/lib/schema/schema.d.ts.map +1 -1
  168. package/build/lib/schema/schema.js +88 -358
  169. package/build/lib/schema/schema.js.map +1 -1
  170. package/build/lib/utils.d.ts +7 -267
  171. package/build/lib/utils.d.ts.map +1 -1
  172. package/build/lib/utils.js +10 -409
  173. package/build/lib/utils.js.map +1 -1
  174. package/lib/{appium.js → appium.ts} +297 -341
  175. package/lib/bidi-commands.ts +10 -14
  176. package/lib/bootstrap/appium-initializer.ts +212 -0
  177. package/lib/bootstrap/appium-main-runner.ts +172 -0
  178. package/lib/bootstrap/config-file.ts +178 -0
  179. package/lib/bootstrap/grid-v3-register.ts +250 -0
  180. package/lib/bootstrap/init-types.ts +31 -0
  181. package/lib/bootstrap/main-helpers.ts +223 -0
  182. package/lib/bootstrap/node-helpers.ts +180 -0
  183. package/lib/bootstrap/startup-config.ts +143 -0
  184. package/lib/cli/{args.js → args.ts} +45 -56
  185. package/lib/cli/driver-command.ts +122 -0
  186. package/lib/cli/{extension-command.js → extension-command.ts} +827 -906
  187. package/lib/cli/extension.ts +65 -0
  188. package/lib/cli/{parser.js → parser.ts} +93 -116
  189. package/lib/cli/plugin-command.ts +117 -0
  190. package/lib/cli/{setup-command.js → setup-command.ts} +59 -74
  191. package/lib/cli/utils.ts +97 -0
  192. package/lib/{constants.js → constants.ts} +30 -41
  193. package/lib/doctor/{doctor.js → doctor.ts} +82 -92
  194. package/lib/extension/driver-config.ts +165 -0
  195. package/lib/extension/{extension-config.js → extension-config.ts} +291 -405
  196. package/lib/extension/index.ts +143 -0
  197. package/lib/extension/manifest-migrations.ts +57 -0
  198. package/lib/extension/manifest.ts +369 -0
  199. package/lib/extension/{package-changed.js → package-changed.ts} +9 -18
  200. package/lib/extension/plugin-config.ts +62 -0
  201. package/lib/helpers/build.ts +111 -0
  202. package/lib/helpers/capability.ts +171 -0
  203. package/lib/helpers/network.ts +30 -0
  204. package/lib/insecure-features.ts +1 -1
  205. package/lib/inspector-commands.ts +6 -1
  206. package/lib/{logger.js → logger.ts} +1 -2
  207. package/lib/{logsink.js → logsink.ts} +91 -137
  208. package/lib/main.ts +60 -0
  209. package/lib/schema/arg-spec.ts +131 -0
  210. package/lib/schema/cli-args-guards.ts +67 -0
  211. package/lib/schema/cli-args.ts +171 -0
  212. package/lib/schema/cli-transformers.ts +83 -0
  213. package/lib/schema/format-errors.ts +43 -0
  214. package/lib/schema/index.ts +4 -0
  215. package/lib/schema/keywords.ts +96 -0
  216. package/lib/schema/schema.ts +448 -0
  217. package/lib/utils.ts +73 -0
  218. package/package.json +17 -18
  219. package/scripts/autoinstall-extensions.js +3 -0
  220. package/build/lib/config-file.d.ts +0 -100
  221. package/build/lib/config-file.d.ts.map +0 -1
  222. package/build/lib/config-file.js.map +0 -1
  223. package/build/lib/config.d.ts +0 -70
  224. package/build/lib/config.d.ts.map +0 -1
  225. package/build/lib/config.js +0 -390
  226. package/build/lib/config.js.map +0 -1
  227. package/build/lib/grid-register.d.ts +0 -10
  228. package/build/lib/grid-register.d.ts.map +0 -1
  229. package/build/lib/grid-register.js +0 -134
  230. package/build/lib/grid-register.js.map +0 -1
  231. package/lib/cli/driver-command.js +0 -174
  232. package/lib/cli/extension.js +0 -74
  233. package/lib/cli/plugin-command.js +0 -164
  234. package/lib/cli/utils.js +0 -91
  235. package/lib/config-file.js +0 -228
  236. package/lib/config.js +0 -389
  237. package/lib/extension/driver-config.js +0 -245
  238. package/lib/extension/index.js +0 -169
  239. package/lib/extension/manifest-migrations.js +0 -136
  240. package/lib/extension/manifest.js +0 -550
  241. package/lib/extension/plugin-config.js +0 -112
  242. package/lib/grid-register.js +0 -146
  243. package/lib/main.js +0 -545
  244. package/lib/schema/arg-spec.js +0 -229
  245. package/lib/schema/cli-args.js +0 -254
  246. package/lib/schema/cli-transformers.js +0 -113
  247. package/lib/schema/index.js +0 -2
  248. package/lib/schema/keywords.js +0 -136
  249. package/lib/schema/schema.js +0 -725
  250. package/lib/utils.js +0 -512
@@ -1,7 +1,4 @@
1
1
  "use strict";
2
- /**
3
- * Module containing {@link Manifest} which handles reading & writing of extension config files.
4
- */
5
2
  var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
6
3
  if (k2 === undefined) k2 = k;
7
4
  var desc = Object.getOwnPropertyDescriptor(m, k);
@@ -49,67 +46,13 @@ const constants_1 = require("../constants");
49
46
  const extension_config_1 = require("./extension-config");
50
47
  const package_changed_1 = require("./package-changed");
51
48
  const manifest_migrations_1 = require("./manifest-migrations");
52
- /**
53
- * The name of the prop (`drivers`) used in `extensions.yaml` for drivers.
54
- * @type {`${typeof DRIVER_TYPE}s`}
55
- */
56
49
  const CONFIG_DATA_DRIVER_KEY = `${constants_1.DRIVER_TYPE}s`;
57
- /**
58
- * The name of the prop (`plugins`) used in `extensions.yaml` for plugins.
59
- * @type {`${typeof PLUGIN_TYPE}s`}
60
- */
61
50
  const CONFIG_DATA_PLUGIN_KEY = `${constants_1.PLUGIN_TYPE}s`;
62
- /**
63
- * @type {Readonly<ManifestData>}
64
- */
65
51
  const INITIAL_MANIFEST_DATA = Object.freeze({
66
52
  [CONFIG_DATA_DRIVER_KEY]: Object.freeze({}),
67
53
  [CONFIG_DATA_PLUGIN_KEY]: Object.freeze({}),
68
54
  schemaRev: constants_1.CURRENT_SCHEMA_REV,
69
55
  });
70
- /**
71
- * Given a `package.json` return `true` if it represents an Appium Extension (either a driver or plugin).
72
- *
73
- * _This is a type guard; not a validator._
74
- *
75
- * The `package.json` must have an `appium` property which is an object.
76
- * @param {any} value
77
- * @returns {value is ExtPackageJson<ExtensionType>}
78
- */
79
- function isExtension(value) {
80
- return (lodash_1.default.isPlainObject(value) &&
81
- lodash_1.default.isPlainObject(value.appium) &&
82
- lodash_1.default.isString(value.name) &&
83
- lodash_1.default.isString(value.version));
84
- }
85
- /**
86
- * Given a `package.json`, return `true` if it represents an Appium Driver.
87
- *
88
- * _This is a type guard; not a validator._
89
- *
90
- * To be considered a driver, a `package.json` must have an `appium.driverName` field.
91
- *
92
- * Further validation of the `appium` property happens elsewhere.
93
- * @param {any} value - Value to test
94
- * @returns {value is ExtPackageJson<DriverType>}
95
- */
96
- function isDriver(value) {
97
- return isExtension(value) && 'driverName' in value.appium && lodash_1.default.isString(value.appium.driverName);
98
- }
99
- /**
100
- * Given a `package.json`, return `true` if it represents an Appium Plugin.
101
- *
102
- * _This is a type guard; not a validator._
103
- *
104
- * To be considered a plugin, a `package.json` must have an `appium.pluginName` field.
105
- *
106
- * Further validation of the `appium` property happens elsewhere.
107
- * @param {any} value - Value to test
108
- * @returns {value is ExtPackageJson<PluginType>}
109
- */
110
- function isPlugin(value) {
111
- return isExtension(value) && 'pluginName' in value.appium && lodash_1.default.isString(value.appium.pluginName);
112
- }
113
56
  /**
114
57
  * Handles reading & writing of extension config files.
115
58
  *
@@ -117,81 +60,151 @@ function isPlugin(value) {
117
60
  */
118
61
  class Manifest {
119
62
  /**
120
- * The entire contents of a parsed YAML extension config file.
63
+ * Returns the memoized manifest for an `APPIUM_HOME` directory (one instance per home).
121
64
  *
122
- * Contains proxies for automatic persistence on disk
123
- * @type {ManifestData}
65
+ * @param appiumHome - `APPIUM_HOME` path used as the cache key
124
66
  */
67
+ static getInstance = lodash_1.default.memoize((appiumHome) => new Manifest(appiumHome));
125
68
  #data;
126
- /**
127
- * Path to `APPIUM_HOME`.
128
- * @type {Readonly<string>}
129
- */
130
69
  #appiumHome;
70
+ #manifestPath = undefined;
71
+ #writing;
72
+ #reading;
73
+ constructor(appiumHome) {
74
+ this.#appiumHome = appiumHome;
75
+ this.#data = lodash_1.default.cloneDeep(INITIAL_MANIFEST_DATA);
76
+ }
77
+ /** `APPIUM_HOME` directory this manifest is tied to. */
78
+ get appiumHome() {
79
+ return this.#appiumHome;
80
+ }
131
81
  /**
132
- * Path to `extensions.yaml`
133
- * @type {string}
134
- * Not set until {@link Manifest.read} is called.
82
+ * Absolute path to the extension manifest file after {@link Manifest.read} or {@link Manifest.write} has resolved it.
83
+ * Before that, this is `undefined`.
135
84
  */
136
- #manifestPath;
85
+ get manifestPath() {
86
+ return this.#manifestPath;
87
+ }
88
+ /** Schema revision of the in-memory manifest data (from YAML `schemaRev`). */
89
+ get schemaRev() {
90
+ return this.#data.schemaRev;
91
+ }
137
92
  /**
138
- * Helps avoid writing multiple times.
93
+ * Returns the live installed-extension map for drivers or plugins (same object as stored in memory).
94
+ * Mutations affect the manifest until replaced by a new object (e.g. via `read()`); `setExtension` / `deleteExtension` update this record.
139
95
  *
140
- * If this is `undefined`, calling {@link Manifest.write} will cause it to be
141
- * set to a `Promise`. When the call to `write()` is complete, the `Promise`
142
- * will resolve and then this value will be set to `undefined`. Concurrent calls
143
- * made while this value is a `Promise` will return the `Promise` itself.
144
- * @type {Promise<boolean>|undefined}
96
+ * @param extType - `"driver"` or `"plugin"`
145
97
  */
146
- #writing;
98
+ getExtensionData(extType) {
99
+ const record = extType === constants_1.DRIVER_TYPE ? this.#data.drivers : this.#data.plugins;
100
+ return record;
101
+ }
147
102
  /**
148
- * Helps avoid reading multiple times.
103
+ * Whether a driver with the given manifest key is present.
149
104
  *
150
- * If this is `undefined`, calling {@link Manifest.read} will cause it to be
151
- * set to a `Promise`. When the call to `read()` is complete, the `Promise`
152
- * will resolve and then this value will be set to `undefined`. Concurrent calls
153
- * made while this value is a `Promise` will return the `Promise` itself.
154
- * @type {Promise<void>|undefined}
105
+ * @param name - Driver name as stored under `drivers` in the manifest
155
106
  */
156
- #reading;
107
+ hasDriver(name) {
108
+ return Boolean(this.#data.drivers[name]);
109
+ }
157
110
  /**
158
- * Sets internal data to a fresh clone of {@link INITIAL_MANIFEST_DATA}
111
+ * Whether a plugin with the given manifest key is present.
159
112
  *
160
- * Use {@link Manifest.getInstance} instead.
161
- * @param {string} appiumHome
162
- * @private
113
+ * @param name - Plugin name as stored under `plugins` in the manifest
163
114
  */
164
- constructor(appiumHome) {
165
- this.#appiumHome = appiumHome;
166
- this.#data = lodash_1.default.cloneDeep(INITIAL_MANIFEST_DATA);
115
+ hasPlugin(name) {
116
+ return Boolean(this.#data.plugins[name]);
167
117
  }
168
118
  /**
169
- * Returns a new or existing {@link Manifest} instance, based on the value of `appiumHome`.
119
+ * Loads manifest YAML from disk into memory, runs migration when needed, may sync with installed packages, and writes back if required.
120
+ * Concurrent calls while a read is in flight share the same in-flight work.
170
121
  *
171
- * Maintains one instance per value of `appiumHome`.
122
+ * @returns The parsed in-memory manifest data
172
123
  */
173
- static getInstance = lodash_1.default.memoize(
124
+ async read() {
125
+ if (this.#reading) {
126
+ await this.#reading;
127
+ return this.#data;
128
+ }
129
+ this.#reading = (async () => {
130
+ let data;
131
+ let shouldWrite = false;
132
+ const manifestPathResolved = await this.#setManifestPath();
133
+ try {
134
+ const yaml = await support_1.fs.readFile(manifestPathResolved, 'utf8');
135
+ data = YAML.parse(yaml);
136
+ }
137
+ catch (err) {
138
+ if (err.code === 'ENOENT') {
139
+ data = lodash_1.default.cloneDeep(INITIAL_MANIFEST_DATA);
140
+ shouldWrite = true;
141
+ }
142
+ else {
143
+ throw new Error(`Appium had trouble loading the extension installation ` +
144
+ `cache file (${manifestPathResolved}). It may be invalid YAML. Specific error: ${err.message}`);
145
+ }
146
+ }
147
+ this.#data = data;
148
+ if (!shouldWrite && (data.schemaRev ?? 0) < constants_1.CURRENT_SCHEMA_REV) {
149
+ shouldWrite = await (0, manifest_migrations_1.migrate)(this);
150
+ }
151
+ const hasAppiumDependency = await support_1.env.hasAppiumDependency(this.appiumHome);
152
+ if (shouldWrite || (hasAppiumDependency && (await (0, package_changed_1.packageDidChange)(this.appiumHome)))) {
153
+ shouldWrite = (await this.syncWithInstalledExtensions(hasAppiumDependency)) || shouldWrite;
154
+ }
155
+ if (shouldWrite) {
156
+ await this.write();
157
+ }
158
+ })();
159
+ try {
160
+ await this.#reading;
161
+ return this.#data;
162
+ }
163
+ finally {
164
+ this.#reading = undefined;
165
+ }
166
+ }
174
167
  /**
175
- * @param {string} appiumHome - Path to `APPIUM_HOME`
176
- * @returns {Manifest}
168
+ * Serializes the current in-memory manifest to the resolved manifest path.
169
+ * Concurrent calls while a write is in flight share the same in-flight work.
170
+ *
171
+ * @returns `true` when the file was written successfully
177
172
  */
178
- function _getInstance(appiumHome) {
179
- return new Manifest(appiumHome);
180
- });
173
+ async write() {
174
+ if (this.#writing) {
175
+ return this.#writing;
176
+ }
177
+ this.#writing = (async () => {
178
+ const manifestPathResolved = await this.#setManifestPath();
179
+ try {
180
+ await support_1.fs.mkdirp(node_path_1.default.dirname(manifestPathResolved));
181
+ }
182
+ catch (err) {
183
+ throw new Error(`Appium could not create the directory for the manifest file: ${node_path_1.default.dirname(manifestPathResolved)}. Original error: ${err.message}`);
184
+ }
185
+ try {
186
+ await support_1.fs.writeFile(manifestPathResolved, YAML.stringify(this.#data), 'utf8');
187
+ return true;
188
+ }
189
+ catch (err) {
190
+ throw new Error(`Appium could not write to manifest at ${manifestPathResolved} using APPIUM_HOME ${this.#appiumHome}. Please ensure it is writable. Original error: ${err.message}`);
191
+ }
192
+ })();
193
+ try {
194
+ return await this.#writing;
195
+ }
196
+ finally {
197
+ this.#writing = undefined;
198
+ }
199
+ }
181
200
  /**
182
- * Searches `APPIUM_HOME` for installed extensions and adds them to the manifest.
183
- * @param {boolean} hasAppiumDependency - This affects whether or not the "dev" `InstallType` is used
184
- * @returns {Promise<boolean>} `true` if any extensions were added, `false` otherwise.
201
+ * Scans `APPIUM_HOME` (root and `node_modules`) for Appium extension packages and merges them into the manifest.
202
+ *
203
+ * @param hasAppiumDependency - When true and the root `package.json` depends on Appium, matching extensions use the `"dev"` install type
204
+ * @returns `true` if any extension entries changed, `false` otherwise
185
205
  */
186
206
  async syncWithInstalledExtensions(hasAppiumDependency = false) {
187
- // this could be parallelized, but we can't use fs.walk as an async iterator
188
207
  let didChange = false;
189
- /**
190
- * Listener for the `match` event of a `glob` instance
191
- * @param {string} filepath - Path to a `package.json`
192
- * @param {boolean} [devType] - If `true`, this is an extension in "dev mode"
193
- * @returns {Promise<void>}
194
- */
195
208
  const onMatch = async (filepath, devType = false) => {
196
209
  try {
197
210
  const pkg = JSON.parse(await support_1.fs.readFile(filepath, 'utf8'));
@@ -201,18 +214,13 @@ class Manifest {
201
214
  didChange = didChange || changed;
202
215
  }
203
216
  }
204
- catch { }
217
+ catch {
218
+ // ignore invalid package.json
219
+ }
205
220
  };
206
- /**
207
- * A list of `Promise`s which read `package.json` files looking for Appium extensions.
208
- * @type {Promise<void>[]}
209
- */
210
221
  const queue = [
211
- // look at `package.json` in `APPIUM_HOME` only.
212
- // this causes extensions in "dev mode" to be automatically found
213
222
  onMatch(node_path_1.default.join(this.#appiumHome, 'package.json'), true),
214
223
  ];
215
- // add dependencies to the queue
216
224
  const filepaths = await support_1.fs.glob('node_modules/{*,@*/*}/package.json', {
217
225
  cwd: this.#appiumHome,
218
226
  absolute: true,
@@ -220,303 +228,120 @@ class Manifest {
220
228
  for (const filepath of filepaths) {
221
229
  queue.push(onMatch(filepath));
222
230
  }
223
- // wait for everything to finish
224
231
  await bluebird_1.default.all(queue);
225
232
  return didChange;
226
233
  }
227
234
  /**
228
- * Returns `true` if driver with name `name` is registered.
229
- * @param {string} name - Driver name
230
- * @returns {boolean}
231
- */
232
- hasDriver(name) {
233
- return Boolean(this.#data.drivers[name]);
234
- }
235
- /**
236
- * Returns `true` if plugin with name `name` is registered.
237
- * @param {string} name - Plugin name
238
- * @returns {boolean}
239
- */
240
- hasPlugin(name) {
241
- return Boolean(this.#data.plugins[name]);
242
- }
243
- /**
244
- * Given a path to a `package.json`, add it as either a driver or plugin to the manifest.
235
+ * Builds manifest metadata from a `package.json` and registers it if it is a driver or plugin and the entry changed.
245
236
  *
246
- * @template {ExtensionType} ExtType
247
- * @param {ExtPackageJson<ExtType>} pkgJson
248
- * @param {string} pkgPath
249
- * @param {typeof INSTALL_TYPE_NPM | typeof INSTALL_TYPE_DEV} [installType]
250
- * @returns {boolean} - `true` if this method did anything.
237
+ * @param pkgJson - Parsed extension `package.json`
238
+ * @param pkgPath - Path to that `package.json` (install path is derived from its directory)
239
+ * @param installType - How the package was discovered (`npm` vs `dev`)
240
+ * @returns `true` if the manifest was updated, `false` if unchanged or already matched
241
+ * @throws TypeError if the package is not a valid driver or plugin extension
251
242
  */
252
243
  addExtensionFromPackage(pkgJson, pkgPath, installType = extension_config_1.INSTALL_TYPE_NPM) {
253
244
  const extensionPath = node_path_1.default.dirname(pkgPath);
254
- /**
255
- * @type {InternalMetadata}
256
- */
257
245
  const internal = {
258
- pkgName: /** @type {string} */ (pkgJson.name),
259
- version: /** @type {string} */ (pkgJson.version),
246
+ pkgName: pkgJson.name,
247
+ version: pkgJson.version,
260
248
  appiumVersion: pkgJson.peerDependencies?.appium,
261
249
  installType,
262
250
  installSpec: `${pkgJson.name}@${pkgJson.version}`,
263
251
  installPath: extensionPath,
264
252
  };
265
253
  if (isDriver(pkgJson)) {
254
+ const driverName = pkgJson.appium.driverName;
266
255
  const value = {
267
256
  ...lodash_1.default.omit(pkgJson.appium, 'driverName'),
268
257
  ...internal,
269
258
  };
270
- if (!lodash_1.default.isEqual(value, this.#data.drivers[pkgJson.appium.driverName])) {
271
- this.setExtension(
272
- /** @type {ExtType} */ (constants_1.DRIVER_TYPE), pkgJson.appium.driverName,
273
- /** @type {ExtManifest<ExtType>} */ (value));
259
+ if (!lodash_1.default.isEqual(value, this.#data.drivers[driverName])) {
260
+ this.setExtension(constants_1.DRIVER_TYPE, driverName, value);
274
261
  return true;
275
262
  }
276
263
  return false;
277
264
  }
278
- else if (isPlugin(pkgJson)) {
265
+ if (isPlugin(pkgJson)) {
266
+ const pluginName = pkgJson.appium.pluginName;
279
267
  const value = {
280
268
  ...lodash_1.default.omit(pkgJson.appium, 'pluginName'),
281
269
  ...internal,
282
270
  };
283
- if (!lodash_1.default.isEqual(value, this.#data.plugins[pkgJson.appium.pluginName])) {
284
- this.setExtension(
285
- /** @type {ExtType} */ (constants_1.PLUGIN_TYPE), pkgJson.appium.pluginName,
286
- /** @type {ExtManifest<ExtType>} */ (value));
271
+ if (!lodash_1.default.isEqual(value, this.#data.plugins[pluginName])) {
272
+ this.setExtension(constants_1.PLUGIN_TYPE, pluginName, value);
287
273
  return true;
288
274
  }
289
275
  return false;
290
276
  }
291
- else {
292
- throw new TypeError(`The extension in ${extensionPath} is neither a valid ${constants_1.DRIVER_TYPE} nor a valid ${constants_1.PLUGIN_TYPE}.`);
293
- }
277
+ throw new TypeError(`The extension in ${extensionPath} is neither a valid ${constants_1.DRIVER_TYPE} nor a valid ${constants_1.PLUGIN_TYPE}.`);
294
278
  }
295
279
  /**
296
- * Adds an extension to the manifest as was installed by the `appium` CLI. The
297
- * `extData`, `extType`, and `extName` have already been determined.
280
+ * Stores a deep-cloned copy of extension metadata under the given type and name.
298
281
  *
299
- * See {@link Manifest.addExtensionFromPackage} for adding an extension from an on-disk package.
300
- * @template {ExtensionType} ExtType
301
- * @param {ExtType} extType - `driver` or `plugin`
302
- * @param {string} extName - Name of extension
303
- * @param {ExtManifest<ExtType>} extData - Extension metadata
304
- * @returns {ExtManifest<ExtType>} A clone of `extData`, potentially with a mutated `appiumVersion` field
282
+ * @param extType - `"driver"` or `"plugin"`
283
+ * @param extName - Manifest key for the extension
284
+ * @param extData - Full extension entry to persist in memory
285
+ * @returns The cloned data now held in the manifest
305
286
  */
306
287
  setExtension(extType, extName, extData) {
307
288
  const data = lodash_1.default.cloneDeep(extData);
308
- this.#data[`${extType}s`][extName] = data;
289
+ if (extType === constants_1.DRIVER_TYPE) {
290
+ this.#data.drivers[extName] = data;
291
+ }
292
+ else {
293
+ this.#data.plugins[extName] = data;
294
+ }
309
295
  return data;
310
296
  }
311
297
  /**
312
- * Sets the schema revision
313
- * @param {keyof import('./manifest-migrations').ManifestDataVersions} rev
298
+ * Updates the in-memory manifest schema revision (typically during migration).
299
+ *
300
+ * @param rev - New `schemaRev` value
314
301
  */
315
302
  setSchemaRev(rev) {
316
303
  this.#data.schemaRev = rev;
317
304
  }
318
305
  /**
319
- * Remove an extension from the manifest.
320
- * @param {ExtensionType} extType
321
- * @param {string} extName
322
- */
323
- deleteExtension(extType, extName) {
324
- delete this.#data[`${extType}s`][extName];
325
- }
326
- /**
327
- * Returns the `APPIUM_HOME` path
328
- */
329
- get appiumHome() {
330
- return this.#appiumHome;
331
- }
332
- /**
333
- * Returns the path to the manifest file (`extensions.yaml`)
334
- */
335
- get manifestPath() {
336
- return this.#manifestPath;
337
- }
338
- /**
339
- * Returns the schema rev of this manifest
340
- */
341
- get schemaRev() {
342
- return this.#data.schemaRev;
343
- }
344
- /**
345
- * Returns extension data for a particular type.
346
- *
347
- * @template {ExtensionType} ExtType
348
- * @param {ExtType} extType
349
- * @returns {Readonly<ExtRecord<ExtType>>}
350
- */
351
- getExtensionData(extType) {
352
- return this.#data[ /** @type {string} */(`${extType}s`)];
353
- }
354
- /**
355
- * Reads manifest from disk and _overwrites_ the internal data.
356
- *
357
- * If the manifest does not exist on disk, an
358
- * {@link INITIAL_MANIFEST_DATA "empty"} manifest file will be created, as
359
- * well as its directory if needed.
360
- *
361
- * This will also, if necessary:
362
- * 1. perform a migration of the manifest data
363
- * 2. sync the manifest with extensions on-disk (kind of like "auto
364
- * discovery")
365
- * 3. write the manifest to disk.
306
+ * Removes an extension entry from the manifest data in memory (does not write to disk by itself).
366
307
  *
367
- * Only one read operation can happen at a time.
368
- *
369
- * @returns {Promise<ManifestData>} The data
308
+ * @param extType - `"driver"` or `"plugin"`
309
+ * @param extName - Manifest key to remove
370
310
  */
371
- async read() {
372
- if (this.#reading) {
373
- await this.#reading;
374
- return this.#data;
375
- }
376
- this.#reading = (async () => {
377
- /** @type {ManifestData} */
378
- let data;
379
- /**
380
- * This will be `true` if, after reading, we need to update the manifest data
381
- * and write it again to disk.
382
- */
383
- let shouldWrite = false;
384
- await this.#setManifestPath();
385
- try {
386
- const yaml = await support_1.fs.readFile(this.#manifestPath, 'utf8');
387
- data = YAML.parse(yaml);
388
- }
389
- catch (err) {
390
- if (err.code === 'ENOENT') {
391
- data = lodash_1.default.cloneDeep(INITIAL_MANIFEST_DATA);
392
- shouldWrite = true;
393
- }
394
- else if (this.#manifestPath) {
395
- throw new Error(`Appium had trouble loading the extension installation ` +
396
- `cache file (${this.#manifestPath}). It may be invalid YAML. Specific error: ${err.message}`);
397
- }
398
- else {
399
- throw new Error(`Appium encountered an unknown problem. Specific error: ${err.message}`);
400
- }
401
- }
402
- this.#data = data;
403
- /**
404
- * the only way `shouldWrite` is `true` is if we have a new file. a new
405
- * file will get the latest schema revision, so we can skip the migration.
406
- */
407
- if (!shouldWrite && (data.schemaRev ?? 0) < constants_1.CURRENT_SCHEMA_REV) {
408
- shouldWrite = await (0, manifest_migrations_1.migrate)(this);
409
- }
410
- const hasAppiumDependency = await support_1.env.hasAppiumDependency(this.appiumHome);
411
- /**
412
- * we still may want to sync with installed extensions even if we have a
413
- * new file. right now this is limited to the following cases:
414
- * 1. we have a brand new manifest file
415
- * 2. we have performed a migration on a manifest file
416
- * 3. `appium` is a dependency within `package.json`, and `package.json`
417
- * has changed since last time we checked.
418
- *
419
- * It may also make sense to sync with the extensions in an arbitrary
420
- * `APPIUM_HOME`, but we don't do that here.
421
- */
422
- if (shouldWrite || (hasAppiumDependency && (await (0, package_changed_1.packageDidChange)(this.appiumHome)))) {
423
- shouldWrite = (await this.syncWithInstalledExtensions(hasAppiumDependency)) || shouldWrite;
424
- }
425
- if (shouldWrite) {
426
- await this.write();
427
- }
428
- })();
429
- try {
430
- await this.#reading;
431
- return this.#data;
311
+ deleteExtension(extType, extName) {
312
+ if (extType === constants_1.DRIVER_TYPE) {
313
+ delete this.#data.drivers[extName];
432
314
  }
433
- finally {
434
- this.#reading = undefined;
315
+ else {
316
+ delete this.#data.plugins[extName];
435
317
  }
436
318
  }
437
- /**
438
- * Ensures the internal manifest path is set.
439
- *
440
- * Creates the directory if necessary.
441
- * @returns {Promise<string>}
442
- */
443
319
  async #setManifestPath() {
444
320
  if (!this.#manifestPath) {
445
- this.#manifestPath = await support_1.env.resolveManifestPath(this.#appiumHome);
446
- /* istanbul ignore if */
447
- if (node_path_1.default.relative(this.#appiumHome, this.#manifestPath).startsWith('.')) {
448
- throw new Error(`Mismatch between location of APPIUM_HOME and manifest file. APPIUM_HOME: ${this.appiumHome}, manifest file: ${this.#manifestPath}`);
321
+ const resolved = await support_1.env.resolveManifestPath(this.#appiumHome);
322
+ this.#manifestPath = resolved;
323
+ if (node_path_1.default.relative(this.#appiumHome, resolved).startsWith('.')) {
324
+ throw new Error(`Mismatch between location of APPIUM_HOME and manifest file. APPIUM_HOME: ${this.appiumHome}, manifest file: ${resolved}`);
449
325
  }
450
326
  }
451
327
  return this.#manifestPath;
452
328
  }
453
- /**
454
- * Writes the data if it need s writing.
455
- *
456
- * If the `schemaRev` prop needs updating, the file will be written.
457
- *
458
- * @todo If this becomes too much of a bottleneck, throttle it.
459
- * @returns {Promise<boolean>} Whether the data was written
460
- */
461
- async write() {
462
- if (this.#writing) {
463
- return this.#writing;
464
- }
465
- this.#writing = (async () => {
466
- await this.#setManifestPath();
467
- try {
468
- await support_1.fs.mkdirp(node_path_1.default.dirname(this.#manifestPath));
469
- }
470
- catch (err) {
471
- throw new Error(`Appium could not create the directory for the manifest file: ${node_path_1.default.dirname(this.#manifestPath)}. Original error: ${err.message}`);
472
- }
473
- try {
474
- await support_1.fs.writeFile(this.#manifestPath, YAML.stringify(this.#data), 'utf8');
475
- return true;
476
- }
477
- catch (err) {
478
- throw new Error(`Appium could not write to manifest at ${this.#manifestPath} using APPIUM_HOME ${this.#appiumHome}. Please ensure it is writable. Original error: ${err.message}`);
479
- }
480
- })();
481
- try {
482
- return await this.#writing;
483
- }
484
- finally {
485
- this.#writing = undefined;
486
- }
487
- }
488
329
  }
489
330
  exports.Manifest = Manifest;
490
- /**
491
- * Type of the string referring to a driver (typically as a key or type string)
492
- * @typedef {import('@appium/types').DriverType} DriverType
493
- */
494
- /**
495
- * Type of the string referring to a plugin (typically as a key or type string)
496
- * @typedef {import('@appium/types').PluginType} PluginType
497
- */
498
- /**
499
- * @typedef SyncWithInstalledExtensionsOpts
500
- * @property {number} [depthLimit] - Maximum depth to recurse into subdirectories
501
- */
502
- /**
503
- * @typedef {import('appium/types').ManifestData} ManifestData
504
- * @typedef {import('appium/types').InternalMetadata} InternalMetadata
505
- */
506
- /**
507
- * @template {ExtensionType} ExtType
508
- * @typedef {import('appium/types').ExtPackageJson<ExtType>} ExtPackageJson
509
- */
510
- /**
511
- * @template {ExtensionType} ExtType
512
- * @typedef {import('appium/types').ExtManifest<ExtType>} ExtManifest
513
- */
514
- /**
515
- * @template {ExtensionType} ExtType
516
- * @typedef {import('appium/types').ExtRecord<ExtType>} ExtRecord
517
- */
518
- /**
519
- * Either `driver` or `plugin` rn
520
- * @typedef {import('@appium/types').ExtensionType} ExtensionType
521
- */
331
+ function isExtension(value) {
332
+ return (lodash_1.default.isPlainObject(value) &&
333
+ lodash_1.default.isPlainObject(value.appium) &&
334
+ lodash_1.default.isString(value.name) &&
335
+ lodash_1.default.isString(value.version));
336
+ }
337
+ function isDriver(value) {
338
+ return (isExtension(value) &&
339
+ 'driverName' in value.appium &&
340
+ lodash_1.default.isString(value.appium.driverName));
341
+ }
342
+ function isPlugin(value) {
343
+ return (isExtension(value) &&
344
+ 'pluginName' in value.appium &&
345
+ lodash_1.default.isString(value.appium.pluginName));
346
+ }
522
347
  //# sourceMappingURL=manifest.js.map