@qooxdoo/framework 8.0.0-beta.1 → 8.0.0-beta.3

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 (66) hide show
  1. package/CHANGELOG.md +42 -0
  2. package/Manifest.json +1 -1
  3. package/lib/compiler/compile-info.json +54 -55
  4. package/lib/compiler/index.js +19039 -23607
  5. package/lib/resource/qx/tool/compiler/cli/templates/class/default.tmpl.js +6 -7
  6. package/lib/resource/qx/tool/compiler/cli/templates/class/singleton.tmpl.js +5 -6
  7. package/lib/resource/qx/tool/compiler/schema/compile-1-0-0.json +6 -2
  8. package/package.json +8 -10
  9. package/source/class/qx/Class.js +26 -7
  10. package/source/class/qx/Mixin.js +15 -6
  11. package/source/class/qx/core/BaseInit.js +14 -13
  12. package/source/class/qx/core/MObjectId.js +16 -0
  13. package/source/class/qx/core/MProperty.js +147 -175
  14. package/source/class/qx/core/check/AbstractCheck.js +5 -1
  15. package/source/class/qx/core/check/CheckFactory.js +6 -0
  16. package/source/class/qx/core/check/DynamicTypeCheck.js +9 -0
  17. package/source/class/qx/core/property/ExplicitPropertyStorage.js +7 -19
  18. package/source/class/qx/core/property/IPropertyStorage.js +2 -21
  19. package/source/class/qx/core/property/Property.js +115 -90
  20. package/source/class/qx/core/property/SimplePropertyStorage.js +2 -18
  21. package/source/class/qx/data/MBinding.js +1 -1
  22. package/source/class/qx/data/SingleValueBinding.js +63 -107
  23. package/source/class/qx/data/binding/AbstractSegment.js +16 -11
  24. package/source/class/qx/data/binding/ArrayIndexSegment.js +17 -10
  25. package/source/class/qx/data/binding/IInputReceiver.js +1 -1
  26. package/source/class/qx/data/binding/PropNameSegment.js +35 -12
  27. package/source/class/qx/dev/unit/TestCase.js +4 -1
  28. package/source/class/qx/event/handler/Focus.js +2 -1
  29. package/source/class/qx/html/Jsx.js +2 -3
  30. package/source/class/qx/html/Node.js +3 -3
  31. package/source/class/qx/io/jsonrpc/Client.js +1 -1
  32. package/source/class/qx/promise/NativeWrapper.js +1 -1
  33. package/source/class/qx/test/Mixin.js +219 -0
  34. package/source/class/qx/test/Promise.js +10 -11
  35. package/source/class/qx/test/core/Property.js +50 -16
  36. package/source/class/qx/test/data/singlevalue/Async.js +17 -4
  37. package/source/class/qx/test/data/singlevalue/Simple.js +6 -0
  38. package/source/class/qx/test/locale/Date.js +2 -2
  39. package/source/class/qx/test/performance/Property.js +0 -1
  40. package/source/class/qx/test/ui/core/SingleSelectionManager.js +150 -0
  41. package/source/class/qx/theme/classic/Appearance.js +21 -0
  42. package/source/class/qx/theme/modern/Appearance.js +21 -0
  43. package/source/class/qx/theme/simple/Appearance.js +21 -0
  44. package/source/class/qx/theme/tangible/Appearance.js +2 -0
  45. package/source/class/qx/tool/cli/AbstractCliApp.js +18 -2
  46. package/source/class/qx/tool/compiler/ClassFile.js +0 -4
  47. package/source/class/qx/tool/compiler/MetaDatabase.js +47 -0
  48. package/source/class/qx/tool/compiler/cli/api/CompilerApi.js +1 -2
  49. package/source/class/qx/tool/compiler/cli/commands/Compile.js +139 -8
  50. package/source/class/qx/tool/compiler/cli/commands/Create.js +1 -1
  51. package/source/class/qx/tool/compiler/cli/commands/Serve.js +1 -1
  52. package/source/class/qx/tool/compiler/cli/commands/Typescript.js +26 -39
  53. package/source/class/qx/tool/compiler/cli/commands/add/Script.js +1 -1
  54. package/source/class/qx/tool/compiler/cli/commands/package/Publish.js +3 -2
  55. package/source/class/qx/tool/compiler/cli/commands/package/Update.js +2 -2
  56. package/source/class/qx/tool/compiler/targets/TypeScriptWriter.js +3 -0
  57. package/source/class/qx/tool/compiler/targets/meta/Browserify.js +142 -80
  58. package/source/class/qx/tool/migration/M8_0_0.js +4 -4
  59. package/source/class/qx/ui/core/SingleSelectionManager.js +4 -4
  60. package/source/class/qx/ui/form/validation/Manager.js +1 -1
  61. package/source/class/qx/ui/toolbar/ToolBar.js +4 -4
  62. package/source/resource/qx/decoration/Modern/table/boolean-false.png +0 -0
  63. package/source/resource/qx/decoration/Modern/table/boolean-true.png +0 -0
  64. package/source/resource/qx/tool/compiler/cli/templates/class/default.tmpl.js +6 -7
  65. package/source/resource/qx/tool/compiler/cli/templates/class/singleton.tmpl.js +5 -6
  66. package/source/resource/qx/tool/compiler/schema/compile-1-0-0.json +6 -2
