@qooxdoo/framework 7.3.2 → 7.4.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.
@@ -107,12 +107,6 @@ module.exports = function (argv, data) {
107
107
  return "^" + data.qooxdoo_version;
108
108
  }
109
109
  },
110
- "compiler_range": {
111
- "description": "the semver range of qooxdoo compiler versions that are compatible with this application",
112
- "default": function () {
113
- return "^" + qx.tool.config.Utils.getCompilerVersion();
114
- }
115
- },
116
110
  "theme": {
117
111
  "description": "the theme of the application",
118
112
  "default": argv.theme
@@ -47,6 +47,12 @@
47
47
  }
48
48
  }
49
49
  },
50
+ "localModules": {
51
+ "type": "object",
52
+ "additionalProperties": {
53
+ "type": "string"
54
+ }
55
+ },
50
56
  "applications": {
51
57
  "type":"array",
52
58
  "description": "Each entry describes an application to be compiled.",
@@ -174,10 +180,7 @@
174
180
  "$ref": "#/properties/parts"
175
181
  },
176
182
  "localModules": {
177
- "type": "object",
178
- "additionalProperties": {
179
- "type": "string"
180
- }
183
+ "$ref": "#/properties/localModules"
181
184
  }
182
185
  }
183
186
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@qooxdoo/framework",
3
- "version": "7.3.2",
3
+ "version": "7.4.0",
4
4
  "description": "The JS Framework for Coders",
5
5
  "author": "The qooxdoo project",
