@researchdatabox/redbox-dev-tools 0.0.1-beta.8936
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 +255 -0
- 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 +145 -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 +464 -0
- package/dist/commands/form-config.d.ts +5 -0
- package/dist/commands/form-config.js +194 -0
- package/dist/completion/index.d.ts +1 -0
- package/dist/completion/index.js +217 -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/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 +143 -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 +85 -0
- 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 +4 -0
- package/templates/hook-archetype/standard/.npmignore.hbs +3 -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 +34 -0
- package/templates/hook-archetype/standard/Dockerfile.hbs +28 -0
- package/templates/hook-archetype/standard/README.md.hbs +39 -0
- package/templates/hook-archetype/standard/assets/fonts/.gitkeep +1 -0
- package/templates/hook-archetype/standard/language-defaults/.gitkeep +1 -0
- package/templates/hook-archetype/standard/package.json.hbs +40 -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/support/bootstrap-data/.gitkeep +1 -0
- package/templates/hook-archetype/standard/support/development/docker-compose.yml.hbs +75 -0
- package/templates/hook-archetype/standard/support/integration-testing/docker-compose.mocha.yml.hbs +84 -0
- package/templates/hook-archetype/standard/support/integration-testing/run-mocha-hook.sh.hbs +9 -0
- package/templates/hook-archetype/standard/test/integration/hook-registration.test.ts.hbs +13 -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 +40 -0
- package/templates/hook-archetype/standard/tsconfig.json.hbs +15 -0
- package/templates/hook-archetype/standard/views/.gitkeep +1 -0
- package/testing.d.ts +1 -0
- package/testing.js +3 -0
|
@@ -0,0 +1,574 @@
|
|
|
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.updateModelIndex = updateModelIndex;
|
|
37
|
+
exports.updateControllerIndex = updateControllerIndex;
|
|
38
|
+
exports.updateServiceIndex = updateServiceIndex;
|
|
39
|
+
exports.updateRoutes = updateRoutes;
|
|
40
|
+
exports.updateAuth = updateAuth;
|
|
41
|
+
exports.updateNavigationConfig = updateNavigationConfig;
|
|
42
|
+
exports.updateLanguageDefaults = updateLanguageDefaults;
|
|
43
|
+
const path = __importStar(require("path"));
|
|
44
|
+
const fs = __importStar(require("fs"));
|
|
45
|
+
const ts_morph_1 = require("ts-morph");
|
|
46
|
+
async function updateModelIndex(params) {
|
|
47
|
+
const indexPath = path.join(params.paths.coreTypes, 'src', 'waterline-models', 'index.ts');
|
|
48
|
+
if (!fs.existsSync(indexPath))
|
|
49
|
+
return;
|
|
50
|
+
const sourceFile = params.project.addSourceFileAtPath(indexPath);
|
|
51
|
+
const wlDefName = `${params.modelName}WLDef`;
|
|
52
|
+
const importPath = `./${params.modelName}`;
|
|
53
|
+
// 1. Add export * from './ModelName' if not exists
|
|
54
|
+
const hasExportAll = sourceFile.getExportDeclarations().some(d => d.getModuleSpecifierValue() === importPath && d.isNamespaceExport());
|
|
55
|
+
if (!hasExportAll) {
|
|
56
|
+
// Find the last export * line and insert after it
|
|
57
|
+
const exportAllDeclarations = sourceFile.getExportDeclarations().filter(d => d.isNamespaceExport());
|
|
58
|
+
if (exportAllDeclarations.length > 0) {
|
|
59
|
+
const lastExportAll = exportAllDeclarations[exportAllDeclarations.length - 1];
|
|
60
|
+
sourceFile.insertExportDeclaration(lastExportAll.getChildIndex() + 1, {
|
|
61
|
+
moduleSpecifier: importPath
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
else {
|
|
65
|
+
sourceFile.addExportDeclaration({
|
|
66
|
+
moduleSpecifier: importPath
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
// 2. Add named import for the WLDef if not exists
|
|
71
|
+
const existingImport = sourceFile.getImportDeclaration(d => d.getModuleSpecifierValue() === importPath);
|
|
72
|
+
if (!existingImport) {
|
|
73
|
+
// Find where the WLDef imports are and add there
|
|
74
|
+
const wlDefImports = sourceFile.getImportDeclarations().filter(d => {
|
|
75
|
+
const namedImports = d.getNamedImports();
|
|
76
|
+
return namedImports.some(n => n.getName().endsWith('WLDef'));
|
|
77
|
+
});
|
|
78
|
+
if (wlDefImports.length > 0) {
|
|
79
|
+
const lastWlDefImport = wlDefImports[wlDefImports.length - 1];
|
|
80
|
+
sourceFile.insertImportDeclaration(lastWlDefImport.getChildIndex() + 1, {
|
|
81
|
+
namedImports: [wlDefName],
|
|
82
|
+
moduleSpecifier: importPath
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
else {
|
|
86
|
+
sourceFile.addImportDeclaration({
|
|
87
|
+
namedImports: [wlDefName],
|
|
88
|
+
moduleSpecifier: importPath
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
// 3. Add to WaterlineModels object if not exists
|
|
93
|
+
const wlModelsVar = sourceFile.getVariableDeclaration('WaterlineModels');
|
|
94
|
+
if (wlModelsVar) {
|
|
95
|
+
const initializer = wlModelsVar.getInitializerIfKind(ts_morph_1.SyntaxKind.ObjectLiteralExpression);
|
|
96
|
+
if (initializer && !initializer.getProperty(params.modelName)) {
|
|
97
|
+
initializer.addPropertyAssignment({
|
|
98
|
+
name: params.modelName,
|
|
99
|
+
initializer: wlDefName
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
sourceFile.formatText();
|
|
104
|
+
if (!params.dryRun) {
|
|
105
|
+
await sourceFile.save();
|
|
106
|
+
console.log(` [UPDATE] ${path.relative(params.root, indexPath)}`);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
async function updateControllerIndex(params) {
|
|
110
|
+
const indexPath = path.join(params.paths.coreTypes, 'src', 'controllers', 'index.ts');
|
|
111
|
+
if (!fs.existsSync(indexPath))
|
|
112
|
+
return;
|
|
113
|
+
const sourceFile = params.project.addSourceFileAtPath(indexPath);
|
|
114
|
+
const moduleName = params.webservice ? `WS${params.className}ControllerModule` : `${params.className}ControllerModule`;
|
|
115
|
+
const importPath = params.webservice ? `./webservice/${params.className}Controller` : `./${params.className}Controller`;
|
|
116
|
+
// 1. Add import if not exists
|
|
117
|
+
if (!sourceFile.getImportDeclaration(d => d.getModuleSpecifierValue() === importPath)) {
|
|
118
|
+
sourceFile.addImportDeclaration({
|
|
119
|
+
namespaceImport: moduleName,
|
|
120
|
+
moduleSpecifier: importPath
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
// 2. Add to ControllerExports or WebserviceControllerExports
|
|
124
|
+
const exportVarName = params.webservice ? 'WebserviceControllerExports' : 'ControllerExports';
|
|
125
|
+
const exportVar = sourceFile.getVariableDeclaration(exportVarName);
|
|
126
|
+
if (exportVar) {
|
|
127
|
+
const initializer = exportVar.getInitializerIfKind(ts_morph_1.SyntaxKind.ObjectLiteralExpression);
|
|
128
|
+
if (initializer && !initializer.getProperty(params.controllerName)) {
|
|
129
|
+
const cachePrefix = params.webservice ? 'WS_' : '';
|
|
130
|
+
initializer.addGetAccessor({
|
|
131
|
+
name: params.controllerName,
|
|
132
|
+
returnType: 'any',
|
|
133
|
+
statements: `return getOrCreate('${cachePrefix}${params.controllerName}', () => new ${moduleName}.Controllers.${params.className}().exports());`
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
// 3. Add to ControllerNames or WebserviceControllerNames
|
|
138
|
+
const namesVarName = params.webservice ? 'WebserviceControllerNames' : 'ControllerNames';
|
|
139
|
+
const namesVar = sourceFile.getVariableDeclaration(namesVarName);
|
|
140
|
+
if (namesVar) {
|
|
141
|
+
const initializer = namesVar.getInitializerIfKind(ts_morph_1.SyntaxKind.ArrayLiteralExpression);
|
|
142
|
+
if (initializer && !initializer.getElements().some((e) => e.getText() === `'${params.controllerName}'`)) {
|
|
143
|
+
initializer.addElement(`'${params.controllerName}'`);
|
|
144
|
+
// Sort elements
|
|
145
|
+
const elements = initializer.getElements().map((e) => e.getText());
|
|
146
|
+
elements.sort();
|
|
147
|
+
// Re-add all elements sorted
|
|
148
|
+
while (initializer.getElements().length > 0) {
|
|
149
|
+
initializer.removeElement(0);
|
|
150
|
+
}
|
|
151
|
+
elements.forEach(el => initializer.addElement(el));
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
sourceFile.formatText();
|
|
155
|
+
if (!params.dryRun) {
|
|
156
|
+
await sourceFile.save();
|
|
157
|
+
console.log(` [UPDATE] ${path.relative(params.root, indexPath)}`);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
async function updateServiceIndex(params) {
|
|
161
|
+
const indexPath = path.join(params.paths.coreTypes, 'src', 'services', 'index.ts');
|
|
162
|
+
if (!fs.existsSync(indexPath))
|
|
163
|
+
return;
|
|
164
|
+
const sourceFile = params.project.addSourceFileAtPath(indexPath);
|
|
165
|
+
const moduleName = `${params.className}ServiceModule`;
|
|
166
|
+
const importPath = `./${params.serviceName}`;
|
|
167
|
+
// 1. Add import if not exists
|
|
168
|
+
if (!sourceFile.getImportDeclaration(d => d.getModuleSpecifierValue() === importPath)) {
|
|
169
|
+
sourceFile.addImportDeclaration({
|
|
170
|
+
namespaceImport: moduleName,
|
|
171
|
+
moduleSpecifier: importPath
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
// 2. Add re-export if not exists
|
|
175
|
+
const exportDeclaration = sourceFile.getExportDeclaration(d => d.getModuleSpecifierValue() === importPath);
|
|
176
|
+
if (!exportDeclaration) {
|
|
177
|
+
sourceFile.addExportDeclaration({
|
|
178
|
+
namedExports: [{ name: moduleName, alias: params.serviceName }],
|
|
179
|
+
moduleSpecifier: importPath
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
// 3. Add to ServiceExports
|
|
183
|
+
const exportVar = sourceFile.getVariableDeclaration('ServiceExports');
|
|
184
|
+
if (exportVar) {
|
|
185
|
+
const initializer = exportVar.getInitializerIfKind(ts_morph_1.SyntaxKind.ObjectLiteralExpression);
|
|
186
|
+
if (initializer && !initializer.getProperty(params.serviceName)) {
|
|
187
|
+
initializer.addGetAccessor({
|
|
188
|
+
name: params.serviceName,
|
|
189
|
+
statements: `return getOrCreateService('${params.serviceName}', () => new ${moduleName}.Services.${params.className}().exports());`
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
sourceFile.formatText();
|
|
194
|
+
if (!params.dryRun) {
|
|
195
|
+
await sourceFile.save();
|
|
196
|
+
console.log(` [UPDATE] ${path.relative(params.root, indexPath)}`);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
async function updateRoutes(params) {
|
|
200
|
+
const routesPath = path.join(params.paths.coreTypes, 'src', 'config', 'routes.config.ts');
|
|
201
|
+
if (!fs.existsSync(routesPath))
|
|
202
|
+
return;
|
|
203
|
+
const sourceFile = params.project.addSourceFileAtPath(routesPath);
|
|
204
|
+
const routesVar = sourceFile.getVariableDeclaration('routes');
|
|
205
|
+
if (!routesVar)
|
|
206
|
+
return;
|
|
207
|
+
const initializer = routesVar.getInitializerIfKind(ts_morph_1.SyntaxKind.ObjectLiteralExpression);
|
|
208
|
+
if (!initializer)
|
|
209
|
+
return;
|
|
210
|
+
let routeKey = params.route;
|
|
211
|
+
if (!routeKey.includes(' ')) {
|
|
212
|
+
routeKey = `get ${routeKey}`;
|
|
213
|
+
}
|
|
214
|
+
if (!initializer.getProperty(`'${routeKey}'`) && !initializer.getProperty(`"${routeKey}"`)) {
|
|
215
|
+
const target = params.webservice ? `webservice/${params.controllerName}` : params.controllerName;
|
|
216
|
+
const csrf = typeof params.csrf === 'boolean' ? params.csrf : (params.webservice ? false : undefined);
|
|
217
|
+
if (params.webservice || typeof csrf === 'boolean') {
|
|
218
|
+
const props = [
|
|
219
|
+
`controller: '${target}'`,
|
|
220
|
+
`action: '${params.action}'`,
|
|
221
|
+
...(typeof csrf === 'boolean' ? [`csrf: ${csrf}`] : [])
|
|
222
|
+
];
|
|
223
|
+
initializer.addPropertyAssignment({
|
|
224
|
+
name: `'${routeKey}'`,
|
|
225
|
+
initializer: `{ ${props.join(', ')} }`
|
|
226
|
+
});
|
|
227
|
+
}
|
|
228
|
+
else {
|
|
229
|
+
initializer.addPropertyAssignment({
|
|
230
|
+
name: `'${routeKey}'`,
|
|
231
|
+
initializer: `'${target}.${params.action}'`
|
|
232
|
+
});
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
sourceFile.formatText();
|
|
236
|
+
if (!params.dryRun) {
|
|
237
|
+
await sourceFile.save();
|
|
238
|
+
console.log(` [UPDATE] ${path.relative(params.root, routesPath)}`);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
async function updateAuth(params) {
|
|
242
|
+
const authPath = path.join(params.paths.coreTypes, 'src', 'config', 'auth.config.ts');
|
|
243
|
+
if (!fs.existsSync(authPath))
|
|
244
|
+
return;
|
|
245
|
+
const sourceFile = params.project.addSourceFileAtPath(authPath);
|
|
246
|
+
const authVar = sourceFile.getVariableDeclaration('auth');
|
|
247
|
+
if (!authVar)
|
|
248
|
+
return;
|
|
249
|
+
const initializer = authVar.getInitializerIfKind(ts_morph_1.SyntaxKind.ObjectLiteralExpression);
|
|
250
|
+
if (!initializer)
|
|
251
|
+
return;
|
|
252
|
+
const rulesProp = initializer.getProperty('rules');
|
|
253
|
+
if (!rulesProp || !rulesProp.asKind(ts_morph_1.SyntaxKind.PropertyAssignment))
|
|
254
|
+
return;
|
|
255
|
+
const rulesArray = rulesProp.asKind(ts_morph_1.SyntaxKind.PropertyAssignment).getInitializerIfKind(ts_morph_1.SyntaxKind.ArrayLiteralExpression);
|
|
256
|
+
if (!rulesArray)
|
|
257
|
+
return;
|
|
258
|
+
// Check existing roles for warning
|
|
259
|
+
const authRolesProp = initializer.getProperty('roles');
|
|
260
|
+
let existingRoles = [];
|
|
261
|
+
if (authRolesProp && authRolesProp.asKind(ts_morph_1.SyntaxKind.PropertyAssignment)) {
|
|
262
|
+
const rolesArray = authRolesProp.asKind(ts_morph_1.SyntaxKind.PropertyAssignment).getInitializerIfKind(ts_morph_1.SyntaxKind.ArrayLiteralExpression);
|
|
263
|
+
if (rolesArray) {
|
|
264
|
+
existingRoles = rolesArray.getElements().map((el) => {
|
|
265
|
+
if (el.getKind() === ts_morph_1.SyntaxKind.ObjectLiteralExpression) {
|
|
266
|
+
return el.asKind(ts_morph_1.SyntaxKind.ObjectLiteralExpression).getProperty('name')?.asKind(ts_morph_1.SyntaxKind.PropertyAssignment)?.getInitializer()?.getText().replace(/['"]/g, '') || '';
|
|
267
|
+
}
|
|
268
|
+
return '';
|
|
269
|
+
}).filter(r => r !== '');
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
const trimmedRoute = params.route.trim();
|
|
273
|
+
if (!trimmedRoute) {
|
|
274
|
+
throw new Error('Route cannot be empty or whitespace.');
|
|
275
|
+
}
|
|
276
|
+
const routePath = trimmedRoute.split(' ').pop();
|
|
277
|
+
if (!routePath) {
|
|
278
|
+
throw new Error(`Route is missing a path segment: '${trimmedRoute}'.`);
|
|
279
|
+
}
|
|
280
|
+
for (const role of params.auth) {
|
|
281
|
+
if (existingRoles.length > 0 && !existingRoles.includes(role)) {
|
|
282
|
+
console.warn(`Warning: Role '${role}' not found in auth.roles. It will still be added to rules, but may not function as expected.`);
|
|
283
|
+
}
|
|
284
|
+
// Check if rule already exists or is covered by a wildcard
|
|
285
|
+
const isCovered = rulesArray.getElements().some((el) => {
|
|
286
|
+
if (el.getKind() === ts_morph_1.SyntaxKind.ObjectLiteralExpression) {
|
|
287
|
+
const obj = el.asKind(ts_morph_1.SyntaxKind.ObjectLiteralExpression);
|
|
288
|
+
const existingPathRaw = obj.getProperty('path')?.asKind(ts_morph_1.SyntaxKind.PropertyAssignment)?.getInitializer()?.getText();
|
|
289
|
+
const existingRoleRaw = obj.getProperty('role')?.asKind(ts_morph_1.SyntaxKind.PropertyAssignment)?.getInitializer()?.getText();
|
|
290
|
+
if (!existingPathRaw || !existingRoleRaw)
|
|
291
|
+
return false;
|
|
292
|
+
const existingPath = existingPathRaw.replace(/['"]/g, '');
|
|
293
|
+
const existingRole = existingRoleRaw.replace(/['"]/g, '');
|
|
294
|
+
if (existingRole !== role)
|
|
295
|
+
return false;
|
|
296
|
+
// Check path coverage
|
|
297
|
+
let covered = false;
|
|
298
|
+
if (existingPath === routePath) {
|
|
299
|
+
covered = true;
|
|
300
|
+
}
|
|
301
|
+
else if (existingPath.endsWith('(/*)') || existingPath.endsWith('/*')) {
|
|
302
|
+
const baseUrl = existingPath.replace(/(\(\/\*\)|\/\*)$/, '');
|
|
303
|
+
if (routePath.startsWith(baseUrl)) {
|
|
304
|
+
covered = true;
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
if (!covered)
|
|
308
|
+
return false;
|
|
309
|
+
// Check permissions
|
|
310
|
+
const verb = trimmedRoute.includes(' ') ? trimmedRoute.split(' ')[0].toLowerCase() : 'get';
|
|
311
|
+
const requestedAccess = verb === 'get' ? 'read' : 'update';
|
|
312
|
+
const canUpdate = obj.getProperty('can_update')?.asKind(ts_morph_1.SyntaxKind.PropertyAssignment)?.getInitializer()?.getText() === 'true';
|
|
313
|
+
const canRead = obj.getProperty('can_read')?.asKind(ts_morph_1.SyntaxKind.PropertyAssignment)?.getInitializer()?.getText() === 'true';
|
|
314
|
+
if (requestedAccess === 'read') {
|
|
315
|
+
return canRead || canUpdate;
|
|
316
|
+
}
|
|
317
|
+
else {
|
|
318
|
+
return canUpdate;
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
return false;
|
|
322
|
+
});
|
|
323
|
+
if (!isCovered) {
|
|
324
|
+
const verb = trimmedRoute.includes(' ') ? trimmedRoute.split(' ')[0].toLowerCase() : 'get';
|
|
325
|
+
const permission = verb === 'get' ? 'can_read: true' : 'can_update: true';
|
|
326
|
+
console.log(` [AUTH] Adding rule for ${role} -> ${routePath} (${permission})`);
|
|
327
|
+
rulesArray.addElement(`{ path: '${routePath}', role: '${role}', ${permission} }`);
|
|
328
|
+
}
|
|
329
|
+
else {
|
|
330
|
+
console.log(` [AUTH] Rule for ${role} -> ${routePath} already covered by existing rule`);
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
sourceFile.formatText();
|
|
334
|
+
if (!params.dryRun) {
|
|
335
|
+
await sourceFile.save();
|
|
336
|
+
console.log(` [UPDATE] ${path.relative(params.root, authPath)}`);
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
function getStringProp(obj, name) {
|
|
340
|
+
const prop = obj.getProperty(name);
|
|
341
|
+
if (!prop || !prop.asKind(ts_morph_1.SyntaxKind.PropertyAssignment))
|
|
342
|
+
return undefined;
|
|
343
|
+
const initializer = prop.asKind(ts_morph_1.SyntaxKind.PropertyAssignment).getInitializer();
|
|
344
|
+
return initializer ? initializer.getText().replace(/['"]/g, '') : undefined;
|
|
345
|
+
}
|
|
346
|
+
function getArrayProp(obj, name) {
|
|
347
|
+
const prop = obj.getProperty(name);
|
|
348
|
+
if (!prop || !prop.asKind(ts_morph_1.SyntaxKind.PropertyAssignment))
|
|
349
|
+
return undefined;
|
|
350
|
+
return prop.asKind(ts_morph_1.SyntaxKind.PropertyAssignment).getInitializerIfKind(ts_morph_1.SyntaxKind.ArrayLiteralExpression) || undefined;
|
|
351
|
+
}
|
|
352
|
+
function addNavItemToArray(array, item) {
|
|
353
|
+
const hasDuplicate = array.getElements().some((el) => {
|
|
354
|
+
if (el.getKind() !== ts_morph_1.SyntaxKind.ObjectLiteralExpression)
|
|
355
|
+
return false;
|
|
356
|
+
const obj = el.asKind(ts_morph_1.SyntaxKind.ObjectLiteralExpression);
|
|
357
|
+
const existingId = getStringProp(obj, 'id');
|
|
358
|
+
const existingHref = getStringProp(obj, 'href');
|
|
359
|
+
if (item.itemId && existingId === item.itemId)
|
|
360
|
+
return true;
|
|
361
|
+
if (item.href && existingHref === item.href)
|
|
362
|
+
return true;
|
|
363
|
+
return false;
|
|
364
|
+
});
|
|
365
|
+
if (hasDuplicate)
|
|
366
|
+
return false;
|
|
367
|
+
const props = [];
|
|
368
|
+
if (item.itemId)
|
|
369
|
+
props.push(`id: '${item.itemId}'`);
|
|
370
|
+
props.push(`labelKey: '${item.labelKey}'`);
|
|
371
|
+
if (item.href)
|
|
372
|
+
props.push(`href: '${item.href}'`);
|
|
373
|
+
array.addElement(`{ ${props.join(', ')} }`);
|
|
374
|
+
return true;
|
|
375
|
+
}
|
|
376
|
+
function findMenuItemById(array, id) {
|
|
377
|
+
for (const el of array.getElements()) {
|
|
378
|
+
if (el.getKind() !== ts_morph_1.SyntaxKind.ObjectLiteralExpression)
|
|
379
|
+
continue;
|
|
380
|
+
const obj = el.asKind(ts_morph_1.SyntaxKind.ObjectLiteralExpression);
|
|
381
|
+
const itemId = getStringProp(obj, 'id');
|
|
382
|
+
if (itemId === id)
|
|
383
|
+
return obj;
|
|
384
|
+
const childrenArray = getArrayProp(obj, 'children');
|
|
385
|
+
if (childrenArray) {
|
|
386
|
+
const nested = findMenuItemById(childrenArray, id);
|
|
387
|
+
if (nested)
|
|
388
|
+
return nested;
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
return undefined;
|
|
392
|
+
}
|
|
393
|
+
function normalizeNavHref(routePath) {
|
|
394
|
+
if (!routePath)
|
|
395
|
+
return routePath;
|
|
396
|
+
return routePath.replace(/^\/:branding\/:portal(\/|$)/, '/');
|
|
397
|
+
}
|
|
398
|
+
async function updateNavigationConfig(params) {
|
|
399
|
+
const mapping = { ...params.mapping };
|
|
400
|
+
if (mapping.href) {
|
|
401
|
+
mapping.href = normalizeNavHref(mapping.href);
|
|
402
|
+
}
|
|
403
|
+
if (mapping.target === 'menu' || mapping.target === 'menuRoot') {
|
|
404
|
+
const menuPath = path.join(params.paths.coreTypes, 'src', 'configmodels', 'MenuConfig.ts');
|
|
405
|
+
if (!fs.existsSync(menuPath))
|
|
406
|
+
return;
|
|
407
|
+
const sourceFile = params.project.addSourceFileAtPath(menuPath);
|
|
408
|
+
const defaultVar = sourceFile.getVariableDeclaration('DEFAULT_MENU_CONFIG');
|
|
409
|
+
if (!defaultVar)
|
|
410
|
+
return;
|
|
411
|
+
const initializer = defaultVar.getInitializerIfKind(ts_morph_1.SyntaxKind.ObjectLiteralExpression);
|
|
412
|
+
if (!initializer)
|
|
413
|
+
return;
|
|
414
|
+
const itemsArray = getArrayProp(initializer, 'items');
|
|
415
|
+
if (!itemsArray)
|
|
416
|
+
return;
|
|
417
|
+
let targetArray = itemsArray;
|
|
418
|
+
if (mapping.target === 'menu' && mapping.containerId) {
|
|
419
|
+
const parent = findMenuItemById(itemsArray, mapping.containerId);
|
|
420
|
+
if (!parent) {
|
|
421
|
+
console.warn(` [NAV] Menu parent '${mapping.containerId}' not found. Skipping.`);
|
|
422
|
+
return;
|
|
423
|
+
}
|
|
424
|
+
let childrenArray = getArrayProp(parent, 'children');
|
|
425
|
+
if (!childrenArray) {
|
|
426
|
+
parent.addPropertyAssignment({ name: 'children', initializer: '[]' });
|
|
427
|
+
childrenArray = getArrayProp(parent, 'children');
|
|
428
|
+
}
|
|
429
|
+
if (!childrenArray)
|
|
430
|
+
return;
|
|
431
|
+
targetArray = childrenArray;
|
|
432
|
+
}
|
|
433
|
+
const added = addNavItemToArray(targetArray, mapping);
|
|
434
|
+
if (added) {
|
|
435
|
+
sourceFile.formatText();
|
|
436
|
+
if (!params.dryRun) {
|
|
437
|
+
await sourceFile.save();
|
|
438
|
+
console.log(` [UPDATE] ${path.relative(params.root, menuPath)}`);
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
return;
|
|
442
|
+
}
|
|
443
|
+
if (mapping.target === 'homePanel') {
|
|
444
|
+
const homePanelPath = path.join(params.paths.coreTypes, 'src', 'configmodels', 'HomePanelConfig.ts');
|
|
445
|
+
if (!fs.existsSync(homePanelPath))
|
|
446
|
+
return;
|
|
447
|
+
const sourceFile = params.project.addSourceFileAtPath(homePanelPath);
|
|
448
|
+
const defaultVar = sourceFile.getVariableDeclaration('DEFAULT_HOME_PANEL_CONFIG');
|
|
449
|
+
if (!defaultVar)
|
|
450
|
+
return;
|
|
451
|
+
const initializer = defaultVar.getInitializerIfKind(ts_morph_1.SyntaxKind.ObjectLiteralExpression);
|
|
452
|
+
if (!initializer)
|
|
453
|
+
return;
|
|
454
|
+
const panelsArray = getArrayProp(initializer, 'panels');
|
|
455
|
+
if (!panelsArray)
|
|
456
|
+
return;
|
|
457
|
+
if (!mapping.containerId) {
|
|
458
|
+
console.warn(' [NAV] Home panel target requires containerId (panel id). Skipping.');
|
|
459
|
+
return;
|
|
460
|
+
}
|
|
461
|
+
const panel = panelsArray.getElements().find((el) => {
|
|
462
|
+
if (el.getKind() !== ts_morph_1.SyntaxKind.ObjectLiteralExpression)
|
|
463
|
+
return false;
|
|
464
|
+
const obj = el.asKind(ts_morph_1.SyntaxKind.ObjectLiteralExpression);
|
|
465
|
+
return getStringProp(obj, 'id') === mapping.containerId;
|
|
466
|
+
})?.asKind(ts_morph_1.SyntaxKind.ObjectLiteralExpression);
|
|
467
|
+
if (!panel) {
|
|
468
|
+
console.warn(` [NAV] Home panel '${mapping.containerId}' not found. Skipping.`);
|
|
469
|
+
return;
|
|
470
|
+
}
|
|
471
|
+
const itemsArray = getArrayProp(panel, 'items');
|
|
472
|
+
if (!itemsArray)
|
|
473
|
+
return;
|
|
474
|
+
const added = addNavItemToArray(itemsArray, mapping);
|
|
475
|
+
if (added) {
|
|
476
|
+
sourceFile.formatText();
|
|
477
|
+
if (!params.dryRun) {
|
|
478
|
+
await sourceFile.save();
|
|
479
|
+
console.log(` [UPDATE] ${path.relative(params.root, homePanelPath)}`);
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
return;
|
|
483
|
+
}
|
|
484
|
+
if (mapping.target === 'adminSection' || mapping.target === 'adminFooter') {
|
|
485
|
+
const adminPath = path.join(params.paths.coreTypes, 'src', 'configmodels', 'AdminSidebarConfig.ts');
|
|
486
|
+
if (!fs.existsSync(adminPath))
|
|
487
|
+
return;
|
|
488
|
+
const sourceFile = params.project.addSourceFileAtPath(adminPath);
|
|
489
|
+
const defaultVar = sourceFile.getVariableDeclaration('DEFAULT_ADMIN_SIDEBAR_CONFIG');
|
|
490
|
+
if (!defaultVar)
|
|
491
|
+
return;
|
|
492
|
+
const initializer = defaultVar.getInitializerIfKind(ts_morph_1.SyntaxKind.ObjectLiteralExpression);
|
|
493
|
+
if (!initializer)
|
|
494
|
+
return;
|
|
495
|
+
let targetArray;
|
|
496
|
+
if (mapping.target === 'adminFooter') {
|
|
497
|
+
targetArray = getArrayProp(initializer, 'footerLinks');
|
|
498
|
+
}
|
|
499
|
+
else {
|
|
500
|
+
const sectionsArray = getArrayProp(initializer, 'sections');
|
|
501
|
+
if (!sectionsArray)
|
|
502
|
+
return;
|
|
503
|
+
if (!mapping.containerId) {
|
|
504
|
+
console.warn(' [NAV] Admin section target requires containerId (section id). Skipping.');
|
|
505
|
+
return;
|
|
506
|
+
}
|
|
507
|
+
const section = sectionsArray.getElements().find((el) => {
|
|
508
|
+
if (el.getKind() !== ts_morph_1.SyntaxKind.ObjectLiteralExpression)
|
|
509
|
+
return false;
|
|
510
|
+
const obj = el.asKind(ts_morph_1.SyntaxKind.ObjectLiteralExpression);
|
|
511
|
+
return getStringProp(obj, 'id') === mapping.containerId;
|
|
512
|
+
})?.asKind(ts_morph_1.SyntaxKind.ObjectLiteralExpression);
|
|
513
|
+
if (!section) {
|
|
514
|
+
console.warn(` [NAV] Admin section '${mapping.containerId}' not found. Skipping.`);
|
|
515
|
+
return;
|
|
516
|
+
}
|
|
517
|
+
targetArray = getArrayProp(section, 'items');
|
|
518
|
+
}
|
|
519
|
+
if (!targetArray)
|
|
520
|
+
return;
|
|
521
|
+
const added = addNavItemToArray(targetArray, mapping);
|
|
522
|
+
if (added) {
|
|
523
|
+
sourceFile.formatText();
|
|
524
|
+
if (!params.dryRun) {
|
|
525
|
+
await sourceFile.save();
|
|
526
|
+
console.log(` [UPDATE] ${path.relative(params.root, adminPath)}`);
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
return;
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
async function updateLanguageDefaults(params) {
|
|
533
|
+
const defaultsRoot = path.join(params.root, 'language-defaults');
|
|
534
|
+
if (!fs.existsSync(defaultsRoot))
|
|
535
|
+
return;
|
|
536
|
+
const entries = params.entries || [];
|
|
537
|
+
if (entries.length === 0)
|
|
538
|
+
return;
|
|
539
|
+
const languages = fs.readdirSync(defaultsRoot, { withFileTypes: true })
|
|
540
|
+
.filter(dirent => dirent.isDirectory())
|
|
541
|
+
.map(dirent => dirent.name)
|
|
542
|
+
.filter(lang => fs.existsSync(path.join(defaultsRoot, lang, 'translation.json')));
|
|
543
|
+
for (const entry of entries) {
|
|
544
|
+
const targetLangs = entry.language ? [entry.language] : languages;
|
|
545
|
+
for (const lang of targetLangs) {
|
|
546
|
+
const translationPath = path.join(defaultsRoot, lang, 'translation.json');
|
|
547
|
+
if (!fs.existsSync(translationPath))
|
|
548
|
+
continue;
|
|
549
|
+
const raw = fs.readFileSync(translationPath, 'utf8');
|
|
550
|
+
let json = {};
|
|
551
|
+
try {
|
|
552
|
+
json = JSON.parse(raw);
|
|
553
|
+
}
|
|
554
|
+
catch (err) {
|
|
555
|
+
console.warn(` [LANG] Failed to parse ${translationPath}. Skipping.`);
|
|
556
|
+
continue;
|
|
557
|
+
}
|
|
558
|
+
if (Object.prototype.hasOwnProperty.call(json, entry.key)) {
|
|
559
|
+
continue;
|
|
560
|
+
}
|
|
561
|
+
const updated = { ...json, [entry.key]: entry.value };
|
|
562
|
+
const indentMatch = raw.match(/\n(\s+)"[^\"]+"\s*:/);
|
|
563
|
+
const indent = indentMatch ? indentMatch[1] : ' ';
|
|
564
|
+
const output = JSON.stringify(updated, null, indent) + '\n';
|
|
565
|
+
if (params.dryRun) {
|
|
566
|
+
console.log(` [LANG] ${path.relative(params.root, translationPath)} (dry run)`);
|
|
567
|
+
}
|
|
568
|
+
else {
|
|
569
|
+
fs.writeFileSync(translationPath, output);
|
|
570
|
+
console.log(` [UPDATE] ${path.relative(params.root, translationPath)}`);
|
|
571
|
+
}
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export interface GeneratorOptions {
|
|
2
|
+
dryRun?: boolean;
|
|
3
|
+
root: string;
|
|
4
|
+
}
|
|
5
|
+
export declare abstract class Generator {
|
|
6
|
+
protected dryRun: boolean;
|
|
7
|
+
protected root: string;
|
|
8
|
+
constructor(options: GeneratorOptions);
|
|
9
|
+
protected writeFile(filePath: string, content: string): void;
|
|
10
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
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.Generator = void 0;
|
|
37
|
+
const fs = __importStar(require("fs"));
|
|
38
|
+
const path = __importStar(require("path"));
|
|
39
|
+
class Generator {
|
|
40
|
+
dryRun;
|
|
41
|
+
root;
|
|
42
|
+
constructor(options) {
|
|
43
|
+
this.dryRun = !!options.dryRun;
|
|
44
|
+
this.root = options.root;
|
|
45
|
+
}
|
|
46
|
+
writeFile(filePath, content) {
|
|
47
|
+
const relativePath = path.relative(this.root, filePath);
|
|
48
|
+
if (fs.existsSync(filePath)) {
|
|
49
|
+
const existingContent = fs.readFileSync(filePath, 'utf-8');
|
|
50
|
+
if (existingContent === content) {
|
|
51
|
+
console.log(` [SKIP] ${relativePath} (no changes)`);
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
console.log(` [UPDATE] ${relativePath}${this.dryRun ? ' (dry run)' : ''}`);
|
|
55
|
+
}
|
|
56
|
+
else {
|
|
57
|
+
console.log(` [CREATE] ${relativePath}${this.dryRun ? ' (dry run)' : ''}`);
|
|
58
|
+
}
|
|
59
|
+
if (!this.dryRun) {
|
|
60
|
+
const dir = path.dirname(filePath);
|
|
61
|
+
if (!fs.existsSync(dir)) {
|
|
62
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
63
|
+
}
|
|
64
|
+
fs.writeFileSync(filePath, content, 'utf-8');
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
exports.Generator = Generator;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
type HookCompilerOptions = {
|
|
2
|
+
baseUrl: string;
|
|
3
|
+
paths: Record<string, string[]>;
|
|
4
|
+
typeRoots: string[];
|
|
5
|
+
};
|
|
6
|
+
export declare function createHookCompilerOptions(projectPath: string): HookCompilerOptions;
|
|
7
|
+
export declare function createHookTsConfig(projectPath: string): string;
|
|
8
|
+
export declare function cleanupHookTsConfig(tempTsconfigPath: string): void;
|
|
9
|
+
export {};
|