@@ -1465,6 +1465,27 @@ qx.Theme.define("qx.theme.classic.Appearance", {
1465
1465
  }
1466
1466
  },
1467
1467
 
1468
+ "selectbox-arrow-button": "widget",
1469
+
1470
+ /*
1471
+ ---------------------------------------------------------------------------
1472
+ CHECKED SELECT BOX
1473
+ ---------------------------------------------------------------------------
1474
+ */
1475
+
1476
+ "checked-selectbox": "selectbox",
1477
+
1478
+ "checked-selectbox/allNone": {
1479
+ include: "button"
1480
+ },
1481
+
1482
+ "checked-selectbox/tag": "tag",
1483
+
1484
+ tag: {
1485
+ alias: "button",
1486
+ include: "button"
1487
+ },
1488
+
1468
1489
  /*
1469
1490
  ---------------------------------------------------------------------------
1470
1491
  DATE CHOOSER
@@ -1728,6 +1728,27 @@ qx.Theme.define("qx.theme.modern.Appearance", {
1728
1728
  }
1729
1729
  },
1730
1730
 
1731
+ "selectbox-arrow-button": "widget",
1732
+
1733
+ /*
1734
+ ---------------------------------------------------------------------------
1735
+ CHECKED SELECT BOX
1736
+ ---------------------------------------------------------------------------
1737
+ */
1738
+
1739
+ "checked-selectbox": "selectbox",
1740
+
1741
+ "checked-selectbox/allNone": {
1742
+ include: "button"
1743
+ },
1744
+
1745
+ "checked-selectbox/tag": "tag",
1746
+
1747
+ tag: {
1748
+ alias: "button",
1749
+ include: "button"
1750
+ },
1751
+
1731
1752
  /*
1732
1753
  ---------------------------------------------------------------------------
1733
1754
  DATE CHOOSER
@@ -1204,6 +1204,27 @@ qx.Theme.define("qx.theme.simple.Appearance", {
1204
1204
  }
1205
1205
  },
1206
1206
 
1207
+ "selectbox-arrow-button": "widget",
1208
+
1209
+ /*
1210
+ ---------------------------------------------------------------------------
1211
+ CHECKED SELECT BOX
1212
+ ---------------------------------------------------------------------------
1213
+ */
1214
+
1215
+ "checked-selectbox": "selectbox",
1216
+
1217
+ "checked-selectbox/allNone": {
1218
+ include: "button"
1219
+ },
1220
+
1221
+ "checked-selectbox/tag": "tag",
1222
+
1223
+ tag: {
1224
+ alias: "button",
1225
+ include: "button"
1226
+ },
1227
+
1207
1228
  /*
1208
1229
  ---------------------------------------------------------------------------
1209
1230
  COMBO BOX
@@ -1313,6 +1313,8 @@ qx.Theme.define("qx.theme.tangible.Appearance", {
1313
1313
  }
1314
1314
  },
1315
1315
 
1316
+ "selectbox-arrow-button": "widget",
1317
+
1316
1318
  /*
1317
1319
  ---------------------------------------------------------------------------
1318
1320
  CHECKED SELECT BOX
@@ -41,12 +41,28 @@ qx.Class.define("qx.tool.cli.AbstractCliApp", {
41
41
  console.log((cmd || rootCmd).usage());
42
42
  process.exit((!cmd || errors) ? 1 : 0);
43
43
  }
44
+ let exitCode = 0;
44
45
  try {
45
- process.exit(await run.call(cmd, cmd) ?? 0);
46
+ exitCode = await run.call(cmd, cmd) ?? 0;
46
47
  } catch (ex) {
47
48
  console.error("ERROR:\n" + (ex.stack ?? ex.message) + "\n");
48
- process.exit(1);
49
+ exitCode = 1;
49
50
  }
51
+ // Close undici's global connection pool before exiting.
52
+ // Native fetch (undici) keeps HTTP keep-alive connections open which would prevent
53
+ // natural process exit. node:undici is available as a built-in from Node.js 22+.
54
+ try {
55
+ const { getGlobalDispatcher } = require("node:undici");
56
+ await getGlobalDispatcher().close();
57
+ } catch (e) {
58
+ // node:undici not available on this Node.js version — proceed
59
+ }
60
+ // Use process.exitCode instead of process.exit() to avoid a libuv race on Windows + Node 24:
61
+ // close() resolves, but undici's internal uv_async_t handles are still tearing down; calling
62
+ // process.exit() immediately marks them UV_HANDLE_CLOSING, then a background task fires
63
+ // uv_async_send() on one → assertion fails (libuv 1.50.x made this a hard crash, not a no-op).
64
+ // Setting exitCode and returning lets the event loop drain naturally instead.
65
+ process.exitCode = exitCode;
50
66
  },
51
67
 
52
68
  /**
@@ -3164,10 +3164,6 @@ qx.Class.define("qx.tool.compiler.ClassFile", {
3164
3164
  * These options are passed to Babel for JSX compilation; they can be changed by the CLI etc
3165
3165
  * as needed.
3166
3166
  *
3167
- * Note that at the moment they use a class that does not exist! `qx.html.Jsx` is coming soon
3168
- * to a PR near you, but in the mean time you could use the compile.json `jsx` setting to
3169
- * change these to something else, eg `{ pragma: "jsx.dom", pragmaFrag: "jsx.Fragment }` and
3170
- * use https://github.com/alecsgone/jsx-render in your application's code.
3171
3167
  */
