@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
@@ -80,7 +80,27 @@ qx.Class.define("qx.tool.compiler.targets.meta.Browserify", {
80
80
  async writeToDisk() {
81
81
  const localModules = this.getAppMeta().getApplication().getLocalModules();
82
82
  let db = this.getAppMeta().getAnalyser().getDatabase();
83
- const { commonjsModules } = this.__getCommonjsModules();
83
+ const { commonjsModules, references } = this.__getCommonjsModules();
84
+
85
+ // Warn about missing npm modules on every compile, not just when the bundle is rebuilt
86
+ if (this.getAppMeta().getEnvironmentValue("qx.compiler.applicationType") == "browser") {
87
+ for (const moduleName of commonjsModules) {
88
+ try {
89
+ require.resolve(moduleName, { paths: [process.cwd()] });
90
+ } catch (_) {
91
+ const msg = [`WARNING: could not locate require()d module: "${moduleName}"`, " required from:"];
92
+ const modRefs = references[moduleName];
93
+ if (modRefs) {
94
+ for (const mr of modRefs) {
95
+ for (const ref of mr) {
96
+ msg.push(" " + ref);
97
+ }
98
+ }
99
+ }
100
+ qx.tool.compiler.Console.error(msg.join("\n"));
101
+ }
102
+ }
103
+ }
84
104
 
85
105
  let modules = [];
86
106
  let modulesInfo = {};
@@ -147,91 +167,133 @@ qx.Class.define("qx.tool.compiler.targets.meta.Browserify", {
147
167
  });
148
168
  },
149
169
 
150
- __browserify(commonjsModules, references, localModules, ws) {
151
- const babelify = require("babelify");
152
- const preset = require("@babel/preset-env");
153
- const browserify = require("browserify");
154
- const builtins = require("browserify/lib/builtins.js");
155
-
156
- // For some reason, `process` is not require()able, but `_process` is.
157
- // Make them equivalent.
158
- builtins.process = builtins._process;
159
-
160
- return new Promise((resolve, reject) => {
161
- const options = {
162
- builtins: builtins,
163
- ignoreMissing: true,
164
- insertGlobals: true,
165
- detectGlobals: true
166
- };
167
- qx.lang.Object.mergeWith(
168
- options,
169
- this.getAppMeta().getAnalyser().getBrowserifyConfig()?.options || {},
170
- false
171
- );
172
- let b = browserify([], options);
170
+ async __browserify(commonjsModules, references, localModules, ws) {
171
+ const esbuild = require("esbuild");
172
+ const { polyfillNode } = require("esbuild-plugin-polyfill-node");
173
173
 
174
- b._mdeps.on("missing", (id, parent) => {
175
- let message = [];
176
- message.push(`ERROR: could not locate require()d module: "${id}"`);
177
- message.push(" required from:");
178
- try {
179
- [...references[id]].forEach(refs => {
180
- refs.forEach(ref => {
181
- message.push(` ${ref}`);
182
- });
183
- });
184
- } catch (e) {
185
- message.push(` <compile.json:application.localModules'>`);
186
- }
187
- qx.tool.compiler.Console.error(message.join("\n"));
188
- });
174
+ // Convert a module name to a valid JS identifier
175
+ const safeName = name => "_m_" + name.replace(/[^a-zA-Z0-9_$]/g, "_");
189
176
 
190
- // Include any dynamically determined `require()`d modules
191
- if (commonjsModules.length > 0) {
192
- b.require(commonjsModules);
177
+ // esbuild equivalent of browserify's ignoreMissing:true — logs a warning and
178
+ // returns an empty module stub so the bundle is still produced
179
+ const missingModulePlugin = {
180
+ name: "qx-missing-module",
181
+ setup(build) {
182
+ const onResolveHandler = async args => {
183
+ if (args.namespace === "qx-missing") { return null; }
184
+ const searchPaths = [args.resolveDir, process.cwd()].filter(Boolean);
185
+ for (const dir of searchPaths) {
186
+ try {
187
+ require.resolve(args.path, { paths: [dir] });
188
+ return null;
189
+ } catch (_) {}
190
+ }
191
+ return { path: args.path, namespace: "qx-missing" };
192
+ };
193
+ build.onResolve({ filter: /^[^./]/ }, onResolveHandler);
194
+ build.onLoad({ filter: /.*/, namespace: "qx-missing" }, args => ({
195
+ contents: `// Missing module: ${args.path}\nmodule.exports = {};`,
196
+ loader: "js"
197
+ }));
193
198
  }
199
+ };
194
200
 
195
- // Include any local modules specified for the application
196
- // in compile.json
197
- if (localModules) {
198
- for (let requireName in localModules) {
199
- b.require(localModules[requireName], { expose: requireName });
200
- }
201
+ const allModules = [
202
+ ...commonjsModules.map(m => ({ require: m, file: m })),
203
+ ...Object.entries(localModules || {}).map(([name, file]) => ({ require: name, file }))
204
+ ];
205
+
206
+ // Build a virtual entry that imports all required modules and exposes
207
+ // them via a global require() function compatible with Qooxdoo's runtime require() calls
208
+ const entryContent = [
209
+ ...allModules.map(m => `import * as ${safeName(m.require)} from ${JSON.stringify(m.file)};`),
210
+ `const __qx_mods = {`,
211
+ ...allModules.map(m => ` ${JSON.stringify(m.require)}: ${safeName(m.require)},`),
212
+ `};`,
213
+ `const __prev = typeof globalThis.require === "function" ? globalThis.require : null;`,
214
+ `globalThis.require = function(name) {`,
215
+ ` if (name in __qx_mods) return __qx_mods[name];`,
216
+ ` if (__prev) return __prev(name);`,
217
+ ` throw new Error("Module not found: " + name);`,
218
+ `};`
219
+ ].join("\n");
220
+
221
+ // Merge in any user-provided esbuild options from compile.json's "browserify" key
222
+ const browserifyConfig = this.getAppMeta().getAnalyser().getBrowserifyConfig() || {};
223
+ const userOptions = { ...(browserifyConfig.options || {}) };
224
+
225
+ // Filter out browserify-only options that esbuild doesn't understand
226
+ const BROWSERIFY_ONLY_OPTS = ["noParse", "ignoreMissing", "insertGlobals", "detectGlobals", "builtins"];
227
+ for (const opt of BROWSERIFY_ONLY_OPTS) {
228
+ if (opt in userOptions) {
229
+ qx.tool.compiler.Console.warn(
230
+ `WARNING: compile.json browserify.options.${opt} is a browserify-only option and is not supported by esbuild — it will be ignored.` +
231
+ (opt === "noParse" ? ' Use esbuild\'s "external" option instead if needed.' : "")
232
+ );
233
+ delete userOptions[opt];
201
234
  }
202
- // Ensure ES6 local modules are converted to CommonJS format
203
- b.transform(babelify, {
204
- presets: [preset],
205
- sourceMaps: false,
206
- global: true
207
- });
208
-
209
- b.bundle(function (e, output) {
210
- if (e) {
211
- // THIS IS A HACK!
212
- // In case of error dependency walker never returns from
213
- // ```if (self.inputPending > 0) return setTimeout(resolve);```
214
- // because inputPending is not decremented anymore.
215
- // so set it to 0 here.
216
- let d = b.pipeline.get("deps");
217
- d.get(0).inputPending = 0;
218
- qx.tool.compiler.Console.error(
219
- `Unable to browserify - this is probably because a module is being require()'d which is not compatible with Browserify:\n${e.message}`
220
- );
221
-
222
- setTimeout(() => {
223
- this.emit("end");
224
- });
225
- return;
235
+ }
236
+
237
+ // polyfillNode is enabled by default; set browserify.polyfillNode: false in compile.json to disable
238
+ const usePolyfillNode = browserifyConfig.polyfillNode !== false;
239
+
240
+ // Extract define and plugins manually (object rest destructuring is not supported by the qx parser)
241
+ const userDefine = userOptions.define || {};
242
+ const userPlugins = Array.isArray(userOptions.plugins) ? userOptions.plugins : [];
243
+ delete userOptions.define;
244
+ delete userOptions.plugins;
245
+ const basePlugins = usePolyfillNode ? [polyfillNode()] : [];
246
+
247
+ let result;
248
+ try {
249
+ result = await esbuild.build(
250
+ Object.assign(
251
+ {
252
+ stdin: {
253
+ contents: entryContent,
254
+ resolveDir: process.cwd()
255
+ },
256
+ bundle: true,
257
+ platform: "browser",
258
+ format: "iife",
259
+ write: false,
260
+ sourcemap: false,
261
+ logLevel: "silent",
262
+ // Preserve .name property of classes/functions even when esbuild renames bindings to
263
+ // avoid scope conflicts inside already-bundled packages (e.g. browserified bundles that
264
+ // have duplicate identifier names across inlined modules).
265
+ keepNames: true,
266
+ // Replace global with globalThis so Node.js packages using `global.<x>` work in browsers
267
+ define: Object.assign({ global: "globalThis" }, userDefine),
268
+ plugins: basePlugins.concat([missingModulePlugin], userPlugins)
269
+ },
270
+ userOptions
271
+ )
272
+ );
273
+ } catch (e) {
274
+ // Report missing/unresolvable modules with context from the analyser database
275
+ for (const err of e.errors || []) {
276
+ const id = err.text?.match(/Cannot resolve "([^"]+)"/)?.[1] || err.text;
277
+ let message = [`ERROR: could not bundle module: "${id || err.text}"`];
278
+ if (id && references[id]) {
279
+ message.push(" required from:");
280
+ try {
281
+ for (const refs of references[id]) {
282
+ for (const ref of refs) {
283
+ message.push(" " + ref);
284
+ }
285
+ }
286
+ } catch (_) {}
226
287
  }
227
- // in case of end event output can not be writen.
228
- // so catch the error and ignore it
229
- try {
230
- ws.write(output);
231
- } catch (err) {}
232
- resolve(null);
233
- });
234
- });
288
+ qx.tool.compiler.Console.error(message.join("\n"));
289
+ }
290
+ qx.tool.compiler.Console.error(`Unable to bundle CommonJS modules: ${e.message}`);
291
+ return;
292
+ }
293
+
294
+ try {
295
+ ws.write(Buffer.from(result.outputFiles[0].contents));
296
+ } catch (_) {}
235
297
  },
236
298
 
237
299
  /**
@@ -74,9 +74,7 @@ qx.Class.define("qx.tool.migration.M8_0_0", {
74
74
  "cancelled before refreshing table model data.\n" +
75
75
  "See: https://github.com/qooxdoo/qooxdoo/blob/master/CHANGELOG.md#breaking-changes"
76
76
  );
77
- this.markAsPending(
78
- "Manual review required for table model data updates"
79
- );
77
+ // Informational only — cannot be auto-detected, so no markAsPending
80
78
  },
81
79
 
82
80
  /**
@@ -368,7 +366,9 @@ qx.Class.define("qx.tool.migration.M8_0_0", {
368
366
  " Old: '@qooxdoo/qx'\n" +
369
367
  " New: '@qooxdoo/eslint-plugin-qx' or full import"
370
368
  );
371
- this.markAsPending("Verify Node.js version >= 20.0.0");
369
+ if (!semver.gte(process.versions.node, "20.0.0")) {
370
+ this.markAsPending("Verify Node.js version >= 20.0.0");
371
+ }
372
372
  },
373
373
 
374
374
  /**
@@ -226,10 +226,6 @@ qx.Class.define("qx.ui.core.SingleSelectionManager", {
226
226
  var oldSelected = this.__selected;
227
227
  var newSelected = item;
228
228
 
229
- if (newSelected != null && oldSelected === newSelected) {
230
- return;
231
- }
232
-
233
229
  if (!this.isAllowEmptySelection() && newSelected == null) {
234
230
  var firstElement = this.getSelectables(true)[0];
235
231
 
@@ -238,6 +234,10 @@ qx.Class.define("qx.ui.core.SingleSelectionManager", {
238
234
  }
239
235
  }
240
236
 
237
+ if (newSelected !== null && newSelected === oldSelected) {
238
+ return;
239
+ }
240
+
241
241
  this.__selected = newSelected;
242
242
  this.fireDataEvent("changeSelected", newSelected, oldSelected);
243
243
  },
@@ -488,7 +488,7 @@ qx.Class.define("qx.ui.form.validation.Manager", {
488
488
 
489
489
  let msg = item.getInvalidMessage();
490
490
  if (
491
- msg &&
491
+ !msg &&
492
492
  qx.core.Environment.get(
493
493
  "qx.ui.form.validation.Manager.allowDefaultInvalidMessage"
494
494
  )
@@ -472,7 +472,7 @@ qx.Class.define("qx.ui.toolbar.ToolBar", {
472
472
  _add(child, options) {
473
473
  super._add(child, options);
474
474
  // sync the show property (bug #6743) - but only if show wasn't explicitly set for the child (bug #6823)
475
- if (child.setShowFeatures && !qx.util.PropertyUtil.getProperty(child, "showFeatures").isThemedValue(child)) {
475
+ if (child.setShowFeatures && !qx.util.PropertyUtil.getProperty(child, "showFeatures").isUserValue(child)) {
476
476
  child.setShowFeatures(this.getShowFeatures());
477
477
  }
478
478
 
@@ -484,7 +484,7 @@ qx.Class.define("qx.ui.toolbar.ToolBar", {
484
484
  _addAt(child, index, options) {
485
485
  super._addAt(child, index, options);
486
486
  // sync the show property (bug #6743) - but only if show wasn't explicitly set for the child (bug #6823)
487
- if (child.setShowFeatures && !qx.util.PropertyUtil.getProperty(child, "showFeatures").isThemedValue(child)) {
487
+ if (child.setShowFeatures && !qx.util.PropertyUtil.getProperty(child, "showFeatures").isUserValue(child)) {
488
488
  child.setShowFeatures(this.getShowFeatures());
489
489
  }
490
490
 
@@ -496,7 +496,7 @@ qx.Class.define("qx.ui.toolbar.ToolBar", {
496
496
  _addBefore(child, before, options) {
497
497
  super._addBefore(child, before, options);
498
498
  // sync the show property (bug #6743) - but only if show wasn't explicitly set for the child (bug #6823)
499
- if (child.setShowFeatures && !qx.util.PropertyUtil.getProperty(child, "showFeatures").isThemedValue()) {
499
+ if (child.setShowFeatures && !qx.util.PropertyUtil.getProperty(child, "showFeatures").isUserValue(child)) {
500
500
  child.setShowFeatures(this.getShowFeatures());
501
501
  }
502
502
 
@@ -508,7 +508,7 @@ qx.Class.define("qx.ui.toolbar.ToolBar", {
508
508
  _addAfter(child, after, options) {
509
509
  super._addAfter(child, after, options);
510
510
  // sync the show property (bug #6743) - but only if show wasn't explicitly set for the child (bug #6823)
511
- if (child.setShowFeatures && !qx.util.PropertyUtil.getProperty(child, "showFeatures").isThemedValue()) {
511
+ if (child.setShowFeatures && !qx.util.PropertyUtil.getProperty(child, "showFeatures").isUserValue(child)) {
512
512
  child.setShowFeatures(this.getShowFeatures());
513
513
  }
514
514
 
@@ -12,9 +12,8 @@ qx.Class.define("${classname}",
12
12
  /**
13
13
  * Constructor
14
14
  */
15
- construct : function() {
16
- // If you want to call the parent constructor, use
17
- // this.base(arguments);
15
+ construct() {
16
+ super();
18
17
  },
19
18
 
20
19
  /**
@@ -62,7 +61,7 @@ qx.Class.define("${classname}",
62
61
  * @param {number} bar The bar parameter
63
62
  * @return The result of the method.
64
63
  */
65
- myMethod : function(foo, bar) {
64
+ myMethod(foo, bar) {
66
65
  //
67
66
  },
68
67
 
@@ -72,7 +71,7 @@ qx.Class.define("${classname}",
72
71
  * @param {string} value new value
73
72
  * @param {string} old the old value
74
73
  */
75
- _applyFoo : function(value, old) {
74
+ _applyFoo(value, old) {
76
75
  //
77
76
  }
78
77
 
@@ -81,7 +80,7 @@ qx.Class.define("${classname}",
81
80
  /**
82
81
  * Use for disposing objects created by class instances
83
82
  */
84
- destruct : function() {
83
+ destruct() {
85
84
  //
86
- }
85
+ }
87
86
  });
@@ -14,9 +14,8 @@ qx.Class.define("${classname}",
14
14
  /**
15
15
  * Create a the singleton
16
16
  */
17
- construct : function() {
18
- // If you want to call the parent constructor, use
19
- // this.base(arguments);
17
+ construct() {
18
+ super();
20
19
  },
21
20
 
22
21
  /**
@@ -55,15 +54,15 @@ qx.Class.define("${classname}",
55
54
  * @param {Number} bar The bar parameter
56
55
  * @return {void} The result of the method.
57
56
  */
58
- myMethod : function(foo, bar)
57
+ myMethod(foo, bar)
59
58
  {
60
59
  //
61
60
  },
62
61
 
63
62
  /** Applies the foo property */
64
- _applyFoo : function(value, old)
63
+ _applyFoo(value, old)
65
64
  {
66
65
  //
67
- }
66
+ }
68
67
  }
69
68
  });
@@ -320,7 +320,7 @@
320
320
  },
321
321
  "browserifyOptions": {
322
322
  "type": "object",
323
- "description": "Options given to browserify. For details see here: <https://github.com/browserify/browserify#usage>. They can be overridden per target."
323
+ "description": "Options passed to esbuild when bundling CommonJS modules. See https://esbuild.github.io/api/ for available options. They can be overridden per target. Browserify-specific options (noParse, ignoreMissing, insertGlobals, detectGlobals, builtins) are not supported and will be ignored with a warning."
324
324
  },
325
325
  "parts": {
326
326
  "$ref": "#/properties/parts"
@@ -465,9 +465,13 @@
465
465
  "browserify": {
466
466
  "type": "object",
467
467
  "properties": {
468
+ "polyfillNode": {
469
+ "type": "boolean",
470
+ "description": "Whether to include the esbuild-plugin-polyfill-node plugin, which provides browser shims for Node.js built-ins (process, buffer, etc.). Defaults to true. Set to false if your packages do not use Node.js built-ins and you want a smaller bundle."
471
+ },
468
472
  "options": {
469
473
  "type": "object",
470
- "description": "Options given to browserify. For details see here: <https://github.com/browserify/browserify#usage>. They can be overridden per target."
474
+ "description": "Options passed to esbuild when bundling CommonJS modules. See https://esbuild.github.io/api/ for available options. They can be overridden per target. Browserify-specific options (noParse, ignoreMissing, insertGlobals, detectGlobals, builtins) are not supported and will be ignored with a warning."
471
475
  }
472
476
  }
473
477
  },