nesoi 3.0.13 → 3.0.14

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 (44) hide show
  1. package/lib/compiler/apps/monolyth/stages/2_build_typescript_stage.js +5 -2
  2. package/lib/compiler/apps/monolyth/stages/3_copy_types_stage.js +2 -2
  3. package/lib/compiler/apps/monolyth/stages/4_dump_modules_stage.js +2 -2
  4. package/lib/compiler/apps/monolyth/stages/7_dump_package_json_stage.js +4 -1
  5. package/lib/compiler/compiler.d.ts +2 -0
  6. package/lib/compiler/compiler.js +10 -38
  7. package/lib/compiler/elements/cached.element.d.ts +11 -0
  8. package/lib/compiler/elements/cached.element.js +18 -0
  9. package/lib/compiler/elements/element.d.ts +3 -1
  10. package/lib/compiler/elements/element.js +3 -1
  11. package/lib/compiler/elements/externals.element.d.ts +1 -1
  12. package/lib/compiler/elements/externals.element.js +2 -35
  13. package/lib/compiler/module.d.ts +3 -2
  14. package/lib/compiler/module.js +9 -2
  15. package/lib/compiler/progressive.d.ts +71 -0
  16. package/lib/compiler/progressive.js +164 -0
  17. package/lib/compiler/stages/1_scan_stage.js +5 -2
  18. package/lib/compiler/stages/2_treeshake_stage.js +7 -1
  19. package/lib/compiler/stages/3_extract_ts_stage.js +9 -0
  20. package/lib/compiler/stages/4_build_schemas_stage.js +10 -1
  21. package/lib/compiler/stages/5_inject_ts_stage.js +3 -0
  22. package/lib/compiler/stages/6_build_elements_stage.js +3 -0
  23. package/lib/compiler/stages/7_dump_stage.d.ts +4 -1
  24. package/lib/compiler/stages/7_dump_stage.js +108 -44
  25. package/lib/compiler/stages/8_diagnose_stage.js +3 -0
  26. package/lib/compiler/treeshake.d.ts +5 -2
  27. package/lib/compiler/treeshake.js +41 -8
  28. package/lib/compiler/typescript/bridge/inject.js +2 -0
  29. package/lib/compiler/typescript/transformers/app_inject.transformer.js +1 -1
  30. package/lib/engine/apps/app.js +2 -2
  31. package/lib/engine/data/trash.d.ts +1 -1
  32. package/lib/engine/data/trash.js +2 -2
  33. package/lib/engine/dependency.d.ts +6 -0
  34. package/lib/engine/dependency.js +1 -0
  35. package/lib/engine/module.d.ts +2 -1
  36. package/lib/engine/module.js +2 -1
  37. package/lib/engine/space.d.ts +1 -1
  38. package/lib/engine/space.js +14 -5
  39. package/lib/engine/tree.d.ts +8 -1
  40. package/lib/engine/tree.js +45 -25
  41. package/lib/engine/util/hash.d.ts +2 -1
  42. package/lib/engine/util/hash.js +10 -1
  43. package/package.json +1 -1
  44. package/tsconfig.build.tsbuildinfo +1 -1
@@ -15,14 +15,23 @@ class BuildSchemasStage {
15
15
  }
16
16
  async run() {
17
17
  log_1.Log.info('compiler', 'stage.build_schemas', 'Building schemas...');
18
+ const t0 = new Date().getTime();
18
19
  await this.compiler.tree.traverse('Building schemas ', async (node) => {
20
+ const module = this.compiler.modules[node.module].module;
21
+ if (node.progressive) {
22
+ await module.inject({
23
+ [node.progressive.schema.$t + 's']: [node.progressive.schema]
24
+ });
25
+ return;
26
+ }
19
27
  // Inline nodes are built by their root builder
20
28
  if (node.isInline) {
21
29
  return;
22
30
  }
23
- const module = this.compiler.modules[node.module].module;
24
31
  await module.buildNode(node, this.compiler.tree);
25
32
  });
33
+ const t = new Date().getTime();
34
+ log_1.Log.debug('compiler', 'stage.build_schemas', `[t: ${(t - t0) / 1000} ms]`);
26
35
  }
27
36
  }
