@researchdatabox/redbox-dev-tools 0.0.1 → 5.0.0-RC1
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.
- package/README.md +259 -14
- package/bin/cli.js +3 -0
- package/bin/run-hook-mocha.js +3 -0
- package/bin/run-hook-tsc.js +3 -0
- package/bin/wrapper-webpack.js +168 -0
- package/config/tsconfig.base.json +16 -0
- package/dist/bin/run-hook-mocha.d.ts +1 -0
- package/dist/bin/run-hook-mocha.js +49 -0
- package/dist/bin/run-hook-tsc.d.ts +1 -0
- package/dist/bin/run-hook-tsc.js +19 -0
- package/dist/cli-parsers.d.ts +9 -0
- package/dist/cli-parsers.js +131 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +495 -0
- package/dist/commands/form-config.d.ts +6 -0
- package/dist/commands/form-config.js +401 -0
- package/dist/commands/sync-translation.d.ts +23 -0
- package/dist/commands/sync-translation.js +348 -0
- package/dist/completion/index.d.ts +1 -0
- package/dist/completion/index.js +218 -0
- package/dist/generators/add-method.d.ts +27 -0
- package/dist/generators/add-method.js +235 -0
- package/dist/generators/angular-app.d.ts +24 -0
- package/dist/generators/angular-app.js +342 -0
- package/dist/generators/angular-service.d.ts +21 -0
- package/dist/generators/angular-service.js +154 -0
- package/dist/generators/controller.d.ts +40 -0
- package/dist/generators/controller.js +195 -0
- package/dist/generators/form-component.d.ts +46 -0
- package/dist/generators/form-component.js +906 -0
- package/dist/generators/form-field.d.ts +15 -0
- package/dist/generators/form-field.js +160 -0
- package/dist/generators/migration.d.ts +15 -0
- package/dist/generators/migration.js +100 -0
- package/dist/generators/model.d.ts +42 -0
- package/dist/generators/model.js +206 -0
- package/dist/generators/service.d.ts +16 -0
- package/dist/generators/service.js +111 -0
- package/dist/runtime-resolver.d.ts +3 -0
- package/dist/runtime-resolver.js +27 -0
- package/dist/templates/hook-archetype.d.ts +12 -0
- package/dist/templates/hook-archetype.js +187 -0
- package/dist/testing.d.ts +7 -0
- package/dist/testing.js +53 -0
- package/dist/utils/config-helper.d.ts +71 -0
- package/dist/utils/config-helper.js +574 -0
- package/dist/utils/generator.d.ts +10 -0
- package/dist/utils/generator.js +68 -0
- package/dist/utils/hook-tsconfig.d.ts +9 -0
- package/dist/utils/hook-tsconfig.js +104 -0
- package/dist/utils/paths.d.ts +10 -0
- package/dist/utils/paths.js +60 -0
- package/index.js +4 -0
- package/package.json +76 -19
- package/runtime-resolver.d.ts +1 -0
- package/runtime-resolver.js +3 -0
- package/skills/redbox-angular-apps/SKILL.md +42 -0
- package/skills/redbox-angular-services/SKILL.md +29 -0
- package/skills/redbox-controllers/SKILL.md +65 -0
- package/skills/redbox-feature-design-planner/SKILL.md +169 -0
- package/skills/redbox-feature-implementation-review/SKILL.md +117 -0
- package/skills/redbox-form-components/SKILL.md +114 -0
- package/skills/redbox-form-config/SKILL.md +34 -0
- package/skills/redbox-hook-development/SKILL.md +66 -0
- package/skills/redbox-services/SKILL.md +54 -0
- package/skills/redbox-test-verification/SKILL.md +38 -0
- package/skills/redbox-testing/SKILL.md +64 -0
- package/skills/redbox-web-verification/SKILL.md +71 -0
- package/skills/redbox-web-verification/redbox-angular-apps/SKILL.md +48 -0
- package/skills/redbox-web-verification/redbox-angular-services/SKILL.md +30 -0
- package/skills/redbox-web-verification/redbox-controllers/SKILL.md +56 -0
- package/skills/redbox-web-verification/redbox-form-config/SKILL.md +29 -0
- package/skills/redbox-web-verification/redbox-hook-development/SKILL.md +61 -0
- package/skills/redbox-web-verification/redbox-services/SKILL.md +45 -0
- package/skills/redbox-web-verification/redbox-testing/SKILL.md +53 -0
- package/skills/redbox-web-verification/redbox-web-verification/SKILL.md +47 -0
- package/templates/hook-archetype/standard/.gitignore.hbs +5 -0
- package/templates/hook-archetype/standard/.npmignore.hbs +4 -0
- package/templates/hook-archetype/standard/.npmrc.hbs +6 -0
- package/templates/hook-archetype/standard/.nvmrc.hbs +1 -0
- package/templates/hook-archetype/standard/AGENTS.md.hbs +51 -0
- package/templates/hook-archetype/standard/Dockerfile.hbs +29 -0
- package/templates/hook-archetype/standard/README.md.hbs +57 -0
- package/templates/hook-archetype/standard/assets/default/.gitkeep +1 -0
- package/templates/hook-archetype/standard/assets/fonts/.gitkeep +1 -0
- package/templates/hook-archetype/standard/assets/images/.gitkeep +1 -0
- package/templates/hook-archetype/standard/assets/styles/.gitkeep +1 -0
- package/templates/hook-archetype/standard/language-defaults/.gitkeep +1 -0
- package/templates/hook-archetype/standard/language-defaults/README.md.hbs +10 -0
- package/templates/hook-archetype/standard/language-defaults/en/translation.json.hbs +3 -0
- package/templates/hook-archetype/standard/language-defaults/meta.json.hbs +6 -0
- package/templates/hook-archetype/standard/package.json.hbs +44 -0
- package/templates/hook-archetype/standard/src/api/controllers/ExampleController.ts.hbs +21 -0
- package/templates/hook-archetype/standard/src/api/controllers/index.ts.hbs +23 -0
- package/templates/hook-archetype/standard/src/api/services/ExampleService.ts.hbs +22 -0
- package/templates/hook-archetype/standard/src/api/services/index.ts.hbs +23 -0
- package/templates/hook-archetype/standard/src/config/brandingConfigurationDefaults.ts.hbs +9 -0
- package/templates/hook-archetype/standard/src/config/reusableFormDefinitions.ts.hbs +6 -0
- package/templates/hook-archetype/standard/src/form-config/default-1.0-draft.ts.hbs +20 -0
- package/templates/hook-archetype/standard/src/form-config/index.ts.hbs +8 -0
- package/templates/hook-archetype/standard/src/index.ts.hbs +55 -0
- package/templates/hook-archetype/standard/src/migrations/index.ts.hbs +19 -0
- package/templates/hook-archetype/standard/support/bootstrap-data/.gitkeep +1 -0
- package/templates/hook-archetype/standard/support/bootstrap-data/namedqueries/.gitkeep +1 -0
- package/templates/hook-archetype/standard/support/bootstrap-data/records/.gitkeep +1 -0
- package/templates/hook-archetype/standard/support/bootstrap-data/reports/.gitkeep +1 -0
- package/templates/hook-archetype/standard/support/bootstrap-data/vocabularies/.gitkeep +1 -0
- package/templates/hook-archetype/standard/support/development/core-mount.env.hbs +3 -0
- package/templates/hook-archetype/standard/support/development/docker-compose.core-mount.yml.hbs +37 -0
- package/templates/hook-archetype/standard/support/development/docker-compose.yml.hbs +108 -0
- package/templates/hook-archetype/standard/support/development/prepare-core-mount.sh.hbs +61 -0
- package/templates/hook-archetype/standard/support/integration-testing/docker-compose.mocha.yml.hbs +118 -0
- package/templates/hook-archetype/standard/support/integration-testing/run-mocha-hook.sh.hbs +14 -0
- package/templates/hook-archetype/standard/support/integration-testing/run-mocha-redbox.sh.hbs +100 -0
- package/templates/hook-archetype/standard/support/prepare-minio.sh.hbs +74 -0
- package/templates/hook-archetype/standard/test/integration/hook-registration.test.ts.hbs +15 -0
- package/templates/hook-archetype/standard/test/support/globals.ts.hbs +40 -0
- package/templates/hook-archetype/standard/test/tsconfig.json.hbs +8 -0
- package/templates/hook-archetype/standard/test/unit/.mocharc.cjs.hbs +9 -0
- package/templates/hook-archetype/standard/test/unit/index.test.ts.hbs +46 -0
- package/templates/hook-archetype/standard/tsconfig.json.hbs +15 -0
- package/templates/hook-archetype/standard/views/.gitkeep +1 -0
- package/templates/hook-archetype/standard/views/default/.gitkeep +1 -0
- package/testing.d.ts +1 -0
- package/testing.js +3 -0
- package/.travis.yml +0 -23
- package/commands/initProject.js +0 -129
- package/redbox-dev-tools +0 -70
- package/yarn.lock +0 -1061
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.AngularServiceGenerator = void 0;
|
|
37
|
+
const path = __importStar(require("path"));
|
|
38
|
+
const fs = __importStar(require("fs"));
|
|
39
|
+
const generator_1 = require("../utils/generator");
|
|
40
|
+
class AngularServiceGenerator extends generator_1.Generator {
|
|
41
|
+
app;
|
|
42
|
+
name;
|
|
43
|
+
methods;
|
|
44
|
+
paths;
|
|
45
|
+
constructor(options) {
|
|
46
|
+
super(options);
|
|
47
|
+
this.app = options.app.toLowerCase();
|
|
48
|
+
this.name = options.name.toLowerCase();
|
|
49
|
+
this.methods = options.methods || [];
|
|
50
|
+
this.paths = options.paths;
|
|
51
|
+
}
|
|
52
|
+
async generate() {
|
|
53
|
+
const projectRoot = path.join(this.paths.angular, 'projects', 'researchdatabox', this.app);
|
|
54
|
+
if (!fs.existsSync(projectRoot)) {
|
|
55
|
+
throw new Error(`Angular app project not found at: ${projectRoot}`);
|
|
56
|
+
}
|
|
57
|
+
const serviceClassName = this.toClassName(this.name);
|
|
58
|
+
const fileName = `${this.name}.service.ts`;
|
|
59
|
+
const servicePath = path.join(projectRoot, 'src', 'app', fileName);
|
|
60
|
+
const content = this.generateServiceContent(serviceClassName);
|
|
61
|
+
this.writeFile(servicePath, content);
|
|
62
|
+
}
|
|
63
|
+
generateServiceContent(serviceClassName) {
|
|
64
|
+
const className = `${serviceClassName}Service`;
|
|
65
|
+
let methodsContent = '';
|
|
66
|
+
if (this.methods.length > 0) {
|
|
67
|
+
const methodInfos = this.methods.map(method => ({
|
|
68
|
+
raw: method,
|
|
69
|
+
identifier: this.toSafeMethodName(method)
|
|
70
|
+
}));
|
|
71
|
+
methodsContent = methodInfos.map(method => `
|
|
72
|
+
/**
|
|
73
|
+
* ${this.capitalize(method.identifier)}
|
|
74
|
+
*/
|
|
75
|
+
public async ${method.identifier}(): Promise<any> {
|
|
76
|
+
const url = \`\${this.brandingAndPortalUrl}/app/${this.app}/${method.raw}\`;
|
|
77
|
+
const result$ = this.http.get(url, { ...this.reqOptsJsonBodyOnly, context: this.httpContext });
|
|
78
|
+
return await firstValueFrom(result$);
|
|
79
|
+
}
|
|
80
|
+
`).join('\n');
|
|
81
|
+
}
|
|
82
|
+
return `import { Injectable, Inject } from '@angular/core';
|
|
83
|
+
import { HttpClient } from '@angular/common/http';
|
|
84
|
+
import { APP_BASE_HREF } from '@angular/common';
|
|
85
|
+
import { HttpClientService, ConfigService, UtilityService } from '@researchdatabox/portal-ng-common';
|
|
86
|
+
import { firstValueFrom } from 'rxjs';
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* ${serviceClassName} Service
|
|
90
|
+
*
|
|
91
|
+
* Generated by ReDBox Hook Kit
|
|
92
|
+
*/
|
|
93
|
+
@Injectable({
|
|
94
|
+
providedIn: 'root'
|
|
95
|
+
})
|
|
96
|
+
export class ${className} extends HttpClientService {
|
|
97
|
+
|
|
98
|
+
constructor(
|
|
99
|
+
@Inject(HttpClient) http: HttpClient,
|
|
100
|
+
@Inject(APP_BASE_HREF) rootContext: string,
|
|
101
|
+
@Inject(UtilityService) utilService: UtilityService,
|
|
102
|
+
@Inject(ConfigService) configService: ConfigService
|
|
103
|
+
) {
|
|
104
|
+
super(http, rootContext, utilService, configService);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
public override async waitForInit(): Promise<any> {
|
|
108
|
+
await super.waitForInit();
|
|
109
|
+
this.enableCsrfHeader();
|
|
110
|
+
return this;
|
|
111
|
+
}
|
|
112
|
+
${methodsContent}
|
|
113
|
+
}
|
|
114
|
+
`;
|
|
115
|
+
}
|
|
116
|
+
toClassName(name) {
|
|
117
|
+
return name.split('-').map(s => s.charAt(0).toUpperCase() + s.slice(1)).join('');
|
|
118
|
+
}
|
|
119
|
+
capitalize(s) {
|
|
120
|
+
return s.charAt(0).toUpperCase() + s.slice(1);
|
|
121
|
+
}
|
|
122
|
+
isValidTsIdentifier(name) {
|
|
123
|
+
return /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(name);
|
|
124
|
+
}
|
|
125
|
+
toSafeMethodName(method) {
|
|
126
|
+
const trimmed = method.trim();
|
|
127
|
+
if (!trimmed) {
|
|
128
|
+
throw new Error('Method name cannot be empty.');
|
|
129
|
+
}
|
|
130
|
+
if (this.isValidTsIdentifier(trimmed)) {
|
|
131
|
+
return trimmed;
|
|
132
|
+
}
|
|
133
|
+
const parts = trimmed.split(/[^A-Za-z0-9_$]+/).filter(Boolean);
|
|
134
|
+
const camel = parts.map((part, index) => {
|
|
135
|
+
const lower = part.toLowerCase();
|
|
136
|
+
if (index === 0)
|
|
137
|
+
return lower;
|
|
138
|
+
return lower.charAt(0).toUpperCase() + lower.slice(1);
|
|
139
|
+
}).join('');
|
|
140
|
+
let candidate = camel || trimmed.replace(/[^A-Za-z0-9_$]/g, '');
|
|
141
|
+
if (!candidate) {
|
|
142
|
+
throw new Error(`Method name '${method}' cannot be converted to a valid identifier.`);
|
|
143
|
+
}
|
|
144
|
+
if (!/^[A-Za-z_$]/.test(candidate)) {
|
|
145
|
+
candidate = `_${candidate}`;
|
|
146
|
+
}
|
|
147
|
+
if (!this.isValidTsIdentifier(candidate)) {
|
|
148
|
+
throw new Error(`Method name '${method}' cannot be converted to a valid identifier.`);
|
|
149
|
+
}
|
|
150
|
+
console.warn(` [WARN] Sanitized method name '${method}' to '${candidate}'.`);
|
|
151
|
+
return candidate;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
exports.AngularServiceGenerator = AngularServiceGenerator;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { Generator, GeneratorOptions } from '../utils/generator';
|
|
2
|
+
import { RedboxPaths } from '../utils/paths';
|
|
3
|
+
import { NavigationMapping, LanguageDefaultEntry } from '../utils/config-helper';
|
|
4
|
+
export interface RouteMapping {
|
|
5
|
+
action: string;
|
|
6
|
+
verb?: string;
|
|
7
|
+
path: string;
|
|
8
|
+
auth?: string[];
|
|
9
|
+
csrf?: boolean;
|
|
10
|
+
}
|
|
11
|
+
export interface ControllerGeneratorOptions extends GeneratorOptions {
|
|
12
|
+
name: string;
|
|
13
|
+
actions?: string[];
|
|
14
|
+
webservice?: boolean;
|
|
15
|
+
/** @deprecated Use routes instead */
|
|
16
|
+
route?: string;
|
|
17
|
+
routes?: RouteMapping[];
|
|
18
|
+
auth?: string[];
|
|
19
|
+
navigation?: NavigationMapping[];
|
|
20
|
+
languageDefaults?: LanguageDefaultEntry[];
|
|
21
|
+
className?: string;
|
|
22
|
+
paths: RedboxPaths;
|
|
23
|
+
}
|
|
24
|
+
export declare class ControllerGenerator extends Generator {
|
|
25
|
+
private name;
|
|
26
|
+
private className;
|
|
27
|
+
private actions;
|
|
28
|
+
private webservice;
|
|
29
|
+
private routes;
|
|
30
|
+
private auth?;
|
|
31
|
+
private navigation;
|
|
32
|
+
private languageDefaults;
|
|
33
|
+
private paths;
|
|
34
|
+
private project;
|
|
35
|
+
constructor(options: ControllerGeneratorOptions);
|
|
36
|
+
generate(): Promise<void>;
|
|
37
|
+
private generateControllerContent;
|
|
38
|
+
private validateActions;
|
|
39
|
+
private isValidIdentifier;
|
|
40
|
+
}
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.ControllerGenerator = void 0;
|
|
37
|
+
const path = __importStar(require("path"));
|
|
38
|
+
const ts_morph_1 = require("ts-morph");
|
|
39
|
+
const generator_1 = require("../utils/generator");
|
|
40
|
+
const config_helper_1 = require("../utils/config-helper");
|
|
41
|
+
class ControllerGenerator extends generator_1.Generator {
|
|
42
|
+
name;
|
|
43
|
+
className;
|
|
44
|
+
actions;
|
|
45
|
+
webservice;
|
|
46
|
+
routes;
|
|
47
|
+
auth;
|
|
48
|
+
navigation;
|
|
49
|
+
languageDefaults;
|
|
50
|
+
paths;
|
|
51
|
+
project;
|
|
52
|
+
constructor(options) {
|
|
53
|
+
super(options);
|
|
54
|
+
this.name = options.name;
|
|
55
|
+
this.actions = options.actions || [];
|
|
56
|
+
this.webservice = !!options.webservice;
|
|
57
|
+
this.auth = options.auth;
|
|
58
|
+
this.navigation = options.navigation || [];
|
|
59
|
+
this.languageDefaults = options.languageDefaults || [];
|
|
60
|
+
this.paths = options.paths;
|
|
61
|
+
const inferredClassName = this.name.endsWith('Controller') ? this.name.replace('Controller', '') : this.name;
|
|
62
|
+
this.className = options.className || inferredClassName;
|
|
63
|
+
this.project = new ts_morph_1.Project({
|
|
64
|
+
manipulationSettings: {
|
|
65
|
+
quoteKind: ts_morph_1.QuoteKind.Single,
|
|
66
|
+
},
|
|
67
|
+
});
|
|
68
|
+
this.validateActions();
|
|
69
|
+
// Handle backwards compatibility: convert single route to routes array
|
|
70
|
+
if (options.routes && options.routes.length > 0) {
|
|
71
|
+
this.routes = options.routes;
|
|
72
|
+
}
|
|
73
|
+
else if (options.route) {
|
|
74
|
+
// Legacy: single route maps to first action or 'index'
|
|
75
|
+
const action = (this.actions && this.actions.length > 0) ? this.actions[0] : 'index';
|
|
76
|
+
this.routes = [{ action, path: options.route, verb: 'get' }];
|
|
77
|
+
}
|
|
78
|
+
else {
|
|
79
|
+
this.routes = [];
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
async generate() {
|
|
83
|
+
const controllerName = this.name.endsWith('Controller') ? this.name : `${this.name}Controller`;
|
|
84
|
+
const className = this.className;
|
|
85
|
+
const controllerDir = path.join(this.paths.coreTypes, 'src', 'controllers', this.webservice ? 'webservice' : '');
|
|
86
|
+
const controllerPath = path.join(controllerDir, `${controllerName}.ts`);
|
|
87
|
+
const content = this.generateControllerContent(className);
|
|
88
|
+
this.writeFile(controllerPath, content);
|
|
89
|
+
if (!this.dryRun) {
|
|
90
|
+
await (0, config_helper_1.updateControllerIndex)({
|
|
91
|
+
project: this.project,
|
|
92
|
+
paths: this.paths,
|
|
93
|
+
root: this.root,
|
|
94
|
+
controllerName: controllerName,
|
|
95
|
+
className: className,
|
|
96
|
+
webservice: this.webservice,
|
|
97
|
+
dryRun: this.dryRun
|
|
98
|
+
});
|
|
99
|
+
// Process each route mapping
|
|
100
|
+
for (const routeMapping of this.routes) {
|
|
101
|
+
const routeKey = routeMapping.verb
|
|
102
|
+
? `${routeMapping.verb.toLowerCase()} ${routeMapping.path}`
|
|
103
|
+
: routeMapping.path;
|
|
104
|
+
await (0, config_helper_1.updateRoutes)({
|
|
105
|
+
project: this.project,
|
|
106
|
+
paths: this.paths,
|
|
107
|
+
root: this.root,
|
|
108
|
+
route: routeKey,
|
|
109
|
+
controllerName: controllerName,
|
|
110
|
+
action: routeMapping.action,
|
|
111
|
+
webservice: this.webservice,
|
|
112
|
+
csrf: routeMapping.csrf,
|
|
113
|
+
dryRun: this.dryRun
|
|
114
|
+
});
|
|
115
|
+
// Apply auth rules: use route-specific auth if provided, otherwise controller-level auth
|
|
116
|
+
const routeAuth = routeMapping.auth || this.auth;
|
|
117
|
+
if (routeAuth && routeAuth.length > 0) {
|
|
118
|
+
await (0, config_helper_1.updateAuth)({
|
|
119
|
+
project: this.project,
|
|
120
|
+
paths: this.paths,
|
|
121
|
+
root: this.root,
|
|
122
|
+
route: routeKey,
|
|
123
|
+
auth: routeAuth,
|
|
124
|
+
dryRun: this.dryRun
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
if (this.navigation.length > 0) {
|
|
129
|
+
for (const nav of this.navigation) {
|
|
130
|
+
const actionName = nav.action || (this.routes.length === 1 ? this.routes[0].action : (this.actions.length === 1 ? this.actions[0] : undefined));
|
|
131
|
+
if (!actionName) {
|
|
132
|
+
console.warn(' [NAV] Navigation mapping missing action and cannot be inferred. Skipping.');
|
|
133
|
+
continue;
|
|
134
|
+
}
|
|
135
|
+
const routeMapping = this.routes.find(r => r.action === actionName);
|
|
136
|
+
if (!routeMapping) {
|
|
137
|
+
console.warn(` [NAV] No route mapping found for action '${actionName}'. Skipping.`);
|
|
138
|
+
continue;
|
|
139
|
+
}
|
|
140
|
+
await (0, config_helper_1.updateNavigationConfig)({
|
|
141
|
+
project: this.project,
|
|
142
|
+
paths: this.paths,
|
|
143
|
+
root: this.root,
|
|
144
|
+
mapping: {
|
|
145
|
+
...nav,
|
|
146
|
+
href: routeMapping.path
|
|
147
|
+
},
|
|
148
|
+
dryRun: this.dryRun
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
if (this.languageDefaults.length > 0) {
|
|
153
|
+
await (0, config_helper_1.updateLanguageDefaults)({
|
|
154
|
+
root: this.root,
|
|
155
|
+
entries: this.languageDefaults,
|
|
156
|
+
dryRun: this.dryRun
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
generateControllerContent(className) {
|
|
162
|
+
const importPath = this.webservice ? '../../index' : '../index';
|
|
163
|
+
const actionsCode = this.actions.map(action => `
|
|
164
|
+
public async ${action}(req: Sails.Req, res: Sails.Res): Promise<unknown> {
|
|
165
|
+
return this.sendResp(req, res, { data: { message: 'Action ${action} in ${className}' } });
|
|
166
|
+
}`).join('\n');
|
|
167
|
+
const exportedMethods = ['init', ...this.actions].map(a => `'${a}'`).join(',\n ');
|
|
168
|
+
return `import { Controllers as controllers } from '${importPath}';
|
|
169
|
+
|
|
170
|
+
export namespace Controllers {
|
|
171
|
+
export class ${className} extends controllers.Core.Controller {
|
|
172
|
+
|
|
173
|
+
protected override _exportedMethods: string[] = [
|
|
174
|
+
${exportedMethods}
|
|
175
|
+
];
|
|
176
|
+
|
|
177
|
+
public init(): void {
|
|
178
|
+
// Initialize services here
|
|
179
|
+
}
|
|
180
|
+
${actionsCode}
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
`;
|
|
184
|
+
}
|
|
185
|
+
validateActions() {
|
|
186
|
+
const invalidActions = this.actions.filter(action => !this.isValidIdentifier(action));
|
|
187
|
+
if (invalidActions.length > 0) {
|
|
188
|
+
throw new Error(`Invalid action name(s): ${invalidActions.join(', ')}`);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
isValidIdentifier(name) {
|
|
192
|
+
return /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(name);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
exports.ControllerGenerator = ControllerGenerator;
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { Generator, GeneratorOptions } from '../utils/generator';
|
|
2
|
+
import { RedboxPaths } from '../utils/paths';
|
|
3
|
+
export interface FormComponentGeneratorOptions extends GeneratorOptions {
|
|
4
|
+
name: string;
|
|
5
|
+
app?: string;
|
|
6
|
+
withService?: boolean;
|
|
7
|
+
paths: RedboxPaths;
|
|
8
|
+
}
|
|
9
|
+
export declare class FormComponentGenerator extends Generator {
|
|
10
|
+
private readonly rawName;
|
|
11
|
+
private readonly app;
|
|
12
|
+
private readonly withService;
|
|
13
|
+
private readonly paths;
|
|
14
|
+
private readonly kebabName;
|
|
15
|
+
private readonly pascalName;
|
|
16
|
+
private readonly componentClassName;
|
|
17
|
+
private readonly modelClassName;
|
|
18
|
+
private readonly componentNameConstant;
|
|
19
|
+
private readonly modelNameConstant;
|
|
20
|
+
constructor(options: FormComponentGeneratorOptions);
|
|
21
|
+
generate(): Promise<void>;
|
|
22
|
+
private toKebabCase;
|
|
23
|
+
private toPascalCase;
|
|
24
|
+
private readFile;
|
|
25
|
+
private updateTextFile;
|
|
26
|
+
private insertBeforeMarker;
|
|
27
|
+
private ensureImport;
|
|
28
|
+
private appendToObjectLiteral;
|
|
29
|
+
private appendToArrayLiteral;
|
|
30
|
+
private findMatchingDelimiter;
|
|
31
|
+
private generateSailsNgCommonComponentFiles;
|
|
32
|
+
private generateAngularComponentFiles;
|
|
33
|
+
private generateAngularServiceFiles;
|
|
34
|
+
private updateSailsNgCommonDictionaries;
|
|
35
|
+
private updateSailsNgCommonIndex;
|
|
36
|
+
private updateBaseVisitors;
|
|
37
|
+
private updateConcreteVisitors;
|
|
38
|
+
private updateClientVisitor;
|
|
39
|
+
private updateDataValueVisitor;
|
|
40
|
+
private updateJsonTypeDefVisitor;
|
|
41
|
+
private updateValidatorVisitor;
|
|
42
|
+
private updateTemplateVisitor;
|
|
43
|
+
private updateConstructVisitor;
|
|
44
|
+
private updateMigrateVisitor;
|
|
45
|
+
private updateAngularWiring;
|
|
46
|
+
}
|