nesoi 3.0.12 → 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 (56) 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/elements/blocks/resource/resource.js +1 -1
  31. package/lib/elements/entities/bucket/bucket.d.ts +3 -1
  32. package/lib/elements/entities/bucket/bucket.js +18 -6
  33. package/lib/engine/apps/app.config.d.ts +11 -9
  34. package/lib/engine/apps/app.config.js +1 -2
  35. package/lib/engine/apps/app.js +2 -2
  36. package/lib/engine/data/trash.d.ts +13 -10
  37. package/lib/engine/data/trash.js +33 -0
  38. package/lib/engine/dependency.d.ts +6 -0
  39. package/lib/engine/dependency.js +1 -0
  40. package/lib/engine/module.d.ts +4 -2
  41. package/lib/engine/module.js +8 -3
  42. package/lib/engine/space.d.ts +1 -1
  43. package/lib/engine/space.js +14 -5
  44. package/lib/engine/transaction/nodes/bucket.trx_node.d.ts +5 -1
  45. package/lib/engine/transaction/nodes/bucket.trx_node.js +9 -2
  46. package/lib/engine/transaction/nodes/bucket_query.trx_node.d.ts +3 -3
  47. package/lib/engine/transaction/nodes/bucket_query.trx_node.js +2 -2
  48. package/lib/engine/transaction/trx_engine.d.ts +1 -1
  49. package/lib/engine/transaction/trx_node.d.ts +1 -1
  50. package/lib/engine/transaction/trx_node.js +3 -1
  51. package/lib/engine/tree.d.ts +8 -1
  52. package/lib/engine/tree.js +45 -25
  53. package/lib/engine/util/hash.d.ts +2 -1
  54. package/lib/engine/util/hash.js +10 -1
  55. package/package.json +1 -1
  56. 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)