28
37
  exports.BuildSchemasStage = BuildSchemasStage;
@@ -16,9 +16,12 @@ class InjectTSStage {
16
16
  }
17
17
  run() {
18
18
  log_1.Log.info('compiler', 'stage.inject_ts', 'Injecting TypeScript code to schemas...');
19
+ const t0 = new Date().getTime();
19
20
  const { tree } = this.compiler;
20
21
  const nodes = tree.allNodes();
21
22
  inject_1.TSBridgeInject.inject(this.compiler, nodes);
23
+ const t = new Date().getTime();
24
+ log_1.Log.debug('compiler', 'stage.inject_ts', `[t: ${(t - t0) / 1000} ms]`);
22
25
  log_1.Log.trace('compiler', 'stage.inject_ts', 'Finished injecting TS code');
23
26
  }
24
27
  }
@@ -16,10 +16,13 @@ class BuildElementsStage {
16
16
  }
17
17
  async run() {
18
18
  log_1.Log.info('compiler', 'stage.build_elements', 'Building Elements...');
19
+ const t0 = new Date().getTime();
19
20
  await this.compiler.tree.traverse('Building elements ', async (node) => {
20
21
  const module = this.compiler.modules[node.module];
21
22
  await module.buildElementNode(node);
22
23
  });
24
+ const t = new Date().getTime();
25
+ log_1.Log.debug('compiler', 'stage.build_elements', `[t: ${(t - t0) / 1000} ms]`);
23
26
  }
24
27
  }
25
28
  exports.BuildElementsStage = BuildElementsStage;
@@ -8,10 +8,13 @@ import { Compiler } from '../compiler';
8
8
  */
9
9
  export declare class DumpStage {
10
10
  compiler: Compiler;
11
+ private cache;
12
+ private hash;
11
13
  constructor(compiler: Compiler);
12
- run(): void;
14
+ run(): Promise<void>;
13
15
  private dumpSpace;
14
16
  private dumpModule;
15
17
  private dumpModuleSchemas;
16
18
  private dumpModuleType;
19
+ private makeModuleType;
17
20
  }
@@ -45,6 +45,7 @@ const dependency_1 = require("../../engine/dependency");
45
45
  const bucket_element_1 = require("../elements/bucket.element");
46
46
  const dump_helpers_1 = require("../helpers/dump_helpers");
47
47
  const space_1 = require("../../engine/space");
48
+ const progressive_1 = require("../progressive");
48
49
  /**
49
50
  * [Compiler Stage #7]
50
51
  * Dump the element schemas and types to the .nesoi folder.
@@ -56,12 +57,27 @@ class DumpStage {
56
57
  constructor(compiler) {
57
58
  this.compiler = compiler;
58
59
  }
59
- run() {
60
+ async run() {
60
61
  log_1.Log.info('compiler', 'stage.dump', 'Dumping Schemas and Types...');
61
- const spaceType = this.dumpSpace();
62
+ const t0 = new Date().getTime();
63
+ this.cache = await progressive_1.ProgressiveBuild.cache(this.compiler);
64
+ this.hash = await progressive_1.ProgressiveBuild.hash(this.compiler);
65
+ let spaceType;
66
+ if (this.hash.$ !== this.cache.hash.$) {
67
+ spaceType = this.dumpSpace();
68
+ this.cache.types.space = spaceType;
69
+ }
70
+ else {
71
+ spaceType = this.cache.types.space;
72
+ }
62
73
  Object.values(this.compiler.modules).forEach(module => {
63
- this.dumpModule(module, spaceType);
74
+ if (this.hash.modules[module.lowName]?.$ !== this.cache.hash.modules[module.lowName]?.$) {
75
+ this.dumpModule(module, spaceType);
76
+ }
64
77
  });
78
+ await progressive_1.ProgressiveBuild.save(this.compiler.space, this.cache, this.hash);
79
+ const t = new Date().getTime();
80
+ log_1.Log.debug('compiler', 'stage.dump', `[t: ${(t - t0) / 1000} ms]`);
65
81
  }
66
82
  /* Space */