3172
3168
  JSX_OPTIONS: {
3173
3169
  pragma: "qx.html.Jsx.createElement",
@@ -211,6 +211,53 @@ qx.Class.define("qx.tool.compiler.MetaDatabase", {
211
211
  }
212
212
  },
213
213
 
214
+ /**
215
+ * Scans directories recursively for .js files and populates the database.
216
+ * Calls addFile() for each discovered file, then reparseAll().
217
+ *
218
+ * @param {String[]} dirs directories to scan
219
+ * @param {Object} [options]
220
+ * @param {Boolean} [options.force] reparse even if up to date (default: false)
221
+ * @param {Object} [options.ignore] an `ignore` instance for exclude patterns
222
+ * @param {Boolean} [options.verbose] log each processed file
223
+ */
224
+ async loadFromDirectories(dirs, options = {}) {
225
+ const classFiles = [];
226
+
227
+ const scanImpl = async filename => {
228
+ let basename = path.basename(filename);
229
+
230
+ if (options.ignore) {
231
+ let relativePath = path.relative(process.cwd(), filename);
232
+ if (options.ignore.ignores(relativePath)) {
233
+ return;
234
+ }
235
+ }
236
+
237
+ let stat = await fs.promises.stat(filename);
238
+ if (stat.isFile() && basename.match(/\.js$/)) {
239
+ classFiles.push(filename);
240
+ } else if (stat.isDirectory() && (basename == "." || basename[0] != ".")) {
241
+ let files = await fs.promises.readdir(filename);
242
+ for (let file of files) {
243
+ await scanImpl(path.join(filename, file));
244
+ }
245
+ }
246
+ };
247
+
248
+ for (let dir of dirs) {
249
+ await scanImpl(dir);
250
+ }
251
+
252
+ for (let filename of classFiles) {
253
+ if (options.verbose) {
254
+ qx.tool.compiler.Console.info(`Processing ${filename} ...`);
255
+ }
256
+ await this.addFile(filename, options.force || false);
257
+ }
258
+ await this.reparseAll();
259
+ },
260
+
214
261
  __createDerivedClassLookup() {
215
262
  const lookup = {};
216
263
 
@@ -51,8 +51,7 @@ qx.Class.define("qx.tool.compiler.cli.api.CompilerApi", {
51
51
  init: null,
52
52
  nullable: true,
53
53
  check: "qx.tool.compiler.cli.Command",
54
- event: "changeCommand",
55
- async: true
54
+ event: "changeCommand"
56
55
  }
57
56
  },
58
57
 
@@ -33,6 +33,11 @@ qx.Class.define("qx.tool.compiler.cli.commands.Compile", {
33
33
  extend: qx.tool.compiler.cli.Command,
34
34
 
35
35
  statics: {
36
+ /**
37
+ * Creates and configures the CLI command for the compile subcommand
38
+ * @param clazz {Function} the class to instantiate as the command handler
39
+ * @return {Promise<qx.tool.cli.Command>} the configured command
40
+ */
36
41
  async createCliCommand(clazz = this) {
37
42
  let cmd = await qx.tool.compiler.cli.Command.createCliCommand(clazz);
38
43
  cmd.set({
@@ -420,14 +425,30 @@ qx.Class.define("qx.tool.compiler.cli.commands.Compile", {
420
425
  properties: {},
421
426
 
422
427
  members: {
428
+ /** @type{cliProgress.SingleBar|null} progress bar instance */
423
429
  __progressBar: null,
430
+ /** @type{qx.tool.compiler.makers.Maker[]|null} list of makers created from config */
424
431
  __makers: null,
432
+ /** @type{Object} map of namespace to Library instance */
425
433
  __libraries: null,
434
+ /** @type{Boolean} true if the output directory was created during this run */
426
435
  __outputDirWasCreated: false,
427
436
  /** @type {Boolean} Whether libraries have had their `.load()` method called yet */
428
437
  __librariesNotified: false,
429
438
 
430
- /*
439
+ /** @type{String} the path to the root of the meta files by classname */
440
+ __metaDir: null,
441
+
442
+ /** @type{Boolean} whether the typescript output is enabled */
443
+ __typescriptEnabled: false,
444
+
445
+ /** @type{String} the name of the typescript file to generate, null = use default */
446
+ __typescriptFile: null,
447
+
448
+ /** @type{Boolean} whether the typescript watcher has already been attached (watch mode) */
449
+ __typescriptWatcherAttached: false,
450
+
451
+ /**
431
452
  * @Override
432
453
  */
433
454
  async process() {
@@ -830,17 +851,36 @@ Framework: v${await this.getQxVersion()} in ${await this.getQxPath()}`);
830
851
  );
831
852
 
832
853
  watch.setConfigFilenames(arr);
854
+
855
+ if (this.__typescriptEnabled && target instanceof qx.tool.compiler.targets.SourceTarget && !this.__typescriptWatcherAttached) {
856
+ this.__typescriptWatcherAttached = true;
857
+ try {
858
+ await this.__attachTypescriptWatcher(watch);
859
+ } catch (ex) {
860
+ qx.tool.compiler.Console.error(ex);
861
+ }
862
+ }
863
+
833
864
  waiters.push(watch.start());
834
865
  }
835
866
  }
867
+
868
+ if (!this.argv.watch && this.__typescriptEnabled) {
869
+ try {
870
+ await this.__attachTypescriptWatcher(null);
871
+ } catch (ex) {
872
+ qx.tool.compiler.Console.error(ex);
873
+ }
874
+ }
875
+
836
876
  return qx.Promise.all(waiters);
837
877
  },
838
878
 
839
879
  /**
840
- * Processes the configuration from a JSON data structure and creates a Maker
880
+ * Processes the configuration from a JSON data structure and creates Makers
841
881
  *
842
- * @param data {Map}
843
- * @return {Maker}
882
+ * @param data {Object} the compile.json configuration data
883
+ * @return {Promise<qx.tool.compiler.makers.Maker[]>}
844
884
  */
845
885
  async createMakersFromConfig(data) {
846
886
  const Console = qx.tool.compiler.Console.getInstance();
@@ -860,6 +900,16 @@ Framework: v${await this.getQxVersion()} in ${await this.getQxPath()}`);
860
900
  delete data.babelOptions;
861
901
  }
862
902
 
903
+ if (qx.lang.Type.isBoolean(data?.meta?.typescript)) {
904
+ this.__typescriptEnabled = data.meta.typescript;
905
+ } else if (qx.lang.Type.isString(data?.meta?.typescript)) {
906
+ this.__typescriptEnabled = true;
907
+ this.__typescriptFile = path.relative(process.cwd(), path.resolve(data.meta.typescript));
908
+ }
909
+ if (this.argv.typescript === true) {
910
+ this.__typescriptEnabled = true;
911
+ }
912
+
863
913
  var argvAppNames = null;
864
914
  if (t.argv["app-name"]) {
865
915
  argvAppNames = {};
@@ -1049,6 +1099,14 @@ Framework: v${await this.getQxVersion()} in ${await this.getQxPath()}`);
1049
1099
  }
1050
1100
  });
1051
1101
 
1102
+ this.__metaDir = data.meta?.output;
1103
+ if (!this.__metaDir && targetConfigs.length > 0) {
1104
+ this.__metaDir = path.relative(
1105
+ process.cwd(),
1106
+ path.resolve(targetConfigs[0].outputPath, "../meta")
1107
+ );
1108
+ }
1109
+
1052
1110
  /*
1053
1111
  * There is still only one target per maker, so convert our list of targetConfigs into an array of makers
1054
1112
  */
@@ -1516,6 +1574,80 @@ Framework: v${await this.getQxVersion()} in ${await this.getQxPath()}`);
1516
1574
  return makers;
1517
1575
  },
1518
1576
 
1577
+ /**
1578
+ * Loads class metadata, generates TypeScript definitions, and (in watch mode) sets up a
1579
+ * debounced file watcher that re-runs metadata parsing and TypeScript generation whenever
1580
+ * a source file changes. When `watch` is null the method performs a single one-shot run
1581
+ * and returns immediately after writing the output.
1582
+ *
1583
+ * @param watch {qx.tool.compiler.cli.Watch|null} watcher instance in watch mode, or null for a one-shot compile
1584
+ */
1585
+ async __attachTypescriptWatcher(watch) {
1586
+ qx.tool.compiler.Console.info(`Loading meta data ...`);
1587
+ let metaDb = new qx.tool.compiler.MetaDatabase().set({ rootDir: this.__metaDir });
1588
+ await metaDb.load(); // hydrates existing class metadata from disk; library map is rebuilt fresh below
1589
+
1590
+ metaDb.getDatabase().libraries = {};
1591
+ const dirs = [];
1592
+ for (let lib of Object.values(this.__libraries)) {
1593
+ let dir = path.join(lib.getRootDir(), lib.getSourcePath());
1594
+ metaDb.getDatabase().libraries[lib.getNamespace()] = { sourceDir: dir };
1595
+ dirs.push(dir);
1596
+ }
1597
+ await metaDb.loadFromDirectories(dirs, { force: !!this.argv.clean });
1598
+ await metaDb.save();
1599
+
1600
+ let tsWriter = null;
1601
+ if (this.__typescriptEnabled) {
1602
+ qx.tool.compiler.Console.info(`Generating typescript output ...`);
1603
+ tsWriter = new qx.tool.compiler.targets.TypeScriptWriter(metaDb);
1604
+ if (this.__typescriptFile) {
1605
+ tsWriter.setOutputTo(this.__typescriptFile);
1606
+ } else {
1607
+ tsWriter.setOutputTo(path.join(this.__metaDir, "..", "qooxdoo.d.ts"));
1608
+ }
1609
+ await tsWriter.process();
1610
+ }
1611
+
1612
+ if (!watch) {
1613
+ return;
1614
+ }
1615
+
1616
+ // Watch mode: re-run metadata and typescript on file changes
1617
+ let classFiles = {};
1618
+ let debounce = new qx.tool.utils.Debounce(async () => {
1619
+ let filesParsed = false;
1620
+ qx.tool.compiler.Console.info(`Loading meta data ...`);
1621
+ let addFilePromises = [];
1622
+ let arr = Object.keys(classFiles);
1623
+ if (arr.length > 0) {
1624
+ filesParsed = true;
1625
+ classFiles = {};
1626
+ arr.forEach(filename => {
1627
+ addFilePromises.push(metaDb.addFile(filename));
1628
+ });
1629
+ }
1630
+ if (filesParsed) {
1631
+ qx.tool.compiler.Console.info(`Generating typescript output ...`);
1632
+ await Promise.all(addFilePromises);
1633
+ await metaDb.reparseAll();
1634
+ await metaDb.save();
1635
+ if (this.__typescriptEnabled) {
1636
+ await tsWriter.process();
1637
+ }
1638
+ }
1639
+ });
1640
+
1641
+ watch.addListener("fileChanged", evt => {
1642
+ let data = evt.getData();
1643
+ if (data.fileType == "source") {
1644
+ let filename = data.library.getFilename(data.filename);
1645
+ classFiles[filename] = true;
1646
+ debounce.run();
1647
+ }
1648
+ });
1649
+ },
1650
+
1519
1651
  /**
1520
1652
  * Checks the dependencies of the current library
1521
1653
  * @param {qx.tool.compiler.app.Library[]} libs
@@ -1663,10 +1795,9 @@ Framework: v${await this.getQxVersion()} in ${await this.getQxPath()}`);
1663
1795
  },
1664
1796
 
1665
1797
  /**
1666
- * Resolves the target class instance from the type name; accepts "source" or "build" or
1667
- * a class name
1798
+ * Resolves the target class from the type name; accepts "source", "build", or a class
1668
1799
  * @param type {String}
1669
- * @returns {Maker}
1800
+ * @returns {Function|null}
1670
1801
  */
1671
1802
  __resolveTargetClass(type) {
1672
1803
  if (!type) {
@@ -1711,7 +1842,7 @@ Framework: v${await this.getQxVersion()} in ${await this.getQxPath()}`);
1711
1842
  * Returns the makers for a given application name
1712
1843
  *
1713
1844
  * @param appName {String} the name of the application
1714
- * @return {Maker}
1845
+ * @return {qx.tool.compiler.makers.Maker[]}
1715
1846
  */
1716
1847
  getMakersForApp(appName) {
1717
1848
  return this.__makers.filter(maker => {
@@ -18,7 +18,6 @@
18
18
  ************************************************************************ */
19
19
  const fs = require("fs");
20
20
  const path = require("upath");
21
- const inquirer = require("inquirer");
22
21
 
23
22
  /**
24
23
  * Create a new qooxdoo project. This will assemble the information needed to create the
@@ -210,6 +209,7 @@ qx.Class.define("qx.tool.compiler.cli.commands.Create", {
210
209
  // ask user for missing values
211
210
  let answers;
212
211
  try {
212
+ const { default: inquirer } = await import("inquirer");
213
213
  answers = await inquirer.prompt(questions);
214
214
  } catch (e) {
215
215
  throw new qx.tool.utils.Utils.UserError(e.message);
@@ -209,7 +209,7 @@ qx.Class.define("qx.tool.compiler.cli.commands.Serve", {
209
209
  });
210
210
  }
211
211
  let config = this.getCompilerApi().getConfiguration();
212
- let listenPort = config?.serve?.listenPort ?? this.argv.listenPort;
212
+ let listenPort = this.argv.listenPort ?? config?.serve?.listenPort;
213
213
  let server = http.createServer(app);
214
214
  this.fireDataEvent("beforeStart", {
215
215
  server: server,
@@ -91,32 +91,6 @@ qx.Class.define("qx.tool.compiler.cli.commands.Typescript", {
91
91
  ig.add(exclude);
92
92
  }
93
93
 
94
- const classFiles = [];
95
-
96
- const scanImpl = async filename => {
97
- let basename = path.basename(filename);
98
- let stat = await fs.promises.stat(filename);
99
-
100
- // Check if this file/directory should be ignored
101
- let relativePath = path.relative(process.cwd(), filename);
102
- if (ig.ignores(relativePath)) {
103
- return;
104
- }
105
-
106
- if (stat.isFile() && basename.match(/\.js$/)) {
107
- classFiles.push(filename);
108
- } else if (
109
- stat.isDirectory() &&
110
- (basename == "." || basename[0] != ".")
111
- ) {
112
- let files = await fs.promises.readdir(filename);
113
- for (let i = 0; i < files.length; i++) {
114
- let subname = path.join(filename, files[i]);
115
- await scanImpl(subname);
116
- }
117
- }
118
- };
119
-
120
94
  let files = this.argv.files || [];
121
95
  if (files.length === 0) {
122
96
  if (fs.existsSync("Manifest.json")) {
@@ -137,18 +111,37 @@ qx.Class.define("qx.tool.compiler.cli.commands.Typescript", {
137
111
  qx.tool.compiler.Console.error("No files to process");
138
112
  process.exit(1);
139
113
  }
140
- for (let file of files) {
141
- await scanImpl(file);
142
- }
143
114
 
144
115
  if (qx.core.Environment.get("qx.debug")) {
145
116
  if (this.argv.metaDebug) {
146
117
  this.argv.verbose = true;
147
- if (classFiles.length > 1) {
148
- console.log("Only one file can be processed in meta debug mode");
118
+ let target = files[0];
119
+ let stat = await fs.promises.stat(target);
120
+ if (stat.isDirectory()) {
121
+ const findFirst = async dir => {
122
+ for (let entry of await fs.promises.readdir(dir)) {
123
+ let full = path.join(dir, entry);
124
+ let s = await fs.promises.stat(full);
125
+ if (s.isFile() && entry.endsWith(".js")) {
126
+ return full;
127
+ }
128
+ if (s.isDirectory() && entry[0] !== ".") {
129
+ let found = await findFirst(full);
130
+ if (found) {
131
+ return found;
132
+ }
133
+ }
134
+ }
135
+ return null;
136
+ };
137
+ target = await findFirst(target);
138
+ if (!target) {
139
+ qx.tool.compiler.Console.error("No .js file found for meta debug");
140
+ process.exit(1);
141
+ }
149
142
  }
150
143
  let meta = new qx.tool.compiler.MetaExtraction();
151
- await meta.parse(classFiles[0]);
144
+ await meta.parse(target);
152
145
  meta.fixupJsDoc({ resolveType: type => type });
153
146
  console.log(JSON.stringify(meta.getMetaData(), null, 2));
154
147
  process.exit(0);
@@ -157,13 +150,7 @@ qx.Class.define("qx.tool.compiler.cli.commands.Typescript", {
157
150
 
158
151
  let metaDb = new qx.tool.compiler.MetaDatabase();
159
152
  await metaDb.load();
160
- for (let filename of classFiles) {
161
- if (this.argv.verbose) {
162
- qx.tool.compiler.Console.info(`Processing ${filename} ...`);
163
- }
164
- await metaDb.addFile(filename);
165
- }
166
- await metaDb.reparseAll();
153
+ await metaDb.loadFromDirectories(files, { ignore: ig, verbose: this.argv.verbose });
167
154
 
168
155
  let tsWriter = new qx.tool.compiler.targets.TypeScriptWriter(metaDb);
169
156
  if (this.argv.outputFilename) {
@@ -20,7 +20,6 @@
20
20
  const fs = require("fs");
21
21
  const process = require("process");
22
22
  const path = require("upath");
23
- const inquirer = require("inquirer");
24
23
  /**
25
24
  * Add a new script file to the current project, to be loaded by the qooxdoo boot loader
26
25
  *
@@ -125,6 +124,7 @@ qx.Class.define("qx.tool.compiler.cli.commands.add.Script", {
125
124
  }
126
125
  if ((await fs.existsAsync(resource_file_path)) && !this.argv.undo) {
127
126
  if (!this.argv.noninteractive) {
127
+ const { default: inquirer } = await import("inquirer");
128
128
  let question = {
129
129
  type: "confirm",
130
130
  name: "doOverwrite",
@@ -20,7 +20,6 @@ const path = require("upath");
20
20
  const process = require("process");
21
21
  const { Octokit } = require("@octokit/rest");
22
22
  const semver = require("semver");
23
- const inquirer = require("inquirer");
24
23
  const { glob } = require("glob");
25
24
 
26
25
  /**
@@ -148,6 +147,7 @@ qx.Class.define("qx.tool.compiler.cli.commands.package.Publish", {
148
147
  async process() {
149
148
  // init
150
149
  const argv = this.argv;
150
+ const { default: inquirer } = await import("inquirer");
151
151
 
152
152
  // qooxdoo version
153
153
  let qxVersion = await this.getQxVersion();
@@ -521,6 +521,7 @@ qx.Class.define("qx.tool.compiler.cli.commands.package.Publish", {
521
521
  * @private
522
522
  */
523
523
  async __createIndexFile(argv) {
524
+ const { default: inquirer } = await import("inquirer");
524
525
  if (argv.verbose && !argv.quiet) {
525
526
  qx.tool.compiler.Console.info("Creating index file...");
526
527
  }
@@ -552,7 +553,7 @@ qx.Class.define("qx.tool.compiler.cli.commands.package.Publish", {
552
553
  let answer = await inquirer.prompt({
553
554
  name: "mainpath",
554
555
  message: "Please choose the main library",
555
- type: "list",
556
+ type: "select",
556
557
  choices
557
558
  });
558
559
 
@@ -18,13 +18,13 @@
18
18
  const process = require("process");
19
19
  const { Octokit } = require("@octokit/rest");
20
20
  const semver = require("semver");
21
- const inquirer = require("inquirer");
22
21
  const path = require("upath");
23
22
 
24
23
  /**
25
24
  * Updates the local cache with information of available library packages
26
25
  *
27
26
  * @ignore(Buffer.from)
27
+ * @ignore(fetch)
28
28
  */
29
29
  qx.Class.define("qx.tool.compiler.cli.commands.package.Update", {
30
30
  extend: qx.tool.compiler.cli.commands.Package,
@@ -120,6 +120,7 @@ qx.Class.define("qx.tool.compiler.cli.commands.package.Update", {
120
120
  await this.updateFromRepository();
121
121
  } else {
122
122
  if (!github.token) {
123
+ const { default: inquirer } = await import("inquirer");
123
124
  let response = await inquirer.prompt([
124
125
  {
125
126
  type: "input",
@@ -173,7 +174,6 @@ qx.Class.define("qx.tool.compiler.cli.commands.package.Update", {
173
174
  }
174
175
  let url = this.getRepositoryCacheUrl();
175
176
  try {
176
- let fetch = (await import("node-fetch")).default;
177
177
  let res = await fetch(url);
178
178
  let data = await res.json();
179
179
  this.setCache(data);
@@ -440,6 +440,9 @@ qx.Class.define("qx.tool.compiler.targets.TypeScriptWriter", {
440
440
 
441
441
  if (typeof typename == "object") {
442
442
  if ("type" in typename) {
443
+ if (!typename.type) {
444
+ return defaultType;
445
+ }
443
446
  const dimensions = typename.dimensions ?? 1;
444
447
  typename = typename.type + "[]".repeat(dimensions - 1);
445
448
  } else {