@deterministic-code/datasources-cli 0.1.13 → 0.1.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 (54) hide show
  1. package/dist/detect.js +21 -7
  2. package/dist/generate/CSharpRepositories.js +18 -14
  3. package/dist/generate/DeterministicProvider.js +23 -7
  4. package/dist/generate/RepositoryModel.js +10 -4
  5. package/dist/generate/RepositoryPlan.js +12 -5
  6. package/dist/generate/RustRepositories.js +42 -31
  7. package/dist/generate/TypeScriptRepositories.js +22 -18
  8. package/dist/generate/applyGenerate.js +9 -2
  9. package/dist/generate/applyMigrations.js +5 -13
  10. package/dist/generate/casing.js +28 -0
  11. package/dist/generate/migrateUp.js +2 -8
  12. package/dist/generate/sqlFlags.js +27 -0
  13. package/dist/migrateInit.js +4 -3
  14. package/dist/parse.js +102 -25
  15. package/dist/run.js +42 -67
  16. package/dist/setup.js +7 -9
  17. package/dist/version/applyVersion.js +11 -14
  18. package/dist/version/delta.js +0 -50
  19. package/dist/version/render.js +1 -11
  20. package/dist/wireRegister.js +29 -11
  21. package/dist/wireRustProviders.js +42 -0
  22. package/node_modules/@deterministic-code/csharp-generators/dist/import-generator.js +16 -12
  23. package/node_modules/@deterministic-code/csharp-generators/src/import-generator.test.ts +22 -11
  24. package/node_modules/@deterministic-code/csharp-generators/src/import-generator.ts +21 -13
  25. package/node_modules/@deterministic-code/datasources-code-generators/dist/nestedSelectTypes.js +2 -6
  26. package/node_modules/@deterministic-code/datasources-code-generators/dist/sql/common/infer-reference-types.d.ts +2 -0
  27. package/node_modules/@deterministic-code/datasources-code-generators/dist/sql/common/infer-reference-types.js +37 -0
  28. package/node_modules/@deterministic-code/datasources-code-generators/dist/sql/common/reference-target.d.ts +2 -0
  29. package/node_modules/@deterministic-code/datasources-code-generators/dist/sql/common/reference-target.js +6 -0
  30. package/node_modules/@deterministic-code/datasources-code-generators/dist/sql/common/sql-schema.d.ts +1 -1
  31. package/node_modules/@deterministic-code/datasources-code-generators/dist/sql/common/sql-schema.js +3 -6
  32. package/node_modules/@deterministic-code/datasources-code-generators/dist/sql/common/version-migrations.js +25 -14
  33. package/node_modules/@deterministic-code/datasources-code-generators/package.json +4 -2
  34. package/node_modules/@deterministic-code/deterministic-generators-common/README.md +61 -1
  35. package/node_modules/@deterministic-code/deterministic-generators-common/typescript/parser/dist/specification-parser.js +128 -1
  36. package/node_modules/@deterministic-code/deterministic-generators-common/typescript/parser/specification-parser.ts +1 -0
  37. package/node_modules/@deterministic-code/deterministic-generators-common/typescript/parser/version-snapshot.ts +154 -0
  38. package/node_modules/@deterministic-code/deterministic-generators-common/typescript/parser/yaml-node.ts +2 -2
  39. package/node_modules/@deterministic-code/rust-generators/dist/import-generator.js +25 -15
  40. package/node_modules/@deterministic-code/rust-generators/src/import-generator.test.ts +11 -0
  41. package/node_modules/@deterministic-code/rust-generators/src/import-generator.ts +36 -18
  42. package/node_modules/@deterministic-code/typescript-generators/dist/generate-frontend-types.js +6 -1
  43. package/node_modules/@deterministic-code/typescript-generators/dist/generate-frontend-validators.js +6 -1
  44. package/node_modules/@deterministic-code/typescript-generators/dist/generate-routes.js +1 -1
  45. package/node_modules/@deterministic-code/typescript-generators/dist/generate-services.js +1 -1
  46. package/node_modules/@deterministic-code/typescript-generators/dist/import-generator.js +29 -21
  47. package/node_modules/@deterministic-code/typescript-generators/src/emit.ts +2 -5
  48. package/node_modules/@deterministic-code/typescript-generators/src/generate-frontend-types.ts +7 -1
  49. package/node_modules/@deterministic-code/typescript-generators/src/generate-frontend-validators.ts +7 -1
  50. package/node_modules/@deterministic-code/typescript-generators/src/generate-routes.ts +1 -1
  51. package/node_modules/@deterministic-code/typescript-generators/src/generate-services.ts +1 -1
  52. package/node_modules/@deterministic-code/typescript-generators/src/import-generator.test.ts +16 -0
  53. package/node_modules/@deterministic-code/typescript-generators/src/import-generator.ts +37 -22
  54. package/package.json +2 -2