@@ -91,7 +91,7 @@ class Resource extends block_1.Block {
91
91
  static query($) {
92
92
  const scope = $.job.scope;
93
93
  return $.trx.bucket(scope.bucket)
94
- .query($.msg.query).page({
94
+ .viewQuery($.msg.query).page({
95
95
  page: $.msg.page,
96
96
  perPage: $.msg.perPage,
97
97
  count: true
@@ -11,6 +11,7 @@ import { NQL_Result } from './query/nql_engine';
11
11
  import { $BucketModelFields } from './model/bucket_model.schema';
12
12
  import { DriveAdapter } from '../drive/drive_adapter';
13
13
  import { IService } from "../../../engine/apps/service";
14
+ import { AnyModule } from "../../../engine/module";
14
15
  /**
15
16
  * **This should only be used inside a `#composition` of a bucket `create`** to refer to the parent id, which doesn't exist yet.
16
17
  *
@@ -26,6 +27,7 @@ export declare const $id: string | number;
26
27
  * @subcategory Entity
27
28
  * */
28
29
  export declare class Bucket<M extends $Module, $ extends $Bucket> {
30
+ module: AnyModule;
29
31
  schema: $;
30
32
  private config?;
31
33
  services: Record<string, IService>;
@@ -34,7 +36,7 @@ export declare class Bucket<M extends $Module, $ extends $Bucket> {
34
36
  graph: BucketGraph<M, $>;
35
37
  private views;
36
38
  drive?: DriveAdapter;
37
- constructor(schema: $, config?: BucketConfig<any, any, any> | undefined, services?: Record<string, IService>);
39
+ constructor(module: AnyModule, schema: $, config?: BucketConfig<any, any, any> | undefined, services?: Record<string, IService>);
38
40
  getQueryMeta(): {
39
41
  bucket: $;
40
42
  scope: string;
@@ -12,6 +12,7 @@ const datetime_1 = require("../../../engine/data/datetime");
12
12
  const tree_1 = require("../../../engine/data/tree");
13
13
  const crypto_1 = require("../../../engine/util/crypto");
14
14
  const bucket_model_schema_1 = require("./model/bucket_model.schema");
15
+ const trash_1 = require("../../../engine/data/trash");
15
16
  /**
16
17
  * **This should only be used inside a `#composition` of a bucket `create`** to refer to the parent id, which doesn't exist yet.
17
18
  *
@@ -27,7 +28,8 @@ exports.$id = Symbol('FUTURE ID OF CREATE');
27
28
  * @subcategory Entity
28
29
  * */
29
30
  class Bucket {
30
- constructor(schema, config, services = {}) {
31
+ constructor(module, schema, config, services = {}) {
32
+ this.module = module;
31
33
  this.schema = schema;
32
34
  this.config = config;
33
35
  this.services = services;
@@ -506,18 +508,19 @@ class Bucket {
506
508
  throw error_1.NesoiError.Bucket.InvalidId({ bucket: this.schema.alias, id });
507
509
  }
508
510
  // Read object, if safe, to check if it exists
509
- if (!options?.unsafe) {
511
+ let result;
512
+ if (this.module.trash || !options?.unsafe) {
510
513
  // Tenancy
511
514
  const tenancy = (options?.no_tenancy)
512
515
  ? undefined
513
516
  : this.getTenancyQuery(trx);
514
517
  // Check if object exists
515
- const result = await this.adapter.query(trx, {
518
+ result = await this.adapter.query(trx, {
516
519
  id, '#and': tenancy
517
520
  }, { perPage: 1 }, undefined, {
518
521
  metadataOnly: true
519
522
  });
520
- if (!result.data.length) {
523
+ if (!result.data.length && !options?.unsafe) {
521
524
  throw error_1.NesoiError.Bucket.ObjNotFound({ bucket: this.schema.alias, id });
522
525
  }
523
526
  }
@@ -542,6 +545,10 @@ class Bucket {
542
545
  }
543
546
  }
544
547
  // Delete the object itself
548
+ if (this.module.trash) {
549
+ const obj = result.data[0];
550
+ await trash_1.Trash.add(trx, this.module, this.schema.name, obj);
551
+ }
545
552
  await this.adapter.delete(trx, id);
546
553
  // Composition (with self key)
547
554
  for (const link of Object.values(this.schema.graph.links)) {
@@ -574,13 +581,14 @@ class Bucket {
574
581
  async deleteMany(trx, ids, options) {
575
582
  log_1.Log.debug('bucket', this.schema.name, `Delete Many ids=${ids}`);
576
583
  // Filter ids, if safe, to check if it exists
577
- if (!options?.unsafe) {
584
+ let result;
585
+ if (this.module.trash || !options?.unsafe) {
578
586
  // Tenancy
579
587
  const tenancy = (options?.no_tenancy)
580
588
  ? undefined
581
589
  : this.getTenancyQuery(trx);
582
590
  // Filter ids
583
- const result = await this.adapter.query(trx, {
591
+ result = await this.adapter.query(trx, {
584
592
  'id in': ids,
585
593
  '#and': tenancy
586
594
  }, undefined, undefined, {
@@ -606,6 +614,10 @@ class Bucket {
606
614
  }
607
615
  }
608
616
  }
617
+ if (this.module.trash) {
618
+ const objs = result.data;
619
+ await trash_1.Trash.addMany(trx, this.module, this.schema.name, objs);
620
+ }
609
621
  await this.adapter.deleteMany(trx, ids);
610
622
  // Composition (with self key)
611
623
  for (const link of Object.values(this.schema.graph.links)) {
@@ -8,10 +8,11 @@ import { App } from './app';
8
8
  import { IService } from './service';
9
9
  import { CLIConfig } from '../cli/cli';
10
10
  import { BucketAdapter } from "../../elements/entities/bucket/adapters/bucket_adapter";
11
- import { TrashObj } from '../data/trash';
11
+ import { $TrashBucket } from '../data/trash';
12
12
  import { $Bucket } from "../../elements";
13
13
  import { Overlay } from '../util/type';
14
14
  import { TrxStatus } from '../transaction/trx';
15
+ import { NesoiObj } from '../data/obj';
15
16
  export type AppConfig<S extends $Space, Modules extends ModuleName<S>> = {
16
17
  i18n?: AppI18nConfig;
17
18
  authn?: AppAuthnConfig<S>;
@@ -20,6 +21,7 @@ export type AppConfig<S extends $Space, Modules extends ModuleName<S>> = {
20
21
  cli?: CLIConfig<any>;
21
22
  compiler?: CompilerConfig;
22
23
  trxEngine?: AppTrxEngineConfig<S, Modules, any>;
24
+ trash?: AppTrashConfig<S, Modules, any>;
23
25
  };
24
26
  export type AnyAppConfig = AppConfig<any, any>;
25
27
  export type AppI18nConfig = {
@@ -33,11 +35,11 @@ export type AppBucketConfig<S extends $Space, Modules extends ModuleName<S>, Ser
33
35
  [K in keyof S['modules'][M]['buckets']]: BucketConfig<S['modules'][M], S['modules'][M]['buckets'][K], Services>;
34
36
  }>;
35
37
  }>;
36
- export type AppTrashConfig = {
37
- adapter: ($: Overlay<$Bucket, {
38
- '#data': TrashObj;
39
- }>) => BucketAdapter<TrashObj>;
40
- };
38
+ export type AppTrashConfig<S extends $Space, Modules extends ModuleName<S>, Services extends Record<string, IService>> = Partial<{
39
+ [M in (Modules & keyof S['modules'])]: {
40
+ adapter?: (schema: typeof $TrashBucket, services: Services) => BucketAdapter<typeof $TrashBucket['#data']>;
41
+ };
42
+ }>;
41
43
  export type AppControllerConfig<S extends $Space, Modules extends ModuleName<S>, Services extends Record<string, IService>> = Partial<{
42
44
  [M in (Modules & keyof S['modules'])]: Partial<{
43
45
  [K in keyof S['modules'][M]['controllers']]: ControllerConfig<S['modules'][M], S['modules'][M]['controllers'][K], Services>;
@@ -48,8 +50,8 @@ export type AppTrxEngineConfig<S extends $Space, Modules extends ModuleName<S>,
48
50
  }>;
49
51
  export type AppAuditConfig = {
50
52
  adapter: ($: Overlay<$Bucket, {
51
- '#data': TrashObj;
52
- }>) => BucketAdapter<TrashObj>;
53
+ '#data': NesoiObj;
54
+ }>) => BucketAdapter<NesoiObj>;
53
55
  transform?: (trx: TrxStatus<any>) => Record<string, any>;
54
56
  };
55
57
  /**
@@ -65,7 +67,7 @@ export declare class AppConfigFactory<S extends $Space, Modules extends string =
65
67
  i18n(config: AppI18nConfig): _App;
66
68
  authn(config: AppAuthnConfig<S>): _App;
67
69
  buckets(config: AppBucketConfig<S, Modules, Services>): _App;
68
- trash(config: AppTrashConfig): _App;
70
+ trash(config: AppTrashConfig<S, Modules, Services>): _App;
69
71
  controllers(config: AppControllerConfig<S, Modules, Services>): _App;
70
72
  audit(config: AppI18nConfig): _App;
71
73
  compiler(config: CompilerConfig): _App;
@@ -25,8 +25,7 @@ class AppConfigFactory {
25
25
  return this.app;
26
26
  }
27
27
  trash(config) {
28
- // TODO
29
- // this.config.buckets = config as never;
28
+ this.config.trash = config;
30
29
  return this.app;
31
30
  }
32
31
  controllers(config) {
@@ -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
  }