@qooxdoo/framework 7.0.0-beta.8 → 7.1.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.
Files changed (33) hide show
  1. package/CHANGELOG.md +8 -3
  2. package/Manifest.json +2 -2
  3. package/README.md +2 -4
  4. package/lib/compiler/compile-info.json +72 -70
  5. package/lib/compiler/index.js +1907 -1639
  6. package/npm-shrinkwrap.json +950 -42
  7. package/package.json +5 -3
  8. package/source/class/qx/Class.js +0 -28
  9. package/source/class/qx/Mixin.js +6 -0
  10. package/source/class/qx/data/Array.js +1 -1
  11. package/source/class/qx/test/Mixin.js +206 -1
  12. package/source/class/qx/tool/cli/api/AbstractApi.js +4 -1
  13. package/source/class/qx/tool/cli/commands/Compile.js +1 -0
  14. package/source/class/qx/tool/cli/commands/Lint.js +19 -8
  15. package/source/class/qx/tool/compiler/ClassFile.js +73 -5
  16. package/source/class/qx/tool/compiler/TargetError.js +27 -0
  17. package/source/class/qx/tool/compiler/targets/Target.js +6 -0
  18. package/source/class/qx/tool/compiler/targets/meta/AbstractJavascriptMeta.js +1 -1
  19. package/source/class/qx/tool/compiler/targets/meta/Browserify.js +143 -0
  20. package/source/class/qx/tool/compiler/targets/meta/Uglify.js +4 -25
  21. package/source/class/qx/ui/form/AbstractSelectBox.js +4 -1
  22. package/source/class/qx/ui/form/DateField.js +4 -1
  23. package/source/class/qx/ui/progressive/renderer/table/Row.js +2 -1
  24. package/source/class/qx/ui/progressive/renderer/table/cell/Boolean.js +24 -26
  25. package/source/class/qx/ui/progressive/renderer/table/cell/Icon.js +9 -7
  26. package/source/class/qx/ui/progressive/renderer/table/cell/Image.js +16 -13
  27. package/source/class/qx/ui/table/Table.js +0 -1
  28. package/source/class/qx/ui/table/model/Abstract.js +31 -1
  29. package/source/class/qx/ui/table/model/Remote.js +1 -0
  30. package/source/class/qx/ui/table/model/Simple.js +14 -3
  31. package/source/class/qx/ui/table/pane/Pane.js +3 -1
  32. package/source/class/qx/ui/treevirtual/MNode.js +60 -5
  33. package/source/class/qx/ui/treevirtual/SimpleTreeDataModel.js +11 -3
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@qooxdoo/framework",
3
- "version": "7.0.0-beta.8",
3
+ "version": "7.1.0",
4
4
  "description": "The JS Framework for Coders",
5
5
  "author": "The qooxdoo project",