67
83
  dumpSpace() {
@@ -74,7 +90,7 @@ class DumpStage {
74
90
  Object.entries(_authn).forEach(([name, model]) => {
75
91
  type.authnUsers[name] = bucket_element_1.BucketElement.buildModelTypeFromSchema(model);
76
92
  });
77
- // Module types
93
+ // Module imports
78
94
  let dump = '';
79
95
  dump += `import { $Space } from '${this.compiler.config?.nesoiPath ?? 'nesoi'}/lib/schema';\n`;
80
96
  Object.values(this.compiler.modules).forEach(module => {
@@ -105,12 +121,18 @@ class DumpStage {
105
121
  dumpModuleSchemas(module, dumpDir) {
106
122
  const nesoiPath = this.compiler.config?.nesoiPath ?? 'nesoi';
107
123
  module.elements.forEach((element) => {
108
- const filename = path_1.default.basename(element.filepath());
109
- const elPath = path_1.default.resolve(dumpDir, filename);
110
- fs.writeFileSync(elPath, element.dumpFileSchema(nesoiPath));
124
+ if (element.schema.$t === 'constants'
125
+ || element.schema.$t === 'externals'
126
+ || (this.hash.modules[element.schema.module].nodes[element.tag]
127
+ !== this.cache.hash.modules[element.schema.module]?.nodes[element.tag])) {
128
+ const filename = path_1.default.basename(element.filepath());
129
+ const elPath = path_1.default.resolve(dumpDir, filename);
130
+ fs.writeFileSync(elPath, element.dumpFileSchema(nesoiPath));
131
+ }
111
132
  });
112
133
  }
113
134
  dumpModuleType(module, spaceType, dumpDir) {
135
+ var _a, _b;
114
136
  const nesoiPath = this.compiler.config?.nesoiPath ?? 'nesoi';
115
137
  const moduleFile = [];
116
138
  moduleFile.push(`import { $Module, $Constants, $Bucket, $Message, $Job, $Resource, $Machine, $Controller, $Queue } from '${nesoiPath}/lib/elements';`);
@@ -118,6 +140,71 @@ class DumpStage {
118
140
  moduleFile.push(`import { NesoiDatetime } from '${nesoiPath}/lib/engine/data/datetime';`);
119
141
  moduleFile.push(`import { NesoiDecimal } from '${nesoiPath}/lib/engine/data/decimal';`);
120
142
  moduleFile.push(`import { NesoiFile } from '${nesoiPath}/lib/engine/data/file';`);
143
+ // Get external modules
144
+ const moduleDependencies = new Set();
145
+ // Pre-populate from cache
146
+ if (this.cache) {
147
+ this.cache.modules[module.lowName]?.dependencies.modules.forEach(module => {
148
+ if (module in this.compiler.modules) {
149
+ moduleDependencies.add(module);
150
+ }
151
+ });
152
+ }
153
+ // Extract from updated elements
154
+ const externalElement = module.elements
155
+ .find(el => el.$t === 'externals');
156
+ if (externalElement) {
157
+ for (const module of externalElement.getModuleDependencies()) {
158
+ moduleDependencies.add(module);
159
+ }
160
+ }
161
+ // Dump external imports
162
+ moduleFile.push(...Array.from(moduleDependencies)
163
+ .map(module => `import ${name_helpers_1.NameHelpers.nameLowToHigh(module)}Module from './${module}.module'`));
164
+ (_a = this.cache.modules)[_b = module.lowName] ?? (_a[_b] = {
165
+ dependencies: {
166
+ modules: []
167
+ }
168
+ });
169
+ this.cache.modules[module.lowName].dependencies.modules = Array.from(moduleDependencies);
170
+ // Build module type (with all elements)
171
+ const type = this.makeModuleType(module);
172
+ this.cache.types.modules[module.lowName] = type;
173
+ // Dump module type
174
+ moduleFile.push('');
175
+ moduleFile.push('/**');
176
+ moduleFile.push(` * ${module.typeName}`);
177
+ moduleFile.push(' */');
178
+ moduleFile.push('');
179
+ let moduleDump = `export default interface ${module.typeName} extends $Module `;
180
+ moduleDump += dump_helpers_1.DumpHelpers.dumpType({
181
+ // Constants should be unknown by default, since enum types
182
+ // are validated across modules. The default type causes
183
+ // the enum alias to be keyof ... & Record<string, ...>, which
184
+ // invalidated the type assertion
185
+ constants: 'Omit<$Constants, \'values\'|\'enums\'> & { values: {}, enums: {} }',
186
+ ...type
187
+ });
188
+ moduleFile.push(moduleDump);
189
+ moduleFile.push('');
190
+ moduleFile.push('/* */');
191
+ moduleFile.push('');
192
+ // Dump authentication users
193
+ moduleFile.push(`type AuthnUsers = ${dump_helpers_1.DumpHelpers.dumpType(spaceType.authnUsers)}`);
194
+ // Dump other elements
195
+ module.elements
196
+ .filter(el => el.$t !== 'externals')
197
+ .forEach((element) => {
198
+ const type = element.dumpTypeSchema(this.cache);
199
+ this.cache.types.elements[element.tag] = type;
200
+ moduleFile.push(this.cache.types.elements[element.tag]);
201
+ });
202
+ // Write to file
203
+ const moduleFilename = `../${module.lowName}.module`;
204
+ const moduleFilepath = path_1.default.resolve(dumpDir, moduleFilename + '.ts');
205
+ fs.writeFileSync(moduleFilepath, moduleFile.join('\n'));
206
+ }
207
+ makeModuleType(module) {
121
208
  // Build module type (with all blocks)
122
209
  const type = {
123
210
  name: `'${module.lowName}'`,
@@ -131,6 +218,19 @@ class DumpStage {
131
218
  queues: {},
132
219
  controllers: {},
133
220
  };
221
+ // Merge types that currently exist and are found on cache
222
+ const typeCache = this.cache.types.modules[module.lowName];
223
+ if (typeCache) {
224
+ type.externals = typeCache.externals || 'any';
225
+ type.constants = typeCache.constants || 'any';
226
+ for (const eltype of ['buckets', 'messages', 'jobs', 'resources', 'machines', 'queues', 'controllers']) {
227
+ for (const name in typeCache[eltype] || {}) {
228
+ if (name in module.module.schema[eltype]) {
229
+ type[eltype][name] = typeCache[eltype][name];
230
+ }
231
+ }
232
+ }
233
+ }
134
234
  const externals = module.elements.find(el => el.$t === 'externals');
135
235
  // Inject external node types on module
136
236
  if (externals) {
@@ -171,43 +271,7 @@ class DumpStage {
171
271
  .filter(el => el.$t === 'message')
172
272
  .map(el => el.typeName));
173
273
  type['#authn'] = 'AuthnUsers';
174
- // Dump external elements (imports)
175
- module.elements
176
- .filter(el => el.$t === 'externals')
177
- .forEach((element) => {
178
- moduleFile.push(element.dumpTypeSchema());
179
- });
180
- // Dump module type
181
- moduleFile.push('');
182
- moduleFile.push('/**');
183
- moduleFile.push(` * ${module.typeName}`);
184
- moduleFile.push(' */');
185
- moduleFile.push('');
186
- let moduleDump = `export default interface ${module.typeName} extends $Module `;
187
- moduleDump += dump_helpers_1.DumpHelpers.dumpType({
188
- // Constants should be unknown by default, since enum types
189
- // are validated across modules. The default type causes
190
- // the enum alias to be keyof ... & Record<string, ...>, which
191
- // invalidated the type assertion
192
- constants: 'Omit<$Constants, \'values\'|\'enums\'> & { values: {}, enums: {} }',
193
- ...type
194
- });
195
- moduleFile.push(moduleDump);
196
- moduleFile.push('');
197
- moduleFile.push('/* */');
198
- moduleFile.push('');
199
- // Dump authentication users
200
- moduleFile.push(`type AuthnUsers = ${dump_helpers_1.DumpHelpers.dumpType(spaceType.authnUsers)}`);
201
- // Dump other elements
202
- module.elements
203
- .filter(el => el.$t !== 'externals')
204
- .forEach((element) => {
205
- moduleFile.push(element.dumpTypeSchema());
206
- });
207
- // Write to file
208
- const moduleFilename = `../${module.lowName}.module`;
209
- const moduleFilepath = path_1.default.resolve(dumpDir, moduleFilename + '.ts');
210
- fs.writeFileSync(moduleFilepath, moduleFile.join('\n'));
274
+ return type;
211
275
  }
212
276
  }
213
277
  exports.DumpStage = DumpStage;
@@ -21,6 +21,7 @@ class DiagnoseStage {
21
21
  }
22
22
  async run() {
23
23
  log_1.Log.info('compiler', 'stage.diagnose', 'Diagnosing space files with TypeScript...');
24
+ const t0 = new Date().getTime();
24
25
  const { tsCompiler, tree } = this.compiler;
25
26
  // Recreate TS program, to load new version of types
26
27
  tsCompiler.createProgram();
@@ -41,6 +42,8 @@ class DiagnoseStage {
41
42
  filepaths.forEach(filepath => {
42
43
  tsCompiler.check(filepath);
43
44
  });
45
+ const t = new Date().getTime();
46
+ log_1.Log.debug('compiler', 'stage.diagnose', `[t: ${(t - t0) / 1000} ms]`);
44
47
  }
45
48
  }
46
49
  exports.DiagnoseStage = DiagnoseStage;
@@ -2,6 +2,7 @@ import { $Dependency, BuilderNode } from "../engine/dependency";
2
2
  import { BucketGraphBuilder } from "../elements/entities/bucket/graph/bucket_graph.builder";
3
3
  import { AnyModule } from "../engine/module";
4
4
  import { $BucketModelFields } from "../elements/entities/bucket/model/bucket_model.schema";
5
+ import { ProgressiveBuildCache } from './progressive';
5
6
  export type TreeshakeConfig = {
6
7
  exclude?: string[];
7
8
  };
@@ -28,14 +29,16 @@ export declare class Treeshake {
28
29
  inlines: BuilderNode[];
29
30
  };
30
31
  static controller(node: BuilderNode): void;
31
- static queue(node: BuilderNode): void;
32
+ static queue(node: BuilderNode): {
33
+ inlines: BuilderNode[];
34
+ };
32
35
  /**
33
36
  * Scans the module directory, imports the builders and lists
34
37
  * all nodes found.
35
38
  *
36
39
  * @returns A list of all `BuilderNodes` found on the module folder
37
40
  */
38
- static module(module: AnyModule, config?: TreeshakeConfig): Promise<BuilderNode[]>;
41
+ static module(module: AnyModule, cache: ProgressiveBuildCache, config?: TreeshakeConfig): Promise<BuilderNode[]>;
39
42
  /**
40
43
  * Shakes a file to find all the builders declared on that file, and returns
41
44
  * them as BuilderNodes:
@@ -1,4 +1,7 @@
1
1
  "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
2
5
  Object.defineProperty(exports, "__esModule", { value: true });
3
6
  exports.Treeshake = void 0;
4
7
  const dependency_1 = require("../engine/dependency");
@@ -8,6 +11,8 @@ const log_1 = require("../engine/util/log");
8
11
  const string_1 = require("../engine/util/string");
9
12
  const error_1 = require("../engine/data/error");
10
13
  const constants_builder_1 = require("../elements/entities/constants/constants.builder");
14
+ const progressive_1 = require("./progressive");
15
+ const path_1 = __importDefault(require("path"));
11
16
  class Treeshake {
12
17
  /* Externals */
13
18
  static externals(node, depth = 1) {
@@ -191,8 +196,15 @@ class Treeshake {
191
196
  node.dependencies = [];
192
197
  }
193
198
  static queue(node) {
194
- const b = node.builder;
195
- node.dependencies = [];
199
+ const builder = node.builder;
200
+ log_1.Log.trace('compiler', 'treeshake', `└ Treeshaking node ${(0, log_1.scopeTag)(builder.$b, node.name)}`);
201
+ const inlineTreeshake = Treeshake.blockInlineNodes(node);
202
+ node.dependencies = [
203
+ ...Treeshake.blockIO(node),
204
+ ...inlineTreeshake.dependencies
205
+ ];
206
+ node.dependencies = this.cleanNodeDependencies(node);
207
+ return { inlines: inlineTreeshake.inlines };
196
208
  }
197
209
  /* Module */
198
210
  /**
@@ -201,7 +213,7 @@ class Treeshake {
201
213
  *
202
214
  * @returns A list of all `BuilderNodes` found on the module folder
203
215
  */
204
- static async module(module, config) {
216
+ static async module(module, cache, config) {
205
217
  log_1.Log.debug('compiler', 'treeshake', `Treeshaking ${(0, log_1.scopeTag)('module', module.name)}`);
206
218
  const nodes = [];
207
219
  const merge = (node) => {
@@ -230,7 +242,7 @@ class Treeshake {
230
242
  if (module.boot && 'dirpath' in module.boot) {
231
243
  const files = module.scanFiles(module.boot.dirpath, config?.exclude);
232
244
  for (const file of files) {
233
- const fileNodes = await Treeshake.file(module.name, file);
245
+ const fileNodes = await Treeshake.file(module.name, file, cache);
234
246
  fileNodes.forEach(merge);
235
247
  }
236
248
  }
@@ -254,7 +266,13 @@ class Treeshake {
254
266
  * - Inline builders
255
267
  * - Nested inline builders
256
268
  */
257
- static async file(module, filepath) {
269
+ static async file(module, filepath, cache) {
270
+ if (cache && filepath in cache.files) {
271
+ const nodes = await progressive_1.ProgressiveBuild.treeshake(cache, filepath);
272
+ if (nodes) {
273
+ return nodes;
274
+ }
275
+ }
258
276
  log_1.Log.debug('compiler', 'treeshake', ` └ Treeshaking file ${(0, string_1.colored)(filepath, 'blue')}`);
259
277
  // Require is used here to avoid cache - which allows watch mode
260
278
  delete require.cache[filepath];
@@ -272,6 +290,10 @@ class Treeshake {
272
290
  nodes.push(...Treeshake.builder(module, builder, filepath));
273
291
  }
274
292
  log_1.Log.debug('compiler', 'treeshake', ` - Nodes: ${(0, string_1.colored)(nodes.map(node => node.tag).join(', '), 'purple')}`);
293
+ cache.files[filepath] = {
294
+ type: nodes.map(node => node.type),
295
+ elements: nodes.map(node => path_1.default.join(cache.nesoidir, module, `${node.type}__${node.name}.ts`)).flat(1)
296
+ };
275
297
  return nodes;
276
298
  }
277
299
  /**
@@ -341,7 +363,14 @@ class Treeshake {
341
363
  Treeshake.controller(node);
342
364
  }
343
365
  else if (builder.$b === 'queue') {
344
- Treeshake.queue(node);
366
+ const { inlines } = Treeshake.queue(node);
367
+ inlines.forEach(inline => {
368
+ nodes.push({
369
+ ...inline,
370
+ module,
371
+ filepath
372
+ });
373
+ });
345
374
  }
346
375
  else {
347
376
  throw error_1.NesoiError.Module.UnknownBuilderType({}, filepath, '', builder.$b);
@@ -382,9 +411,13 @@ class Treeshake {
382
411
  }))
383
412
  .sort((a, b) => a.tag.localeCompare(b.tag))
384
413
  .forEach(({ node, tag }) => {
385
- log_1.Log.trace('compiler', 'treeshake', `${' '.repeat(depth)} └ ${tag} ` + (0, string_1.colored)(`@ ${node.filepath}`, 'purple'));
414
+ log_1.Log.debug('compiler', 'treeshake', `${' '.repeat(depth)} └ ${tag} ` + (0, string_1.colored)(`@ ${node.filepath}`, 'purple'));
415
+ if (node.progressive) {
416
+ log_1.Log.debug('compiler', 'treeshake', `${' '.repeat(depth + 1)}` + (0, string_1.colored)('[cache]', 'green'));
417
+ return;
418
+ }
386
419
  if (node.dependencies.length) {
387
- log_1.Log.trace('compiler', 'treeshake', (0, string_1.colored)(`${' '.repeat(depth)} (depends on: ${node.dependencies.map(dep => dep.tag).join(', ')})`, 'purple'));
420
+ log_1.Log.debug('compiler', 'treeshake', (0, string_1.colored)(`${' '.repeat(depth)} (depends on: ${node.dependencies.map(dep => dep.tag).join(', ')})`, 'purple'));
388
421
  }
389
422
  if ('_inlineNodes' in node.builder) {
390
423
  const inlineNodes = node.builder['_inlineNodes'];
@@ -7,6 +7,8 @@ class TSBridgeInject {
7
7
  static inject(compiler, nodes) {
8
8
  const { tsCompiler } = compiler;
9
9
  nodes.forEach(node => {
10
+ if (node.progressive)
11
+ return;
10
12
  log_1.Log.debug('compiler', 'bridge.inject', `Injecting TS code on ${node.tag}`);
11
13
  const schema = node.schema;
12
14
  if (schema.$t === 'bucket') {
@@ -60,7 +60,7 @@ function makeAppInjectTransformer(modules) {
60
60
  monolyth = true;
61
61
  return deep.node;
62
62
  }, context);
63
- // Transform .modules() into .prebuilt()
63
+ // Transform .modules() into .inject()
64
64
  if (monolyth
65
65
  && ts.isCallExpression(cNode)
66
66
  && ts.isPropertyAccessExpression(cNode.expression)
@@ -74,9 +74,9 @@ class App {
74
74
  makeModules() {
75
75
  const modules = {};
76
76
  if (this.space) {
77
- space_1.Space.scan(this.space, (name, path) => {
77
+ space_1.Space.scan(this.space, (name, path, subdir) => {
78
78
  if (this._spaceModuleNames.includes(name)) {
79
- modules[name] = new module_1.Module(name, { dirpath: path });
79
+ modules[name] = new module_1.Module(name, { dirpath: path }, subdir);
80
80
  }
81
81
  });
82
82
  }
@@ -1,6 +1,6 @@
1
1
  import { NesoiObj } from './obj';
2
2
  import { AnyTrxNode } from '../transaction/trx_node';
3
- import { $Bucket } from "../../elements";
3
+ import { $Bucket } from "../../elements/entities/bucket/bucket.schema";
4
4
  import { AnyModule } from '../module';
5
5
  export type TrashObj = {
6
6
  id: number;
@@ -1,10 +1,10 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.Trash = exports.$TrashBucket = void 0;
4
- const elements_1 = require("../../elements");
4
+ const bucket_schema_1 = require("../../elements/entities/bucket/bucket.schema");
5
5
  const bucket_model_schema_1 = require("../../elements/entities/bucket/model/bucket_model.schema");
6
6
  const bucket_graph_schema_1 = require("../../elements/entities/bucket/graph/bucket_graph.schema");
7
- exports.$TrashBucket = new elements_1.$Bucket('__trash__', 'trash', 'Trash', new bucket_model_schema_1.$BucketModel({
7
+ exports.$TrashBucket = new bucket_schema_1.$Bucket('__trash__', 'trash', 'Trash', new bucket_model_schema_1.$BucketModel({
8
8
  id: new bucket_model_schema_1.$BucketModelField('id', 'id', 'int', 'id', false, true),
9
9
  module: new bucket_model_schema_1.$BucketModelField('module', 'module', 'string', 'Module Name', false, true),
10
10
  bucket: new bucket_model_schema_1.$BucketModelField('bucket', 'bucket', 'string', 'Bucket Name', false, true),
@@ -96,6 +96,9 @@ export declare class BuilderNode {
96
96
  filepath: string | string[];
97
97
  dependencies: $Dependency[];
98
98
  builder: AnyBuilder;
99
+ progressive?: {
100
+ schema: AnyElementSchema;
101
+ };
99
102
  constructor($: {
100
103
  module: string;
101
104
  type: BuilderType;
@@ -104,6 +107,9 @@ export declare class BuilderNode {
104
107
  filepath: string | string[];
105
108
  dependencies: $Dependency[];
106
109
  builder: AnyBuilder;
110
+ progressive?: {
111
+ schema: AnyElementSchema;
112
+ };
107
113
  });
108
114
  }
109
115
  /**
@@ -156,6 +156,7 @@ class BuilderNode {
156
156
  this.filepath = $.filepath;
157
157
  this.dependencies = $.dependencies;
158
158
  this.builder = $.builder;
159
+ this.progressive = $.progressive;
159
160
  }
160
161
  }
161
162
  exports.BuilderNode = BuilderNode;
@@ -63,6 +63,7 @@ export type VirtualModuleDef = {
63
63
  */
64
64
  export declare class Module<S extends $Space, $ extends $Module> {
65
65
  name: string;
66
+ subdir: string[];
66
67
  schema: $;
67
68
  buckets: { [B in keyof $["buckets"]]: Bucket<$, $["buckets"][B]>; };
68
69
  messages: { [B in keyof $["messages"]]: MessageParser<$["messages"][B]>; };
@@ -101,7 +102,7 @@ export declare class Module<S extends $Space, $ extends $Module> {
101
102
  dirpath: string;
102
103
  } | {
103
104
  builders: AnyBuilder[];
104
- });
105
+ }, subdir?: string[]);
105
106
  /**
106
107
  * Log the module elements
107
108
  */
@@ -79,8 +79,9 @@ class Module {
79
79
  * @param name A module name
80
80
  * @param boot The boot source for this module
81
81
  */
82
- constructor(name, boot) {
82
+ constructor(name, boot, subdir = []) {
83
83
  this.name = name;
84
+ this.subdir = subdir;
84
85
  this.schema = {
85
86
  constants: new constants_schema_1.$Constants(this.name),
86
87
  externals: new externals_schema_1.$Externals(this.name),
@@ -203,6 +203,6 @@ export declare class Space<$ extends $Space> {
203
203
  * @param space A `Space` instance
204
204
  * @param buildFn A callback to run for each module directory
205
205
  */
206
- static scan(space: Space<any>, buildFn: (name: string, path: string) => void): void;
206
+ static scan(space: Space<any>, buildFn: (name: string, path: string, subdir: string[]) => void): void;
207
207
  }
208
208
  export type AnySpace = Space<$Space>;
@@ -296,11 +296,20 @@ class Space {
296
296
  if (!fs.existsSync(modulesPath)) {
297
297
  throw error_1.CompilerError.NoModulesFolder();
298
298
  }
299
- const dirs = fs.readdirSync(modulesPath, { withFileTypes: true })
300
- .filter(node => node.isDirectory());
301
- for (const dir of dirs) {
302
- buildFn(dir.name, path.join(modulesPath, dir.name));
303
- }
299
+ const perform = (dirpath, subdir) => {
300
+ const dirs = fs.readdirSync(dirpath, { withFileTypes: true })
301
+ .filter(node => node.isDirectory());
302
+ for (const dir of dirs) {
303
+ const modulePath = path.join(dirpath, dir.name);
304
+ if (fs.existsSync(path.join(modulePath, '.modules'))) {
305
+ perform(modulePath, [...subdir, dir.name]);
306
+ }
307
+ else {
308
+ buildFn(dir.name, modulePath, subdir);
309
+ }
310
+ }
311
+ };
312
+ perform(modulesPath, []);
304
313
  }
305
314
  }
306
315
  exports.Space = Space;
@@ -2,6 +2,7 @@ import { BuilderType } from "../schema";
2
2
  import { ResolvedBuilderNode } from './dependency';
3
3
  import { AnyModule } from './module';
4
4
  import { TreeshakeConfig } from "../compiler/treeshake";
5
+ import { ProgressiveBuildCache } from "../compiler/progressive";
5
6
  type TraverseCallback = (node: ResolvedBuilderNode) => Promise<void>;
6
7
  /**
7
8
  * A tree of module elements which allows building in the correct order.
@@ -23,7 +24,7 @@ export declare class ModuleTree {
23
24
  * - Resolves each found dependency forming a tree
24
25
  * - Groups tree into layers which can be built in isolation
25
26
  */
26
- resolve(): Promise<void>;
27
+ resolve(cache?: ProgressiveBuildCache): Promise<void>;
27
28
  /**
28
29
  * Read the module elements from files and identify
29
30
  * all related nodes.
@@ -82,5 +83,11 @@ export declare class ModuleTree {
82
83
  * @returns A list of resolved builder nodes
83
84
  */
84
85
  allNodes(): ResolvedBuilderNode[];
86
+ /**
87
+ * Return a list of all nodes of all modules on the tree.
88
+ *
89
+ * @returns A list of resolved builder nodes
90
+ */
91
+ allNodesByModule(): Record<string, ResolvedBuilderNode[]>;
85
92
  }
86
93
  export {};