6
6
  "keywords": [
@@ -44,6 +44,7 @@
44
44
  "files": [
45
45
  "LICENSE",
46
46
  "addGitHook",
47
+ "bin/tools/utils.js",
47
48
  "CHANGELOG.md",
48
49
  "README.md",
49
50
  "Manifest.json",
@@ -189,7 +189,7 @@ qx.Class.define("qx.test.bom.media.MediaTestCase", {
189
189
  "test Play Event"() {
190
190
  if (navigator.plugins.length == 0) {
191
191
  this.skip(
192
- "Headless browser HTML5 audio/video play event test disabled on headless browsers"
192
+ "HTML5 audio/video play event test disabled on headless browsers"
193
193
  );
194
194
  }
195
195
  // Disabled on travis because of events not being fired reliable
@@ -24,7 +24,7 @@ qx.Class.define("qx.test.io.transport.Websocket", {
24
24
  extend: qx.dev.unit.TestCase,
25
25
 
26
26
  statics: {
27
- TEST_ENDPOINT: "echo.websocket.events"
27
+ TEST_ENDPOINT: "socketsbay.com/wss/v2/2/demo/"
28
28
  },
29
29
 
30
30
  members: {
@@ -111,7 +111,11 @@ qx.Class.define("qx.test.ui.form.Form", {
111
111
  },
112
112
  function (e) {
113
113
  self.assertEquals("affe", e.getData(), "Wrong data in the event.");
114
- self.assertEquals("", e.getOldData(), "Wrong old data in the event.");
114
+ self.assertEquals(
115
+ null,
116
+ e.getOldData(),
117
+ "Wrong old data in the event."
118
+ );
115
119
  },
116
120
  "Change event not fired!"
117
121
  );
@@ -21,6 +21,10 @@ qx.Class.define("qx.test.util.DeferredCall", {
21
21
 
22
22
  members: {
23
23
  testGlobalErrorHandling() {
24
+ if (navigator.plugins.length == 0) {
25
+ this.skip("test disabled on headless browsers");
26
+ }
27
+
24
28
  var fail = function () {
25
29
  throw new Error("fail");
26
30
  };
@@ -518,7 +518,8 @@ Version: v${await qx.tool.config.Utils.getQxVersion()}
518
518
  parsedArgs.environment[key] = value;
519
519
  });
520
520
  }
521
- config.targetType = parsedArgs.target || config.defaultTarget || "source";
521
+
522
+ let targetType = this._compilerApi.getCommand().getTargetType();
522
523
 
523
524
  if (!config.locales) {
524
525
  config.locales = [];
@@ -536,7 +537,7 @@ Version: v${await qx.tool.config.Utils.getQxVersion()}
536
537
  // one and assign it to the target.
537
538
  if (config.targets) {
538
539
  const target = config.targets.find(
539
- target => target.type === config.targetType
540
+ target => target.type === targetType
540
541
  );
541
542
 
542
543
  target.environment = target.environment || {};
@@ -170,6 +170,13 @@ qx.Class.define("qx.tool.cli.Watch", {
170
170
  if (dir && !dirs.includes(dir)) {
171
171
  dirs.push(dir);
172
172
  }
173
+ let localModules = application.getLocalModules();
174
+ for (let requireName in localModules) {
175
+ let dir = localModules[requireName];
176
+ if (dir && !dirs.includes(dir)) {
177
+ dirs.push(dir);
178
+ }
179
+ }
173
180
  });
174
181
  if (this.isDebug()) {
175
182
  qx.tool.compiler.Console.debug(
@@ -291,15 +298,22 @@ qx.Class.define("qx.tool.cli.Watch", {
291
298
  data.dependsOn = {};
292
299
  var deps = data.application.getDependencies();
293
300
  deps.forEach(function (classname) {
294
- var info = db.classInfo[classname];
295
- var lib = analyser.findLibrary(info.libraryName);
296
- var parts = [lib.getRootDir(), lib.getSourcePath()].concat(
301
+ let info = db.classInfo[classname];
302
+ let lib = analyser.findLibrary(info.libraryName);
303
+ let parts = [lib.getRootDir(), lib.getSourcePath()].concat(
297
304
  classname.split(".")
298
305
  );
299
306
 
300
- var filename = path.resolve.apply(path, parts) + ".js";
307
+ let filename = path.resolve.apply(path, parts) + ".js";
301
308
  data.dependsOn[filename] = true;
302
309
  });
310
+
311
+ let localModules = data.application.getLocalModules();
312
+ for (let requireName in localModules) {
313
+ let filename = path.resolve(localModules[requireName]);
314
+ data.dependsOn[filename] = true;
315
+ }
316
+
303
317
  var filename = path.resolve(data.application.getLoaderTemplate());
304
318
  promises.push(
305
319
  qx.tool.utils.files.Utils.correctCase(filename).then(
@@ -173,6 +173,14 @@ qx.Class.define("qx.tool.cli.commands.Command", {
173
173
  } catch (e) {
174
174
  throw new qx.tool.utils.Utils.UserError(e.message);
175
175
  }
176
- }
176
+ },
177
+
178
+ /**
179
+ * Returns the calculated target type
180
+ * @returns {String}
181
+ */
182
+ getTargetType() {
183
+ return this.argv.target || this.getCompilerApi().getConfiguration().defaultTarget || "source";
184
+ },
177
185
  }
178
186
  });
@@ -344,7 +344,6 @@ qx.Class.define("qx.tool.cli.commands.Compile", {
344
344
  members: {
345
345
  __gauge: null,
346
346
  __makers: null,
347
- __config: null,
348
347
  __libraries: null,
349
348
  __outputDirWasCreated: false,
350
349
 
@@ -532,13 +531,7 @@ Framework: v${await this.getQxVersion()} in ${await this.getQxPath()}`);
532
531
  * @return {Boolean} true if all makers succeeded
533
532
  */
534
533
  async _loadConfigAndStartMaking() {
535
- var config = (this.__config =
536
- await qx.tool.cli.Cli.getInstance().getParsedArgs());
537
- if (!config) {
538
- throw new qx.tool.utils.Utils.UserError(
539
- "Error: Cannot find any configuration"
540
- );
541
- }
534
+ var config = this.getCompilerApi().getConfiguration();
542
535
  var makers = (this.__makers = await this.createMakersFromConfig(config));
543
536
  if (!makers || !makers.length) {
544
537
  throw new qx.tool.utils.Utils.UserError(
@@ -750,7 +743,7 @@ Framework: v${await this.getQxVersion()} in ${await this.getQxPath()}`);
750
743
  let targetConfigs = [];
751
744
  let defaultTargetConfig = null;
752
745
  data.targets.forEach(targetConfig => {
753
- if (targetConfig.type === data.targetType) {
746
+ if (targetConfig.type === this.getTargetType()) {
754
747
  if (
755
748
  !targetConfig["application-names"] &&
756
749
  !targetConfig["application-types"]
@@ -1231,8 +1224,13 @@ Framework: v${await this.getQxVersion()} in ${await this.getQxPath()}`);
1231
1224
  if (appConfig.description) {
1232
1225
  app.setDescription(appConfig.description);
1233
1226
  }
1234
-
1235
- if (appConfig.localModules) {
1227
+ appConfig.localModules = appConfig.localModules || {};
1228
+ qx.lang.Object.mergeWith(
1229
+ appConfig.localModules,
1230
+ data.localModules || {},
1231
+ false
1232
+ );
1233
+ if (!qx.lang.Object.isEmpty(appConfig.localModules)) {
1236
1234
  app.setLocalModules(appConfig.localModules);
1237
1235
  }
1238
1236
 
@@ -1578,13 +1576,6 @@ Framework: v${await this.getQxVersion()} in ${await this.getQxPath()}`);
1578
1576
  });
1579
1577
  },
1580
1578
 
1581
- /**
1582
- * Returns the configuration object being compiled
1583
- */
1584
- _getConfig() {
1585
- return this.__config;
1586
- },
1587
-
1588
1579
  /**
1589
1580
  * Returns a list of libraries which are used
1590
1581
  *
@@ -65,7 +65,7 @@ qx.Class.define("qx.tool.cli.commands.Run", {
65
65
  this.argv["machine-readable"] = false;
66
66
  this.argv["feedback"] = false;
67
67
  await super.process();
68
- let config = this._getConfig();
68
+ let config = this.getCompilerApi().getConfiguration();
69
69
  if (!config.run) {
70
70
  qx.tool.compiler.Console.print("qx.tool.cli.run.noRunConfig");
71
71
  process.exit(-1);
@@ -155,7 +155,7 @@ qx.Class.define("qx.tool.cli.commands.Serve", {
155
155
  if (this.__showStartpage === undefined || this.__showStartpage === null) {
156
156
  this.__showStartpage = defaultMaker === null;
157
157
  }
158
- var config = this._getConfig();
158
+ let config = this.getCompilerApi().getConfiguration();
159
159
  const app = express();
160
160
  app.use((req, res, next) => {
161
161
  res.set({
@@ -195,17 +195,28 @@ qx.Class.define("qx.tool.compiler.makers.AppMaker", {
195
195
  // will be no dependencies so we just compile anyway, but `qx compile --watch` will call it
196
196
  // multiple times
197
197
  let compiledClasses = this.getRecentlyCompiledClasses(true);
198
- var appsThisTime = this.__applications.filter(app => {
198
+ let db = analyser.getDatabase();
199
+
200
+ var appsThisTime = await this.__applications.filter(async app => {
199
201
  let loadDeps = app.getDependencies();
200
202
  if (!loadDeps || !loadDeps.length) {
201
203
  return true;
202
204
  }
203
- return loadDeps.some(name => Boolean(compiledClasses[name]));
205
+ let res = loadDeps.some(name => Boolean(compiledClasses[name]));
206
+ let localModules = app.getLocalModules();
207
+ for (let requireName in localModules) {
208
+ let stat = await qx.tool.utils.files.Utils.safeStat(
209
+ localModules[requireName]
210
+ );
211
+ res ||=
212
+ stat.mtime.getTime() >
213
+ (db?.modulesInfo?.localModules[requireName] || 0);
214
+ }
215
+ return res;
204
216
  });
205
217
 
206
218
  let allAppInfos = [];
207
219
 
208
- let db = analyser.getDatabase();
209
220
  for (let i = 0; i < appsThisTime.length; i++) {
210
221
  let application = appsThisTime[i];
211
222
  if (application.getType() != "browser" && !compileEnv["qx.headless"]) {
@@ -20,8 +20,7 @@
20
20
  *
21
21
  * ************************************************************************/
22
22
 
23
- const fs = qx.tool.utils.Promisify.fs;
24
- const path = require("upath");
23
+ const hash = require("object-hash");
25
24
 
26
25
  /**
27
26
  *
@@ -31,66 +30,114 @@ qx.Class.define("qx.tool.compiler.targets.meta.Browserify", {
31
30
 
32
31
  construct(appMeta) {
33
32
  super(appMeta, `${appMeta.getApplicationRoot()}commonjs-browserify.js`);
34
- this.__appMeta = appMeta;
33
+ this.__commonjsModules = [];
34
+ this.__references = {};
35
35
  this.setNeedsWriteToDisk(true);
36
36
  },
37
37
 
38
38
  members: {
39
- __appMeta: null,
39
+ __commonjsModules: null,
40
+ __references: null,
40
41
 
41
- /**
42
- * @Override
43
- */
44
- async writeSourceCodeToStream(ws) {
45
- let hasCommonjsModules = false;
42
+ __getCommonjsModules() {
46
43
  let commonjsModules = new Set();
47
44
  let references = {};
45
+ const db = this.getAppMeta().getAnalyser().getDatabase();
48
46
  const localModules =
49
- this.__appMeta.getApplication().getLocalModules() || {};
50
- const db = this.__appMeta.getAnalyser().getDatabase();
51
-
52
- // Only include discovered `require()`d Node modules if the
53
- // target application type is browser.
54
- if (
55
- this.__appMeta.getEnvironmentValue("qx.compiler.applicationType") ==
56
- "browser"
57
- ) {
58
- // Get a Set of unique `require`d CommonJS module names from classes needed by the application
59
- let classnames = this.__appMeta.getApplication().getDependencies();
60
- for (let className of classnames) {
61
- let classInfo = db.classInfo[className];
62
- if (classInfo.commonjsModules) {
63
- Object.keys(classInfo.commonjsModules).forEach(moduleName => {
64
- // Ignore this found `require()` if its a local modules
65
- if (moduleName in localModules) {
66
- return;
67
- }
68
-
47
+ this.getAppMeta().getApplication().getLocalModules() || {};
48
+ // Get a Set of unique `require`d CommonJS module names from
49
+ // all classes
50
+ for (let className in db.classInfo) {
51
+ let classInfo = db.classInfo[className];
52
+ if (classInfo.commonjsModules) {
53
+ Object.keys(classInfo.commonjsModules).forEach(moduleName => {
54
+ // Ignore this found `require()` if its a local modules
55
+ if (!(moduleName in localModules)) {
69
56
  // Add this module name to the set of module names
70
57
  commonjsModules.add(moduleName);
58
+ }
59
+ // Add the list of references from which this module was require()d
60
+ if (!references[moduleName]) {
61
+ references[moduleName] = new Set();
62
+ }
63
+ references[moduleName].add([
64
+ ...classInfo.commonjsModules[moduleName]
65
+ ]);
66
+ });
67
+ }
68
+ }
69
+ return { commonjsModules: [...commonjsModules], references: references };
70
+ },
71
71
 
72
- // Add the list of references from which this module was require()d
73
- if (!references[moduleName]) {
74
- references[moduleName] = new Set();
75
- }
76
- references[moduleName].add([
77
- ...classInfo.commonjsModules[moduleName]
78
- ]);
79
-
80
- // There is at least one module
81
- hasCommonjsModules = true;
82
- });
83
- }
72
+ /**
73
+ * @Override
74
+ */
75
+ async writeToDisk() {
76
+ const localModules = this.getAppMeta().getApplication().getLocalModules();
77
+ let db = this.getAppMeta().getAnalyser().getDatabase();
78
+ const { commonjsModules, references } = this.__getCommonjsModules();
79
+
80
+ let modules = [];
81
+ let modulesInfo = {};
82
+ let doIt = !!!(await qx.tool.utils.files.Utils.safeStat(
83
+ this.getFilename()
84
+ ));
85
+
86
+ // Include any dynamically determined `require()`d modules
87
+ if (commonjsModules.length > 0) {
88
+ modules.push(commonjsModules);
89
+ }
90
+ // Include any local modules specified for the application
91
+ // in compile.json
92
+ if (localModules) {
93
+ modulesInfo.localModules = {};
94
+ for (let requireName in localModules) {
95
+ modules.push(requireName);
96
+ let stat = await qx.tool.utils.files.Utils.safeStat(
97
+ localModules[requireName]
98
+ );
99
+
100
+ modulesInfo.localModules[requireName] = stat.mtime.getTime();
101
+ doIt ||=
102
+ modulesInfo.localModules[requireName] >
103
+ (db?.modulesInfo?.localModules[requireName] || 0);
84
104
  }
85
105
  }
106
+ modulesInfo.modulesHash = hash(modules);
107
+ doIt ||= modulesInfo.modulesHash !== (db?.modulesInfo?.modulesHash || "");
108
+ if (doIt) {
109
+ db.modulesInfo = modulesInfo;
110
+ await this.getAppMeta().getAnalyser().saveDatabase();
111
+ this.__commonjsModules = commonjsModules;
112
+ this.__references = references;
113
+ }
114
+ this.setNeedsWriteToDisk(doIt);
115
+ return super.writeToDisk();
116
+ },
86
117
 
118
+ /**
119
+ * @Override
120
+ */
121
+ async writeSourceCodeToStream(ws) {
87
122
  // If there are any CommonJS modules required to be bundled, or
88
123
  // any local modules specified for the application in
89
124
  // compile.json, browserify them
90
- if (hasCommonjsModules || localModules) {
91
- await this.__browserify(commonjsModules, references, localModules, ws);
125
+ if (
126
+ this.getAppMeta().getEnvironmentValue("qx.compiler.applicationType") ==
127
+ "browser"
128
+ ) {
129
+ const localModules = this.getAppMeta()
130
+ .getApplication()
131
+ .getLocalModules();
132
+ if (this.__commonjsModules || localModules) {
133
+ await this.__browserify(
134
+ this.__commonjsModules,
135
+ this.__references,
136
+ localModules,
137
+ ws
138
+ );
139
+ }
92
140
  }
93
-
94
141
  await new Promise(resolve => {
95
142
  ws.write("\n", resolve);
96
143
  });
@@ -106,10 +153,7 @@ qx.Class.define("qx.tool.compiler.targets.meta.Browserify", {
106
153
  // Make them equivalent.
107
154
  builtins.process = builtins._process;
108
155
 
109
- // Convert the Set of CommonJS module names to an array
110
- commonjsModules = [...commonjsModules];
111
-
112
- return new Promise(resolve => {
156
+ return new Promise(async resolve => {
113
157
  let b = browserify([], {
114
158
  builtins: builtins,
115
159
  ignoreMissing: true,
@@ -119,22 +163,17 @@ qx.Class.define("qx.tool.compiler.targets.meta.Browserify", {
119
163
 
120
164
  b._mdeps.on("missing", (id, parent) => {
121
165
  let message = [];
122
-
123
166
  message.push(`ERROR: could not locate require()d module: "${id}"`);
124
- if (references[id]) {
125
- message.push(" required from:");
126
-
127
- try {
128
- [...references[id]].forEach(refs => {
129
- refs.forEach(ref => {
130
- message.push(` ${ref}`);
131
- });
167
+ message.push(" required from:");
168
+ try {
169
+ [...references[id]].forEach(refs => {
170
+ refs.forEach(ref => {
171
+ message.push(` ${ref}`);
132
172
  });
133
- } catch (e) {
134
- message.push(` <compile.json:application.localModules'>`);
135
- }
173
+ });
174
+ } catch (e) {
175
+ message.push(` <compile.json:application.localModules'>`);
136
176
  }
137
-
138
177
  qx.tool.compiler.Console.error(message.join("\n"));
139
178
  });
140
179
 
@@ -150,7 +189,6 @@ qx.Class.define("qx.tool.compiler.targets.meta.Browserify", {
150
189
  b.require(localModules[requireName], { expose: requireName });
151
190
  }
152
191
  }
153
-
154
192
  // Ensure ES6 local modules are converted to CommonJS format
155
193
  b.transform(babelify, {
156
194
  presets: [preset],
@@ -21,7 +21,10 @@ const async = require("async");
21
21
  const { promisify } = require("util");
22
22
  const child_process = require("child_process");
23
23
  const psTree = require("ps-tree");
24
-
24
+ /**
25
+ * @ignore(process)
26
+ */
27
+ /* global process */
25
28
  /**
26
29
  * Utility methods
27
30
  */
@@ -52,7 +52,7 @@ qx.Mixin.define("qx.ui.form.MForm", {
52
52
  },
53
53
 
54
54
  /**
55
- * Message which is shown in an invalid tooltip.
55
+ * Message which will be shown in an tooltip if the widget is invalid.
56
56
  */
57
57
  invalidMessage: {
58
58
  init: null,
@@ -62,7 +62,7 @@ qx.Mixin.define("qx.ui.form.MForm", {
62
62
  },
63
63
 
64
64
  /**
65
- * Message which is shown in an invalid tooltip if the {@link #required} is
65
+ * Message which will be shown in an invalid tooltip if the {@link #required} is
66
66
  * set to true.
67
67
  */
68
68
  requiredInvalidMessage: {
@@ -71,7 +71,7 @@ qx.Class.define("qx.ui.form.validation.Manager", {
71
71
  },
72
72
 
73
73
  /**
74
- * The invalid message should store the message why the form validation
74
+ * The invalid message stores the message why the form validation
75
75
  * failed. It will be added to the array returned by
76
76
  * {@link #getInvalidMessages}.
77
77
  */
@@ -483,8 +483,13 @@ qx.Class.define("qx.ui.form.validation.Manager", {
483
483
  }
484
484
 
485
485
  let msg = item.getInvalidMessage();
486
- if (!msg && qx.core.Environment.get("qx.ui.form.validation.Manager.allowDefaultInvalidMessage")) {
487
- msg = "Invalid field";
486
+ if (
487
+ msg &&
488
+ qx.core.Environment.get(
489
+ "qx.ui.form.validation.Manager.allowDefaultInvalidMessage"
490
+ )
491
+ ) {
492
+ msg = qx.locale.Manager.tr("Invalid field");
488
493
  } else if (qx.core.Environment.get("qx.debug")) {
489
494
  this.assertTrue(msg != null && msg.length > 0);
490
495
  }
@@ -538,8 +543,13 @@ qx.Class.define("qx.ui.form.validation.Manager", {
538
543
  var formItem = this.__formItems[i].item;
539
544
  if (!formItem.getValid()) {
540
545
  let msg = formItem.getInvalidMessage();
541
- if (!msg && qx.core.Environment.get("qx.ui.form.validation.Manager.allowDefaultInvalidMessage")) {
542
- msg = "Invalid field";
546
+ if (
547
+ !msg &&
548
+ qx.core.Environment.get(
549
+ "qx.ui.form.validation.Manager.allowDefaultInvalidMessage"
550
+ )
551
+ ) {
552
+ msg = qx.locale.Manager.tr("Invalid field");
543
553
  } else if (qx.core.Environment.get("qx.debug")) {
544
554
  this.assertTrue(msg !== null && msg.length > 0);
545
555
  }
@@ -550,12 +560,9 @@ qx.Class.define("qx.ui.form.validation.Manager", {
550
560
  // add the forms fail message
551
561
  if (!this.isValid()) {
552
562
  let msg = this.getInvalidMessage();
553
- if (!msg && qx.core.Environment.get("qx.ui.form.validation.Manager.allowDefaultInvalidMessage")) {
554
- msg = "Invalid field";
555
- } else if (qx.core.Environment.get("qx.debug")) {
556
- this.assertTrue(msg !== null && msg.length > 0);
563
+ if (msg != "") {
564
+ messages.push(msg);
557
565
  }
558
- messages.push(msg);
559
566
  }
560
567
 
561
568
  return messages;
@@ -665,7 +672,7 @@ qx.Class.define("qx.ui.form.validation.Manager", {
665
672
  },
666
673
 
667
674
  environment: {
668
- // Whether to assume a default "Invalid Field" message for invalid fields; if false, an
675
+ // Whether to assume a default "Invalid Field" message for invalid fields; if false, an
669
676
  // exception will be raised if invalid fields do not have an `invalidMessage`
670
677
  "qx.ui.form.validation.Manager.allowDefaultInvalidMessage": true
671
678
  }
@@ -37,7 +37,6 @@
37
37
  *
38
38
  * @group (Core)
39
39
  *
40
- * @asset(qx/iconfont/MaterialIcons/*)
41
40
  */
42
41
  qx.Bootstrap.define("qxWeb", {
43
42
  extend: qx.type.BaseArray,
@@ -107,12 +107,6 @@ module.exports = function (argv, data) {
107
107
  return "^" + data.qooxdoo_version;
108
108
  }
109
109
  },
110
- "compiler_range": {
111
- "description": "the semver range of qooxdoo compiler versions that are compatible with this application",
112
- "default": function () {
113
- return "^" + qx.tool.config.Utils.getCompilerVersion();
114
- }
115
- },
116
110
  "theme": {
117
111
  "description": "the theme of the application",
118
112
  "default": argv.theme
@@ -47,6 +47,12 @@
47
47
  }
48
48
  }
49
49
  },
50
+ "localModules": {
51
+ "type": "object",
52
+ "additionalProperties": {
53
+ "type": "string"
54
+ }
55
+ },
50
56
  "applications": {
51
57
  "type":"array",
52
58
  "description": "Each entry describes an application to be compiled.",
@@ -174,10 +180,7 @@
174
180
  "$ref": "#/properties/parts"
175
181
  },
176
182
  "localModules": {
177
- "type": "object",
178
- "additionalProperties": {
179
- "type": "string"
180
- }
183
+ "$ref": "#/properties/localModules"
181
184
  }
182
185
  }
183
186
  }