6
6
  "keywords": [
@@ -36,7 +36,7 @@
36
36
  "scripts": {
37
37
  "devtools": "node source/resource/qx/tool/bin/build-devtools",
38
38
  "website": "node source/resource/qx/tool/bin/build-website",
39
- "pretest": "node bootstrap-compiler --target build",
39
+ "pretest": "node ./bootstrap-compiler",
40
40
  "test": "node ./bin/build/qx test --colorize=false --quiet",
41
41
  "prepack": "node ./bootstrap/qx deploy --clean"
42
42
  },
@@ -57,6 +57,7 @@
57
57
  "@babel/parser": "^7.12.11",
58
58
  "@babel/plugin-proposal-nullish-coalescing-operator": "^7.12.1",
59
59
  "@babel/plugin-proposal-optional-chaining": "^7.12.7",
60
+ "@babel/plugin-syntax-jsx": "^7.16.7",
60
61
  "@babel/plugin-transform-block-scoping": "^7.12.12",
61
62
  "@babel/plugin-transform-react-jsx": "^7.12.12",
62
63
  "@babel/preset-env": "^7.12.11",
@@ -73,6 +74,7 @@
73
74
  "app-module-path": "^2.2.0",
74
75
  "async": "^2.6.3",
75
76
  "better-ajv-errors": "^1.1.1",
77
+ "browserify": "^17.0.0",
76
78
  "chokidar": "^3.5.1",
77
79
  "cldr": "^7.1.1",
78
80
  "columnify": "^1.5.4",
@@ -96,7 +98,7 @@
96
98
  "metalsmith": "^2.3.0",
97
99
  "metalsmith-layouts": "^2.3.1",
98
100
  "metalsmith-markdown": "^1.3.0",
99
- "node-fetch": "^2.6.0",
101
+ "node-fetch": "^2.6.7",
100
102
  "object-hash": "^2.1.1",
101
103
  "prettier": "^2.5.1",
102
104
  "ps-tree": "^1.2.0",
@@ -1649,34 +1649,6 @@ qx.Bootstrap.define("qx.Class", {
1649
1649
  }
1650
1650
  },
1651
1651
 
1652
- /**
1653
- * Wraps a member function of a mixin, which is included using "patch". This
1654
- * allows "base" calls in the mixin member function.
1655
- *
1656
- * @param member {Function} The mixin method to wrap
1657
- * @param base {Function} The overwritten method
1658
- * @return {Function} the wrapped mixin member
1659
- */
1660
- __mixinMemberWrapper(member, base) {
1661
- if (qx.core.Environment.get("qx.compiler")) {
1662
- throw new Error(
1663
- "This function should not be used except with code compiled by the generator (ie python toolchain)"
1664
- );
1665
- } else {
1666
- if (base) {
1667
- return function () {
1668
- var oldBase = member.base;
1669
- member.base = base;
1670
- var retval = member.apply(this, arguments);
1671
- member.base = oldBase;
1672
- return retval;
1673
- };
1674
- } else {
1675
- return member;
1676
- }
1677
- }
1678
- },
1679
-
1680
1652
  /**
1681
1653
  * Add a single interface to a class
1682
1654
  *
@@ -370,6 +370,12 @@ qx.Bootstrap.define("qx.Mixin", {
370
370
  // Try looking in the class itself
371
371
  if (!fn && mixedInAt.prototype[methodName]) {
372
372
  fn = mixedInAt.prototype[methodName].base;
373
+ // if fn.self is set fn is an overloaded mixin method from
374
+ // another mixin. In this case fn.base contains the original
375
+ // class method.
376
+ if (fn && fn.self) {
377
+ fn = fn.base;
378
+ }
373
379
  }
374
380
  // Try looking in the superclass
375
381
  if (!fn && mixedInAt.superclass) {
@@ -1017,7 +1017,7 @@ qx.Class.define("qx.data.Array", {
1017
1017
  * <li><code>index</code>: the index of the current item</li>
1018
1018
  * <li><code>array</code>: The native array instance, NOT the data array instance.</li>
1019
1019
  * @param self {var?undefined} The context of the callback.
1020
- * @return {Boolean} <code>true</code>, if any element passed the test function.
1020
+ * @return {var | undefined} The found item.
1021
1021
  */
1022
1022
  find(callback, self) {
1023
1023
  return this.__array.find(callback, self);
@@ -402,6 +402,211 @@ qx.Class.define("qx.test.Mixin", {
402
402
  this.assertTrue(objBaseIncluded instanceof qx.test.testclasses.RootClass);
403
403
  this.assertTrue(objBaseBoth instanceof qx.test.testclasses.RootClass);
404
404
  this.assertTrue(objPatched instanceof qx.test.testclasses.RootClass);
405
+ },
406
+
407
+ testPatchDouble() {
408
+
409
+ qx.Class.define("qx.Patch_1", {
410
+ extend: qx.core.Object,
411
+
412
+ members: {
413
+ sayJuhu() {
414
+ return "Juhu 1";
415
+ }
416
+ }
417
+ });
418
+
419
+ qx.Class.define("qx.Patch_2", {
420
+ extend: qx.core.Object,
421
+
422
+ members: {
423
+ sayJuhu() {
424
+ return "Juhu 2";
425
+ }
426
+ }
427
+ });
428
+
429
+
430
+ qx.Mixin.define("qx.MPatch", {
431
+ members: {
432
+ sayJuhu() {
433
+ return super.sayJuhu() + " Mixin";
434
+ },
435
+ }
436
+ });
437
+ qx.Class.patch(qx.Patch_1, qx.MPatch);
438
+ qx.Class.patch(qx.Patch_2, qx.MPatch);
439
+
440
+ var o = new qx.Patch_1();
441
+ this.assertEquals("Juhu 1 Mixin", o.sayJuhu());
442
+ o.dispose();
443
+
444
+ var o = new qx.Patch_2();
445
+ this.assertEquals("Juhu 2 Mixin", o.sayJuhu());
446
+ o.dispose();
447
+
448
+ },
449
+
450
+ testPatchOverwrittenDerived() {
451
+ qx.Class.define("qx.Patch", {
452
+ extend: qx.core.Object,
453
+ members: {
454
+ sayJuhu() {
455
+ return "Juhu";
456
+ }
457
+ }
458
+ });
459
+
460
+ qx.Class.define("qx.PatchDerived", {
461
+ extend: qx.Patch,
462
+ members: {
463
+ sayJuhu() {
464
+ return super.sayJuhu() + " Derived";
465
+ }
466
+ }
467
+ });
468
+
469
+ qx.Mixin.define("qx.MPatch", {
470
+ members: {
471
+ sayJuhu() {
472
+ return super.sayJuhu() + " Mixin";
473
+ },
474
+ }
475
+ });
476
+ qx.Class.patch(qx.PatchDerived, qx.MPatch);
477
+
478
+ var o = new qx.PatchDerived();
479
+ this.assertEquals("Juhu Derived Mixin", o.sayJuhu());
480
+ o.dispose();
481
+ },
482
+
483
+ testPatchOverwrittenDerivedInBaseClass() {
484
+
485
+ qx.Mixin.define("qx.MPatch", {
486
+ members: {
487
+ sayJuhu() {
488
+ return super.sayJuhu() + " Mixin";
489
+ },
490
+ }
491
+ });
492
+
493
+ qx.Class.define("qx.Patch", {
494
+ extend: qx.core.Object,
495
+ members: {
496
+ sayJuhu() {
497
+ return "Juhu";
498
+ }
499
+ }
500
+ });
501
+
502
+ qx.Class.define("qx.PatchDerived", {
503
+ extend: qx.Patch,
504
+ members: {
505
+ sayJuhu() {
506
+ return super.sayJuhu() + " Derived";
507
+ }
508
+ }
509
+ });
510
+
511
+ qx.Class.patch(qx.Patch, qx.MPatch);
512
+
513
+ var o = new qx.Patch();
514
+ this.assertEquals("Juhu Mixin", o.sayJuhu());
515
+ o.dispose();
516
+
517
+ var o = new qx.PatchDerived();
518
+ this.assertEquals("Juhu Mixin Derived", o.sayJuhu());
519
+ o.dispose();
520
+
521
+ },
522
+
523
+ testPatchMultiOverwrittenDerived() {
524
+ qx.Class.define("qx.A", {
525
+ extend: qx.core.Object,
526
+ members: {
527
+ sayJuhu() {
528
+ return "A";
529
+ }
530
+ }
531
+ });
532
+ qx.Class.define("qx.B", {
533
+ extend: qx.A,
534
+ members: {
535
+ sayJuhu() {
536
+ return super() + " B";
537
+ }
538
+ }
539
+ });
540
+ qx.Class.define("qx.C", {
541
+ extend: qx.B,
542
+ members: {
543
+ sayJuhu() {
544
+ return super() + " C";
545
+ }
546
+ }
547
+ });
548
+ qx.Mixin.define("qx.MA", {
549
+ members: {
550
+ sayJuhu() {
551
+ return super.sayJuhu() + " MA";
552
+ },
553
+ }
554
+ });
555
+ qx.Mixin.define("qx.MB", {
556
+ members: {
557
+ sayJuhu() {
558
+ return super.sayJuhu() + " MB";
559
+ },
560
+ }
561
+ });
562
+ qx.Mixin.define("qx.MC", {
563
+ members: {
564
+ sayJuhu() {
565
+ return super.sayJuhu() + " MC";
566
+ },
567
+ }
568
+ });
569
+ qx.Class.patch(qx.A, qx.MA);
570
+ qx.Class.patch(qx.B, qx.MB);
571
+ qx.Class.patch(qx.C, qx.MC);
572
+
573
+ var o = new qx.C();
574
+ this.assertEquals("A MA B MB C MC", o.sayJuhu());
575
+ o.dispose();
576
+
577
+ },
578
+
579
+ testDoubleMixin() {
580
+ qx.Class.define("qx.D", {
581
+ extend: qx.core.Object,
582
+ members: {
583
+ sayJuhu() {
584
+ return "Double";
585
+ }
586
+ }
587
+ });
588
+ qx.Mixin.define("qx.MDA", {
589
+ members: {
590
+ sayJuhu() {
591
+ return super.sayJuhu() + " MA";
592
+ },
593
+ }
594
+ });
595
+ qx.Mixin.define("qx.MDB", {
596
+ members: {
597
+ sayJuhu() {
598
+ return super.sayJuhu() + " MB";
599
+ },
600
+ }
601
+ });
602
+ qx.Class.patch(qx.D, qx.MDA);
603
+ qx.Class.patch(qx.D, qx.MDB);
604
+
605
+ var o = new qx.D();
606
+ this.assertEquals("Double MA MB", o.sayJuhu());
607
+ o.dispose();
608
+
405
609
  }
406
- }
610
+
611
+ }
407
612
  });