@@ -1,14 +1,19 @@
1
1
  import { verifyEntries } from "@deterministic-code/generators-common/reference-verifier";
2
+ import { createCasing } from "./common/default-casing.js";
2
3
  import { Emit } from "./emit.js";
3
4
  import { generateViewTypes } from "./emit-shaped-types.js";
4
5
  import { referencesBackend } from "./inline-inherited.js";
6
+ const layered = (settings, path) => {
7
+ const casing = createCasing(settings);
8
+ return path.split("/").map((segment) => casing.convertDirectories(segment)).join("/");
9
+ };
5
10
  const generate = async (ctx) => {
6
11
  const referenceBackendType = referencesBackend(ctx.settings);
7
12
  const views = new Emit(ctx.settings).imports.frontend("src/types");
8
13
  const entries = await generateViewTypes(ctx, {
9
14
  referenceBackendType,
10
15
  basePath: views,
11
- datasourceBasePath: referenceBackendType ? "types/generated/datasource" : views
16
+ datasourceBasePath: referenceBackendType ? layered(ctx.settings, "types/generated/datasource") : views
12
17
  });
13
18
  if (!referenceBackendType) verifyEntries(entries);
14
19
  return entries;
@@ -1,5 +1,10 @@
1
1
  import { verifyEntries } from "@deterministic-code/generators-common/reference-verifier";
2
+ import { createCasing } from "./common/default-casing.js";
2
3
  import { Emit } from "./emit.js";
4
+ const layered = (settings, path) => {
5
+ const casing = createCasing(settings);
6
+ return path.split("/").map((segment) => casing.convertDirectories(segment)).join("/");
7
+ };
3
8
  import { generate as generateViewTypeValidators } from "./generate-view-type-validators.js";
4
9
  import { referencesBackend } from "./inline-inherited.js";
5
10
  import {
@@ -24,7 +29,7 @@ const generate = async (ctx) => {
24
29
  schemaInheritTmpl
25
30
  },
26
31
  basePath: validators,
27
- datasourceBasePath: referenceBackendType ? "types/generated/datasource/validators" : validators
32
+ datasourceBasePath: referenceBackendType ? layered(ctx.settings, "types/generated/datasource/validators") : validators
28
33
  });
29
34
  if (!referenceBackendType) verifyEntries(entries);
30
35
  return entries;
@@ -44,7 +44,7 @@ class Generator extends Emit {
44
44
  return entries;
45
45
  }
46
46
  customModuleKey(emitPath) {
47
- return customRelKey(emitPath, "routes");
47
+ return customRelKey(emitPath, this.casing.convertDirectories("routes"));
48
48
  }