@@ -86,7 +86,10 @@ qx.Class.define("qx.tool.cli.api.AbstractApi", {
86
86
  */
87
87
  loadNpmModule(module) {
88
88
  const { execSync } = require("child_process");
89
- let s = `npm install --no-save --no-package-lock ${module}`;
89
+ // since npm 7 --no-save deletes the node_modules folder
90
+ // see https://github.com/npm/cli/pull/3907
91
+ // let s = `npm install --no-save --no-package-lock ${module}`;
92
+ let s = `npm install --no-package-lock ${module}`;
90
93
  qx.tool.compiler.Console.info(s);
91
94
  execSync(s, {
92
95
  stdio: "inherit"
@@ -915,6 +915,7 @@ Framework: v${await this.getQxVersion()} in ${await this.getQxPath()}`);
915
915
  */
916
916
  let targetOutputPaths = {};
917
917
  let makers = [];
918
+
918
919
  targetConfigs.forEach(targetConfig => {
919
920
  if (!targetConfig.appConfigs) {
920
921
  qx.tool.compiler.Console.print(
@@ -112,13 +112,14 @@ qx.Class.define("qx.tool.cli.commands.Lint", {
112
112
  lintOptions.globals || {},
113
113
  await this.__addGlobals(config)
114
114
  );
115
-
116
115
  lintOptions.parser = "@babel/eslint-parser";
117
116
  lintOptions.parserOptions = lintOptions.parserOptions || {};
118
117
  lintOptions.parserOptions.requireConfigFile = false;
119
118
  lintOptions.parserOptions.babelOptions = {
120
- plugins: ["@babel/plugin-syntax-jsx"],
121
-
119
+ cwd: helperFilePath,
120
+ plugins: [
121
+ "@babel/plugin-syntax-jsx"
122
+ ],
122
123
  parserOpts: {
123
124
  allowSuperOutsideMethod: true
124
125
  }
@@ -156,13 +157,23 @@ qx.Class.define("qx.tool.cli.commands.Lint", {
156
157
  }
157
158
  if (report.errorCount > 0 || report.warningCount > 0) {
158
159
  let outputFormat = this.argv.format || "codeframe";
159
-
160
- // If there are too many errors, the pretty formatter is appallingly slow
161
- if (report.errorCount + report.warningCount > 150) {
162
- outputFormat = "compact";
163
- }
164
160
  const formatter = await linter.loadFormatter(outputFormat);
165
161
  const s = formatter.format(report);
162
+ // If there are too many errors, the pretty formatter is appallingly slow so if the
163
+ // user has not specified a format, change to compact mode
164
+ const maxDefaultFormatErrorCount = 150;
165
+ if (report.errorCount + report.warningCount > maxDefaultFormatErrorCount) {
166
+ if (!this.argv.format) {
167
+ qx.tool.compiler.Console.info(
168
+ `Total errors and warnings exceed ${maxDefaultFormatErrorCount}, switching to "compact" style report`
169
+ );
170
+ outputFormat = "compact";
171
+ } else {
172
+ qx.tool.compiler.Console.info(
173
+ `Total errors and warnings exceed ${maxDefaultFormatErrorCount}, the report may take some time to generate.`
174
+ );
175
+ }
176
+ }
166
177
  if (this.argv.outputFile) {
167
178
  if (this.argv.verbose) {
168
179
  qx.tool.compiler.Console.info(
@@ -223,6 +223,7 @@ qx.Class.define("qx.tool.compiler.ClassFile", {
223
223
  };
224
224
 
225
225
  this.__externals = [];
226
+ this.__commonjsModules = {};
226
227
 
227
228
  this.__taskQueueDrains = [];
228
229
  this.__taskQueue = async.queue(function (task, cb) {
@@ -281,6 +282,7 @@ qx.Class.define("qx.tool.compiler.ClassFile", {
281
282
  __privates: null,
282
283
  __blockedPrivates: null,
283
284
  __externals: null,
285
+ __commonjsModules: null,
284
286
 
285
287
  _onTaskQueueDrain() {
286
288
  var cbs = this.__taskQueueDrain;
@@ -496,6 +498,7 @@ qx.Class.define("qx.tool.compiler.ClassFile", {
496
498
  delete dbClassInfo.translations;
497
499
  delete dbClassInfo.markers;
498
500
  delete dbClassInfo.fatalCompileError;
501
+ delete dbClassInfo.commonjsModules;
499
502
  for (var key in this.__dbClassInfo) {
500
503
  dbClassInfo[key] = this.__dbClassInfo[key];
501
504
  }
@@ -667,6 +670,14 @@ qx.Class.define("qx.tool.compiler.ClassFile", {
667
670
  dbClassInfo.fatalCompileError = true;
668
671
  }
669
672
 
673
+ // CommonJS modules
674
+ if (Object.keys(this.__commonjsModules).length > 0) {
675
+ dbClassInfo.commonjsModules = {};
676
+ for (let moduleName in this.__commonjsModules) {
677
+ dbClassInfo.commonjsModules[moduleName] = [ ...this.__commonjsModules[moduleName] ];
678
+ }
679
+ }
680
+
670
681
  return dbClassInfo;
671
682
  },
672
683
 
@@ -1648,6 +1659,52 @@ qx.Class.define("qx.tool.compiler.ClassFile", {
1648
1659
  }
1649
1660
  }
1650
1661
 
1662
+ // Are we looking at the Identifier `require`, and is it a
1663
+ // function call (identified by having
1664
+ // `path.node.arguments`? If so, we'll add the discovered
1665
+ // module to the list of modules that must be browserified
1666
+ // if the application is destined for the browser.
1667
+ let scope;
1668
+ let applicationTypes = t.__analyser.getApplicationTypes();
1669
+
1670
+ if (path.node.callee.type == "Identifier" &&
1671
+ path.node?.callee?.name == "require" &&
1672
+ path.node.arguments?.length == 1 &&
1673
+ applicationTypes.includes("browser")) {
1674
+
1675
+ // See if this is a reference to global `require` or
1676
+ // something in the scope chain
1677
+ for (scope = t.__scope; scope; scope = scope.parent) {
1678
+ if (scope.vars["require"]) {
1679
+ // It's in the scope chain. Ignore it.
1680
+ break;
1681
+ }
1682
+ }
1683
+ // Did we reach top level without finding it in a local scope?
1684
+ if (! scope) {
1685
+ // Yup. It's the global one we're looking for. Ensure the argument is valid.
1686
+ let arg = path.node.arguments[0];
1687
+ if (types.isLiteral(arg)) {
1688
+ if (typeof arg.value != "string") {
1689
+ log.error(
1690
+ `${t.__className}: ` +
1691
+ "Only literal string arguments to require() are supported: " +
1692
+ arg.value
1693
+ );
1694
+ } else {
1695
+ qx.tool.compiler.Console.log(
1696
+ `${t.__className}:${path.node.loc.start.line}:` +
1697
+ ` automatically detected \'require(${arg.value})\``);
1698
+ t.addCommonjsModule(arg.value, t.__className, path.node.loc.start.line);
1699
+
1700
+ // Don't show "unresolved" error for `require` since the
1701
+ // browserified code defines it as a global
1702
+ t.addIgnore("require");
1703
+ }
1704
+ }
1705
+ }
1706
+ }
1707
+
1651
1708
  if (
1652
1709
  types.isMemberExpression(path.node.callee) ||
1653
1710
  (es6ClassDeclarations == 0 &&
@@ -1828,10 +1885,7 @@ qx.Class.define("qx.tool.compiler.ClassFile", {
1828
1885
  types.stringLiteral(t.__classMeta.functionName)
1829
1886
  ]
1830
1887
  );
1831
-
1832
1888
  expr = types.memberExpression(expr, types.identifier("call"));
1833
- //expr = expandMemberExpression("qx.Mixin.baseClassMethod(this.constructor, " + t.__classMeta.className + ", \"" + t.__classMeta.functionName + "\").call");
1834
- //expr = expandMemberExpression(t.__classMeta.className + ".$$members." + t.__classMeta.functionName + ".base.call");
1835
1889
  } else if (t.__classMeta.functionName == "$$constructor") {
1836
1890
  expr = expandMemberExpression(
1837
1891
  t.__classMeta.superClass + ".constructor.call"
@@ -1839,9 +1893,10 @@ qx.Class.define("qx.tool.compiler.ClassFile", {
1839
1893
  } else if (t.__classMeta.className) {
1840
1894
  expr = expandMemberExpression(
1841
1895
  t.__classMeta.className +
1842
- ".prototype." +
1896
+ ".superclass" +
1897
+ ".prototype." +
1843
1898
  t.__classMeta.functionName +
1844
- ".base.call"
1899
+ ".call"
1845
1900
  );
1846
1901
  } else {
1847
1902
  expr = expandMemberExpression(
@@ -2508,6 +2563,19 @@ qx.Class.define("qx.tool.compiler.ClassFile", {
2508
2563
  }
2509
2564
  },
2510
2565
 
2566
+ /**
2567
+ * Adds a CommonJS module to be browserified
2568
+ *
2569
+ * @param name {String} name of the module
2570
+ */
2571
+ addCommonjsModule(moduleName, className, linenum) {
2572
+ if (! this.__commonjsModules[moduleName]) {
2573
+ this.__commonjsModules[moduleName] = new Set();
2574
+ }
2575
+
2576
+ this.__commonjsModules[moduleName].add(`${className}:${linenum}`);
2577
+ },
2578
+
2511
2579
  /**
2512
2580
  * Adds an ignored symbol
2513
2581
  * @param name {String} name of the symbol
@@ -0,0 +1,27 @@
1
+ /* ************************************************************************
2
+ *
3
+ * qooxdoo-compiler - node.js based replacement for the Qooxdoo python
4
+ * toolchain
5
+ *
6
+ * https://github.com/qooxdoo/qooxdoo-compiler
7
+ *
8
+ * Copyright:
9
+ * 3033 Derrell Lipman
10
+ *
11
+ * License:
12
+ * MIT: https://opensource.org/licenses/MIT
13
+ *
14
+ * This software is provided under the same licensing terms as Qooxdoo,
15
+ * please see the LICENSE file in the Qooxdoo project's top-level directory
16
+ * for details.
17
+ *
18
+ * Authors:
19
+ * * Derrell Lipman (@derrell)
20
+ *
21
+ * ************************************************************************/
22
+
23
+ qx.Class.define("qx.tool.compiler.TargetError",
24
+ {
25
+ // extend : qx.type.BaseError
26
+ extend : Error
27
+ });
@@ -432,6 +432,12 @@ qx.Class.define("qx.tool.compiler.targets.Target", {
432
432
  new qx.tool.compiler.targets.meta.PolyfillJs(appMeta)
433
433
  );
434
434
 
435
+ // Add browserified CommonJS modules, if any
436
+ if (appMeta.getEnvironmentValue("qx.compiler.applicationType") == "browser") {
437
+ bootPackage.addJavascriptMeta(
438
+ new qx.tool.compiler.targets.meta.Browserify(appMeta));
439
+ }
440
+
435
441
  /*
436
442
  * Assemble the Parts
437
443
  */
@@ -26,7 +26,7 @@ const sourceMap = require("source-map");
26
26
 
27
27
  /**
28
28
  * An AbstractJavascriptMeta provides an abstraction of some source code, and might be
29
- * compromised of a number of input files which are merged together as required.
29
+ * comprised of a number of input files which are merged together as required.
30
30
  *
31
31
  * This object could represent a file which already exists on disk (eg a transpiled
32
32
  * source file), or something that is generated on the fly (such as a index.js), or