49
49
  entityRouter(candidate) {
50
50
  const { simpleDoc, descriptionDoc } = this.settings;
@@ -129,7 +129,7 @@ class Generator extends Emit {
129
129
  }
130
130
  /** Map emit paths like `../custom/foo.ts` to Rel keys `services/custom/foo.ts`. */
131
131
  customModuleKey(emitPath) {
132
- return customRelKey(emitPath, "services");
132
+ return customRelKey(emitPath, this.casing.convertDirectories("services"));
133
133
  }
134
134
  custom(entry) {
135
135
  const { simpleDoc, descriptionDoc } = this.settings;
@@ -27,7 +27,7 @@ class TypeScriptImportGenerator {
27
27
  return this.underBase(path);
28
28
  }
29
29
  datasourceRel(entity) {
30
- return this.rel("types/generated/datasource", this.datasource(entity));
30
+ return this.rel(this.layered("types/generated/datasource"), this.datasource(entity));
31
31
  }
32
32
  datasourceQual(entity) {
33
33
  return this.casing.convertTypes(entity);
@@ -39,19 +39,19 @@ class TypeScriptImportGenerator {
39
39
  }
40
40
  datasourceValidatorRel(entity) {
41
41
  return this.rel(
42
- "types/generated/datasource/validators",
42
+ this.layered("types/generated/datasource/validators"),
43
43
  this.datasourceValidator(entity)
44
44
  );
45
45
  }
46
46
  datasourceTestRel(entity) {
47
47
  return this.rel(
48
- "types/generated/datasource",
48
+ this.layered("types/generated/datasource"),
49
49
  this.test(this.datasource(entity), entity)
50
50
  );
51
51
  }
52
52
  datasourceValidatorTestRel(entity) {
53
53
  return this.rel(
54
- "types/generated/datasource/validators",
54
+ this.layered("types/generated/datasource/validators"),
55
55
  this.test(this.datasourceValidator(entity), entity)
56
56
  );
57
57
  }
@@ -59,7 +59,7 @@ class TypeScriptImportGenerator {
59
59
  return this.underBase(this.viewLike(entity, ""));
60
60
  }
61
61
  viewRel(entity) {
62
- return this.rel("types/generated/views", this.view(entity));
62
+ return this.rel(this.layered("types/generated/views"), this.view(entity));
63
63
  }
64
64
  viewQual(entity) {
65
65
  return this.casing.convertTypes(entity);
@@ -69,16 +69,16 @@ class TypeScriptImportGenerator {
69
69
  }
70
70
  viewValidatorRel(entity) {
71
71
  return this.rel(
72
- "types/generated/views/validators",
72
+ this.layered("types/generated/views/validators"),
73
73
  this.viewValidator(entity)
74
74
  );
75
75
  }
76
76
  viewTestRel(entity) {
77
- return this.rel("types/generated/views", this.test(this.view(entity), entity));
77
+ return this.rel(this.layered("types/generated/views"), this.test(this.view(entity), entity));
78
78
  }
79
79
  viewValidatorTestRel(entity) {
80
80
  return this.rel(
81
- "types/generated/views/validators",
81
+ this.layered("types/generated/views/validators"),
82
82
  this.test(this.viewValidator(entity), entity)
83
83
  );
84
84
  }
@@ -91,29 +91,29 @@ class TypeScriptImportGenerator {
91
91
  return this.underBase(path);
92
92
  }
93
93
  serviceRel(entity) {
94
- return this.rel("services/generated", this.service(entity));
94
+ return this.rel(this.layered("services/generated"), this.service(entity));
95
95
  }
96
96
  serviceCustom(name, module) {
97
97
  return this.resolveCustom(name, module, "services");
98
98
  }
99
99
  serviceCustomRel(entity) {
100
100
  const file = `${this.serviceStem(entity)}.ts`;
101
- return this.organizeByFeature ? `features/${this.casing.directory(entity)}/custom/${file}` : `services/custom/${file}`;
101
+ return this.organizeByFeature ? `${this.featuresDir(entity)}/custom/${file}` : `${this.layered("services")}/custom/${file}`;
102
102
  }
103
103
  serviceTest(entity) {
104
104
  const file = `${this.serviceStem(entity)}.test.ts`;
105
- const path = this.organizeByFeature ? `features/${this.casing.directory(entity)}/__tests__/${file}` : file;
105
+ const path = this.organizeByFeature ? `${this.featuresDir(entity)}/__tests__/${file}` : file;
106
106
  return this.underBase(path);
107
107
  }
108
108
  serviceTestRel(entity) {
109
- return this.rel("services/generated/__tests__", this.serviceTest(entity));
109
+ return this.rel(this.layered("services/generated/__tests__"), this.serviceTest(entity));
110
110
  }
111
111
  serviceIntegrationTest(entity) {
112
112
  return this.serviceTest(entity).replace(/\.test\.ts$/, ".integration.test.js");
113
113
  }
114
114
  serviceIntegrationTestRel(entity) {
115
115
  return this.rel(
116
- "services/generated/__tests__",
116
+ this.layered("services/generated/__tests__"),
117
117
  this.serviceIntegrationTest(entity)
118
118
  );
119
119
  }
@@ -126,18 +126,18 @@ class TypeScriptImportGenerator {
126
126
  return this.underBase(path);
127
127
  }
128
128
  routeRel(entity) {
129
- return this.rel("routes/generated", this.route(entity));
129
+ return this.rel(this.layered("routes/generated"), this.route(entity));
130
130
  }
131
131
  routeCustom(name, module) {
132
132
  return this.resolveCustom(name, module, "routes");
133
133
  }
134
134
  routeTest(entity) {
135
135
  const file = `${this.casing.fileBase(entity)}.integration.test.ts`;
136
- const path = this.organizeByFeature ? `features/${this.casing.directory(entity)}/__tests__/${file}` : file;
136
+ const path = this.organizeByFeature ? `${this.featuresDir(entity)}/__tests__/${file}` : file;
137
137
  return this.underBase(path);
138
138
  }
139
139
  routeTestRel(entity) {
140
- return this.rel("routes/generated/__tests__", this.routeTest(entity));
140
+ return this.rel(this.layered("routes/generated/__tests__"), this.routeTest(entity));
141
141
  }
142
142
  enrichment(_targetTable) {
143
143
  return "";
@@ -187,8 +187,8 @@ class TypeScriptImportGenerator {
187
187
  /** Layered types/services/routes globs, or features when by-feature. Empty when flat. */
188
188
  tsconfigIncludes() {
189
189
  if (this.flat) return [];
190
- if (this.organizeByFeature) return ["features/**/*.ts"];
191
- return ["types/**/*.ts", "services/**/*.ts", "routes/**/*.ts"];
190
+ if (this.organizeByFeature) return [`${this.casing.convertDirectories("features")}/**/*.ts`];
191
+ return ["types", "services", "routes"].map((layer) => `${this.casing.convertDirectories(layer)}/**/*.ts`);
192
192
  }
193
193
  rel(prefix, file) {
194
194
  if (this.organizeByFeature || this.flat) return file;
@@ -197,8 +197,16 @@ class TypeScriptImportGenerator {
197
197
  tsFile(stem) {
198
198
  return `${this.casing.fileBase(stem)}.ts`;
199
199
  }
200
+ layered(path) {
201
+ return path.split("/").map(
202
+ (segment) => segment === "custom" || segment === "__tests__" ? segment : this.casing.convertDirectories(segment)
203
+ ).join("/");
204
+ }
205
+ featuresDir(entity) {
206
+ return `${this.casing.convertDirectories("features")}/${this.casing.directory(entity)}`;
207
+ }
200
208
  featurePath(entity, file) {
201
- return `features/${this.casing.directory(entity)}/${file}`;
209
+ return `${this.featuresDir(entity)}/${file}`;
202
210
  }
203
211
  serviceStem(entity) {
204
212
  return this.casing.fileBase(`${entity}_service`);
@@ -209,13 +217,13 @@ class TypeScriptImportGenerator {
209
217
  }
210
218
  viewLike(entity, featureExt) {
211
219
  const file = `${this.casing.fileBase(entity)}${this.organizeByFeature ? featureExt : ""}.ts`;
212
- return this.organizeByFeature ? `features/${this.casing.directory(entity)}/${file}` : file;
220
+ return this.organizeByFeature ? `${this.featuresDir(entity)}/${file}` : file;
213
221
  }
214
222
  resolveCustom(name, mod, layer) {
215
223
  const kind = layer === "services" ? "service" : "route";
216
224
  const stubFn = layer === "services" ? "generateCustomServiceStub" : "generateCustomRouteStub";
217
225
  const file = layer === "services" ? this.tsFile(name) : `${this.casing.fileBase(`${name}_route`)}.ts`;
218
- const defaultStub = this.organizeByFeature ? `features/${this.casing.directory(name)}/custom/${file}` : `../custom/${file}`;
226
+ const defaultStub = this.organizeByFeature ? `${this.featuresDir(name)}/custom/${file}` : `../custom/${file}`;
219
227
  if (this.organizeByFeature) {
220
228
  if (typeof mod !== "string" || !mod.startsWith(".") || mod.startsWith("./services/") || mod.startsWith("./routes/")) {
221
229
  return defaultStub;
@@ -37,11 +37,8 @@ export const bag = (attrs: {
37
37
  return out;
38
38
  };
39
39
 
40
- /** Map `../….ts` emit paths to project-relative Rel keys (`services/….ts`). */
41
- export const customRelKey = (
42
- emitPath: string,
43
- layer: "services" | "routes",
44
- ): string =>
40
+ /** Map `../….ts` emit paths to project-relative Rel keys using the cased layer directory. */
41
+ export const customRelKey = (emitPath: string, layer: string): string =>
45
42
  emitPath.startsWith("../") ? `${layer}/${emitPath.slice(3)}` : emitPath;
46
43
 
47
44
  /** Settings plus pack import generators created once; lanes use `this.imports`. */
@@ -1,10 +1,16 @@
1
1
  import type { GenerateContext } from "@deterministic-code/generators-common/generate-context";
2
2
  import type { GenerateEntry } from "@deterministic-code/generators-common/generate-entry";
3
3
  import { verifyEntries } from "@deterministic-code/generators-common/reference-verifier";
4
+ import { createCasing } from "./common/default-casing.ts";
4
5
  import { Emit } from "./emit.ts";
5
6
  import { generateViewTypes } from "./emit-shaped-types.ts";
6
7
  import { referencesBackend } from "./inline-inherited.ts";
7
8
 
9
+ const layered = (settings: Record<string, string>, path: string): string => {
10
+ const casing = createCasing(settings);
11
+ return path.split("/").map((segment) => casing.convertDirectories(segment)).join("/");
12
+ };
13
+
8
14
  /** Self-checks when the lane is closed; backend-type refs need host `finalizeEntries`. */
9
15
  export const generate = async (
10
16
  ctx: GenerateContext,
@@ -15,7 +21,7 @@ export const generate = async (
15
21
  referenceBackendType,
16
22
  basePath: views,
17
23
  datasourceBasePath: referenceBackendType
18
- ? "types/generated/datasource"
24
+ ? layered(ctx.settings, "types/generated/datasource")
19
25
  : views,
20
26
  });
21
27
  if (!referenceBackendType) verifyEntries(entries);
@@ -1,7 +1,13 @@
1
1
  import type { GenerateContext } from "@deterministic-code/generators-common/generate-context";
2
2
  import type { GenerateEntry } from "@deterministic-code/generators-common/generate-entry";
3
3
  import { verifyEntries } from "@deterministic-code/generators-common/reference-verifier";
4
+ import { createCasing } from "./common/default-casing.ts";
4
5
  import { Emit } from "./emit.ts";
6
+
7
+ const layered = (settings: Record<string, string>, path: string): string => {
8
+ const casing = createCasing(settings);
9
+ return path.split("/").map((segment) => casing.convertDirectories(segment)).join("/");
10
+ };
5
11
  import { generate as generateViewTypeValidators } from "./generate-view-type-validators.ts";
6
12
  import { referencesBackend } from "./inline-inherited.ts";
7
13
  import {
@@ -31,7 +37,7 @@ export const generate = async (
31
37
  },
32
38
  basePath: validators,
33
39
  datasourceBasePath: referenceBackendType
34
- ? "types/generated/datasource/validators"
40
+ ? layered(ctx.settings, "types/generated/datasource/validators")
35
41
  : validators,
36
42
  });
37
43
  if (!referenceBackendType) verifyEntries(entries);
@@ -54,7 +54,7 @@ class Generator extends Emit {
54
54
  }
55
55
 
56
56
  private customModuleKey(emitPath: string): string {
57
- return customRelKey(emitPath, "routes");
57
+ return customRelKey(emitPath, this.casing.convertDirectories("routes"));
58
58
  }
59
59
 
60
60
  private entityRouter(candidate: RouteCandidate): GenerateEntry {
@@ -165,7 +165,7 @@ class Generator extends Emit {
165
165
 
166
166
  /** Map emit paths like `../custom/foo.ts` to Rel keys `services/custom/foo.ts`. */
167
167
  private customModuleKey(emitPath: string): string {
168
- return customRelKey(emitPath, "services");
168
+ return customRelKey(emitPath, this.casing.convertDirectories("services"));
169
169
  }
170
170
 
171
171
  private custom(entry: CustomServiceEntry): GenerateEntry {
@@ -73,6 +73,22 @@ describe("TypeScriptImportGenerator layered (organize_by_feature unset)", () =>
73
73
  "services/generated/__tests__/userService.integration.test.ts",
74
74
  );
75
75
  assert.equal(imports.serviceCustomRel("user"), "services/custom/userService.ts");
76
+ const pascalDirs = createImportGenerator(".", {
77
+ "languages.typescript.casing.directories": "Pascal",
78
+ });
79
+ assert.equal(
80
+ pascalDirs.datasourceRel("user"),
81
+ "Types/Generated/Datasource/user.ts",
82
+ );
83
+ assert.equal(
84
+ pascalDirs.serviceRel("user"),
85
+ "Services/Generated/userService.ts",
86
+ );
87
+ assert.deepEqual(pascalDirs.tsconfigIncludes(), [
88
+ "Types/**/*.ts",
89
+ "Services/**/*.ts",
90
+ "Routes/**/*.ts",
91
+ ]);
76
92
  assert.equal(imports.route("user"), "user.ts");
77
93
  assert.equal(imports.routeRel("user"), "routes/generated/user.ts");
78
94
  assert.equal(imports.routeTest("user"), "user.integration.test.ts");
@@ -39,7 +39,7 @@ export class TypeScriptImportGenerator implements IImportGenerator {
39
39
  }
40
40
 
41
41
  datasourceRel(entity: string): string {
42
- return this.rel("types/generated/datasource", this.datasource(entity));
42
+ return this.rel(this.layered("types/generated/datasource"), this.datasource(entity));
43
43
  }
44
44
 
45
45
  datasourceQual(entity: string): string {
@@ -58,21 +58,21 @@ export class TypeScriptImportGenerator implements IImportGenerator {
58
58
 
59
59
  datasourceValidatorRel(entity: string): string {
60
60
  return this.rel(
61
- "types/generated/datasource/validators",
61
+ this.layered("types/generated/datasource/validators"),
62
62
  this.datasourceValidator(entity),
63
63
  );
64
64
  }
65
65
 
66
66
  datasourceTestRel(entity: string): string {
67
67
  return this.rel(
68
- "types/generated/datasource",
68
+ this.layered("types/generated/datasource"),
69
69
  this.test(this.datasource(entity), entity),
70
70
  );
71
71
  }
72
72
 
73
73
  datasourceValidatorTestRel(entity: string): string {
74
74
  return this.rel(
75
- "types/generated/datasource/validators",
75
+ this.layered("types/generated/datasource/validators"),
76
76
  this.test(this.datasourceValidator(entity), entity),
77
77
  );
78
78
  }
@@ -82,7 +82,7 @@ export class TypeScriptImportGenerator implements IImportGenerator {
82
82
  }
83
83
 
84
84
  viewRel(entity: string): string {
85
- return this.rel("types/generated/views", this.view(entity));
85
+ return this.rel(this.layered("types/generated/views"), this.view(entity));
86
86
  }
87
87
 
88
88
  viewQual(entity: string): string {
@@ -95,18 +95,18 @@ export class TypeScriptImportGenerator implements IImportGenerator {
95
95
 
96
96
  viewValidatorRel(entity: string): string {
97
97
  return this.rel(
98
- "types/generated/views/validators",
98
+ this.layered("types/generated/views/validators"),
99
99
  this.viewValidator(entity),
100
100
  );
101
101
  }
102
102
 
103
103
  viewTestRel(entity: string): string {
104
- return this.rel("types/generated/views", this.test(this.view(entity), entity));
104
+ return this.rel(this.layered("types/generated/views"), this.test(this.view(entity), entity));
105
105
  }
106
106
 
107
107
  viewValidatorTestRel(entity: string): string {
108
108
  return this.rel(
109
- "types/generated/views/validators",
109
+ this.layered("types/generated/views/validators"),
110
110
  this.test(this.viewValidator(entity), entity),
111
111
  );
112
112
  }
@@ -126,7 +126,7 @@ export class TypeScriptImportGenerator implements IImportGenerator {
126
126
  }
127
127
 
128
128
  serviceRel(entity: string): string {
129
- return this.rel("services/generated", this.service(entity));
129
+ return this.rel(this.layered("services/generated"), this.service(entity));
130
130
  }
131
131
 
132
132
  serviceCustom(name: string, module?: string): string {
@@ -136,20 +136,20 @@ export class TypeScriptImportGenerator implements IImportGenerator {
136
136
  serviceCustomRel(entity: string): string {
137
137
  const file = `${this.serviceStem(entity)}.ts`;
138
138
  return this.organizeByFeature
139
- ? `features/${this.casing.directory(entity)}/custom/${file}`
140
- : `services/custom/${file}`;
139
+ ? `${this.featuresDir(entity)}/custom/${file}`
140
+ : `${this.layered("services")}/custom/${file}`;
141
141
  }
142
142
 
143
143
  serviceTest(entity: string): string {
144
144
  const file = `${this.serviceStem(entity)}.test.ts`;
145
145
  const path = this.organizeByFeature
146
- ? `features/${this.casing.directory(entity)}/__tests__/${file}`
146
+ ? `${this.featuresDir(entity)}/__tests__/${file}`
147
147
  : file;
148
148
  return this.underBase(path);
149
149
  }
150
150
 
151
151
  serviceTestRel(entity: string): string {
152
- return this.rel("services/generated/__tests__", this.serviceTest(entity));
152
+ return this.rel(this.layered("services/generated/__tests__"), this.serviceTest(entity));
153
153
  }
154
154
 
155
155
  serviceIntegrationTest(entity: string): string {
@@ -158,7 +158,7 @@ export class TypeScriptImportGenerator implements IImportGenerator {
158
158
 
159
159
  serviceIntegrationTestRel(entity: string): string {
160
160
  return this.rel(
161
- "services/generated/__tests__",
161
+ this.layered("services/generated/__tests__"),
162
162
  this.serviceIntegrationTest(entity),
163
163
  );
164
164
  }
@@ -178,7 +178,7 @@ export class TypeScriptImportGenerator implements IImportGenerator {
178
178
  }
179
179
 
180
180
  routeRel(entity: string): string {
181
- return this.rel("routes/generated", this.route(entity));
181
+ return this.rel(this.layered("routes/generated"), this.route(entity));
182
182
  }
183
183
 
184
184
  routeCustom(name: string, module?: string): string {
@@ -188,13 +188,13 @@ export class TypeScriptImportGenerator implements IImportGenerator {
188
188
  routeTest(entity: string): string {
189
189
  const file = `${this.casing.fileBase(entity)}.integration.test.ts`;
190
190
  const path = this.organizeByFeature
191
- ? `features/${this.casing.directory(entity)}/__tests__/${file}`
191
+ ? `${this.featuresDir(entity)}/__tests__/${file}`
192
192
  : file;
193
193
  return this.underBase(path);
194
194
  }
195
195
 
196
196
  routeTestRel(entity: string): string {
197
- return this.rel("routes/generated/__tests__", this.routeTest(entity));
197
+ return this.rel(this.layered("routes/generated/__tests__"), this.routeTest(entity));
198
198
  }
199
199
 
200
200
  enrichment(_targetTable: string): string {
@@ -262,8 +262,8 @@ export class TypeScriptImportGenerator implements IImportGenerator {
262
262
  /** Layered types/services/routes globs, or features when by-feature. Empty when flat. */
263
263
  tsconfigIncludes(): string[] {
264
264
  if (this.flat) return [];
265
- if (this.organizeByFeature) return ["features/**/*.ts"];
266
- return ["types/**/*.ts", "services/**/*.ts", "routes/**/*.ts"];
265
+ if (this.organizeByFeature) return [`${this.casing.convertDirectories("features")}/**/*.ts`];
266
+ return ["types", "services", "routes"].map((layer) => `${this.casing.convertDirectories(layer)}/**/*.ts`);
267
267
  }
268
268
 
269
269
  private rel(prefix: string, file: string): string {
@@ -275,8 +275,23 @@ export class TypeScriptImportGenerator implements IImportGenerator {
275
275
  return `${this.casing.fileBase(stem)}.ts`;
276
276
  }
277
277
 
278
+ private layered(path: string): string {
279
+ return path
280
+ .split("/")
281
+ .map((segment) =>
282
+ segment === "custom" || segment === "__tests__"
283
+ ? segment
284
+ : this.casing.convertDirectories(segment),
285
+ )
286
+ .join("/");
287
+ }
288
+
289
+ private featuresDir(entity: string): string {
290
+ return `${this.casing.convertDirectories("features")}/${this.casing.directory(entity)}`;
291
+ }
292
+
278
293
  private featurePath(entity: string, file: string): string {
279
- return `features/${this.casing.directory(entity)}/${file}`;
294
+ return `${this.featuresDir(entity)}/${file}`;
280
295
  }
281
296
 
282
297
  private serviceStem(entity: string): string {
@@ -291,7 +306,7 @@ export class TypeScriptImportGenerator implements IImportGenerator {
291
306
  private viewLike(entity: string, featureExt: string): string {
292
307
  const file = `${this.casing.fileBase(entity)}${this.organizeByFeature ? featureExt : ""}.ts`;
293
308
  return this.organizeByFeature
294
- ? `features/${this.casing.directory(entity)}/${file}`
309
+ ? `${this.featuresDir(entity)}/${file}`
295
310
  : file;
296
311
  }
297
312
 
@@ -310,7 +325,7 @@ export class TypeScriptImportGenerator implements IImportGenerator {
310
325
  ? this.tsFile(name)
311
326
  : `${this.casing.fileBase(`${name}_route`)}.ts`;
312
327
  const defaultStub = this.organizeByFeature
313
- ? `features/${this.casing.directory(name)}/custom/${file}`
328
+ ? `${this.featuresDir(name)}/custom/${file}`
314
329
  : `../custom/${file}`;
315
330
  if (this.organizeByFeature) {
316
331
  if (
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@deterministic-code/datasources-cli",
3
- "version": "0.1.13",
3
+ "version": "0.1.14",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "datasources": "./bin/datasources.mjs"
@@ -13,7 +13,7 @@
13
13
  "access": "public"
14
14
  },
15
15
  "dependencies": {
16
- "@deterministic-code/datasources-code-generators": "0.1.2",
16
+ "@deterministic-code/datasources-code-generators": "0.1.14",
17
17
  "@deterministic-code/generators-common": "0.0.1",
18
18
  "@deterministic-code/deterministic-generators-common": "0.1.0",
19
19
  "@deterministic-code/typescript-generators": "0.0.1",