@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.
Files changed (104) hide show
  1. package/README.md +255 -0
  2. package/bin/cli.js +3 -0
  3. package/bin/run-hook-mocha.js +3 -0
  4. package/bin/run-hook-tsc.js +3 -0
  5. package/bin/wrapper-webpack.js +145 -0
  6. package/config/tsconfig.base.json +16 -0
  7. package/dist/bin/run-hook-mocha.d.ts +1 -0
  8. package/dist/bin/run-hook-mocha.js +49 -0
  9. package/dist/bin/run-hook-tsc.d.ts +1 -0
  10. package/dist/bin/run-hook-tsc.js +19 -0
  11. package/dist/cli-parsers.d.ts +9 -0
  12. package/dist/cli-parsers.js +131 -0
  13. package/dist/cli.d.ts +1 -0
  14. package/dist/cli.js +464 -0
  15. package/dist/commands/form-config.d.ts +5 -0
  16. package/dist/commands/form-config.js +194 -0
  17. package/dist/completion/index.d.ts +1 -0
  18. package/dist/completion/index.js +217 -0
  19. package/dist/generators/add-method.d.ts +27 -0
  20. package/dist/generators/add-method.js +235 -0
  21. package/dist/generators/angular-app.d.ts +24 -0
  22. package/dist/generators/angular-app.js +342 -0
  23. package/dist/generators/angular-service.d.ts +21 -0
  24. package/dist/generators/angular-service.js +154 -0
  25. package/dist/generators/controller.d.ts +40 -0
  26. package/dist/generators/controller.js +195 -0
  27. package/dist/generators/form-component.d.ts +46 -0
  28. package/dist/generators/form-component.js +906 -0
  29. package/dist/generators/form-field.d.ts +15 -0
  30. package/dist/generators/form-field.js +160 -0
  31. package/dist/generators/model.d.ts +42 -0
  32. package/dist/generators/model.js +206 -0
  33. package/dist/generators/service.d.ts +16 -0
  34. package/dist/generators/service.js +111 -0
  35. package/dist/runtime-resolver.d.ts +3 -0
  36. package/dist/runtime-resolver.js +27 -0
  37. package/dist/templates/hook-archetype.d.ts +12 -0
  38. package/dist/templates/hook-archetype.js +143 -0
  39. package/dist/testing.d.ts +7 -0
  40. package/dist/testing.js +53 -0
  41. package/dist/utils/config-helper.d.ts +71 -0
  42. package/dist/utils/config-helper.js +574 -0
  43. package/dist/utils/generator.d.ts +10 -0
  44. package/dist/utils/generator.js +68 -0
  45. package/dist/utils/hook-tsconfig.d.ts +9 -0
  46. package/dist/utils/hook-tsconfig.js +104 -0
  47. package/dist/utils/paths.d.ts +10 -0
  48. package/dist/utils/paths.js +60 -0
  49. package/index.js +4 -0
  50. package/package.json +85 -0
  51. package/runtime-resolver.d.ts +1 -0
  52. package/runtime-resolver.js +3 -0
  53. package/skills/redbox-angular-apps/SKILL.md +42 -0
  54. package/skills/redbox-angular-services/SKILL.md +29 -0
  55. package/skills/redbox-controllers/SKILL.md +65 -0
  56. package/skills/redbox-feature-design-planner/SKILL.md +169 -0
  57. package/skills/redbox-feature-implementation-review/SKILL.md +117 -0
  58. package/skills/redbox-form-components/SKILL.md +114 -0
  59. package/skills/redbox-form-config/SKILL.md +34 -0
  60. package/skills/redbox-hook-development/SKILL.md +66 -0
  61. package/skills/redbox-services/SKILL.md +54 -0
  62. package/skills/redbox-test-verification/SKILL.md +38 -0
  63. package/skills/redbox-testing/SKILL.md +64 -0
  64. package/skills/redbox-web-verification/SKILL.md +71 -0
  65. package/skills/redbox-web-verification/redbox-angular-apps/SKILL.md +48 -0
  66. package/skills/redbox-web-verification/redbox-angular-services/SKILL.md +30 -0
  67. package/skills/redbox-web-verification/redbox-controllers/SKILL.md +56 -0
  68. package/skills/redbox-web-verification/redbox-form-config/SKILL.md +29 -0
  69. package/skills/redbox-web-verification/redbox-hook-development/SKILL.md +61 -0
  70. package/skills/redbox-web-verification/redbox-services/SKILL.md +45 -0
  71. package/skills/redbox-web-verification/redbox-testing/SKILL.md +53 -0
  72. package/skills/redbox-web-verification/redbox-web-verification/SKILL.md +47 -0
  73. package/templates/hook-archetype/standard/.gitignore.hbs +4 -0
  74. package/templates/hook-archetype/standard/.npmignore.hbs +3 -0
  75. package/templates/hook-archetype/standard/.npmrc.hbs +6 -0
  76. package/templates/hook-archetype/standard/.nvmrc.hbs +1 -0
  77. package/templates/hook-archetype/standard/AGENTS.md.hbs +34 -0
  78. package/templates/hook-archetype/standard/Dockerfile.hbs +28 -0
  79. package/templates/hook-archetype/standard/README.md.hbs +39 -0
  80. package/templates/hook-archetype/standard/assets/fonts/.gitkeep +1 -0
  81. package/templates/hook-archetype/standard/language-defaults/.gitkeep +1 -0
  82. package/templates/hook-archetype/standard/package.json.hbs +40 -0
  83. package/templates/hook-archetype/standard/src/api/controllers/ExampleController.ts.hbs +21 -0
  84. package/templates/hook-archetype/standard/src/api/controllers/index.ts.hbs +23 -0
  85. package/templates/hook-archetype/standard/src/api/services/ExampleService.ts.hbs +22 -0
  86. package/templates/hook-archetype/standard/src/api/services/index.ts.hbs +23 -0
  87. package/templates/hook-archetype/standard/src/config/brandingConfigurationDefaults.ts.hbs +9 -0
  88. package/templates/hook-archetype/standard/src/config/reusableFormDefinitions.ts.hbs +6 -0
  89. package/templates/hook-archetype/standard/src/form-config/default-1.0-draft.ts.hbs +20 -0
  90. package/templates/hook-archetype/standard/src/form-config/index.ts.hbs +8 -0
  91. package/templates/hook-archetype/standard/src/index.ts.hbs +55 -0
  92. package/templates/hook-archetype/standard/support/bootstrap-data/.gitkeep +1 -0
  93. package/templates/hook-archetype/standard/support/development/docker-compose.yml.hbs +75 -0
  94. package/templates/hook-archetype/standard/support/integration-testing/docker-compose.mocha.yml.hbs +84 -0
  95. package/templates/hook-archetype/standard/support/integration-testing/run-mocha-hook.sh.hbs +9 -0
  96. package/templates/hook-archetype/standard/test/integration/hook-registration.test.ts.hbs +13 -0
  97. package/templates/hook-archetype/standard/test/support/globals.ts.hbs +40 -0
  98. package/templates/hook-archetype/standard/test/tsconfig.json.hbs +8 -0
  99. package/templates/hook-archetype/standard/test/unit/.mocharc.cjs.hbs +9 -0
  100. package/templates/hook-archetype/standard/test/unit/index.test.ts.hbs +40 -0
  101. package/templates/hook-archetype/standard/tsconfig.json.hbs +15 -0
  102. package/templates/hook-archetype/standard/views/.gitkeep +1 -0
  103. package/testing.d.ts +1 -0
  104. package/testing.js +3 -0
package/README.md ADDED
@@ -0,0 +1,255 @@
1
+ # ReDBox Dev Tools
2
+
3
+ A development toolkit for creating and maintaining ReDBox customisation hooks.
4
+
5
+ ## Overview
6
+
7
+ The `@researchdatabox/redbox-dev-tools` package provides shared configuration, generators, and migration tooling for developing ReDBox hook projects. It ensures consistency across hook implementations and simplifies dependency management.
8
+
9
+ ## Features
10
+
11
+ - **Shared TypeScript configuration**: Pre-configured TypeScript settings and type definitions
12
+ - **Shared configuration**: Base `tsconfig.json` that follows ReDBox conventions
13
+ - **CLI scaffolding**: Quick project initialization with `npx`
14
+ - **Type safety**: Includes ReDBox core types as peer dependency
15
+ - **Version alignment**: Versioned to match ReDBox core releases
16
+
17
+ ## Installation
18
+
19
+ ```bash
20
+ npm install --save-dev @researchdatabox/redbox-dev-tools
21
+ ```
22
+
23
+ ## Quick Start
24
+
25
+ Initialize a new hook project:
26
+
27
+ ```bash
28
+ npx @researchdatabox/redbox-dev-tools init redbox-hook-my-client
29
+ ```
30
+
31
+ This will:
32
+
33
+ - Generate the standard hook archetype in the current directory
34
+ - Create `src/`, `test/`, `support/`, `assets/`, `views/`, and `language-defaults/`
35
+ - Create a `package.json` with the shared Redbox dependency contract
36
+ - Generate starter controller, service, form-config, config, Docker, and test files
37
+
38
+ The standard archetype is based on the current hook structure used for `redbox-hook-jcu`, but stripped back to generic placeholders so a new client hook can start from the same shape without inheriting client-specific logic.
39
+
40
+ The archetype is now backed by file-based Handlebars templates under [templates/hook-archetype](templates/hook-archetype), which gives us a clean path for future variants such as branding-heavy hooks, lighter hooks, or alternate TypeScript setups.
41
+
42
+ ## TypeScript Configuration
43
+
44
+ Your hook project's `tsconfig.json` should extend the shared configuration:
45
+
46
+ ```json
47
+ {
48
+ "extends": "@researchdatabox/redbox-dev-tools/config/tsconfig.base.json",
49
+ "compilerOptions": {
50
+ "outDir": "./dist",
51
+ "typeRoots": ["node_modules/@types"]
52
+ },
53
+ "include": ["src/**/*.ts", "src/**/*.d.ts"]
54
+ }
55
+ ```
56
+
57
+ **Note:** Shared runtime path injection for packages such as `rxjs`, `axios`, `lodash`, and `@researchdatabox/sails-ng-common` is handled by the `run-hook-tsc` and `run-hook-mocha` entrypoints, not by hard-coded hook-local `paths` blocks.
58
+
59
+ ## Compiling TypeScript
60
+
61
+ Compile your TypeScript code using the toolchain provided by dev tools:
62
+
63
+ ```bash
64
+ node ./node_modules/@researchdatabox/redbox-dev-tools/bin/run-hook-tsc.js -p tsconfig.json
65
+ ```
66
+
67
+ Or add it to your `package.json` scripts:
68
+
69
+ ```json
70
+ {
71
+ "scripts": {
72
+ "compile": "node ./node_modules/@researchdatabox/redbox-dev-tools/bin/run-hook-tsc.js -p tsconfig.json"
73
+ }
74
+ }
75
+ ```
76
+
77
+ Then run:
78
+
79
+ ```bash
80
+ npm run compile
81
+ ```
82
+
83
+ ## Archetype Starter Files
84
+
85
+ ```typescript
86
+ import { defineRedboxHook } from '@researchdatabox/redbox-core';
87
+
88
+ const hook = defineRedboxHook({
89
+ registerRedboxControllers() {
90
+ return require('./api/controllers').ControllerExports;
91
+ },
92
+ registerRedboxServices() {
93
+ return require('./api/services').ServiceExports;
94
+ }
95
+ });
96
+
97
+ module.exports = hook;
98
+ ```
99
+
100
+ ## Shared Dependency Contract
101
+
102
+ Hooks should declare only:
103
+
104
+ - `peerDependencies.@researchdatabox/redbox-core`
105
+ - `devDependencies.@researchdatabox/redbox-dev-tools`
106
+ - direct `dependencies` for hook-owned runtime libraries only
107
+
108
+ Do not directly declare shared Redbox runtime or toolchain packages in a hook if they are already supplied by the core or dev-tools contract. That includes `axios`, `rxjs`, `lodash`, `mocha`, `chai`, `ts-node`, and `typescript`.
109
+
110
+ `redbox-dev-tools` directly provides the shared hook authoring toolchain:
111
+
112
+ - `typescript`
113
+ - `ts-node`
114
+ - `mocha`
115
+ - `chai`
116
+ - `@types/node`
117
+ - `@types/mocha`
118
+ - `@types/chai`
119
+ - `@types/lodash`
120
+
121
+ For hook tests and authoring utilities, `redbox-dev-tools` also exposes shared resolution helpers via `@researchdatabox/redbox-dev-tools/testing` and `@researchdatabox/redbox-dev-tools/runtime-resolver`. These are for development-time use only. Hook runtime code should continue to import normal runtime packages such as `axios` and `rxjs` directly and rely on the Redbox host contract to provide them. The shared TypeScript config prefers resolving those runtime modules from the installed `@researchdatabox/redbox-core` dependency tree, and only falls back to the `redbox-dev-tools` install when package manager flattening hoists them there.
122
+
123
+ `@researchdatabox/redbox-core` is the runtime compatibility contract for hooks. It supplies the approved shared runtime dependency surface that hook authors may rely on implicitly, including `axios`, `rxjs`, and `lodash`.
124
+
125
+ ## Versioning
126
+
127
+ This package is versioned to match the ReDBox core release it supports. For example, version `4.5.1` is compatible with ReDBox Portal version `4.5.1`.
128
+
129
+ ## CLI Commands
130
+
131
+ ### `init`
132
+
133
+ Initialize a new ReDBox hook project from the standard archetype.
134
+
135
+ ```bash
136
+ npx @researchdatabox/redbox-dev-tools init redbox-hook-my-client
137
+ ```
138
+
139
+ Template variants are selected with `--template`:
140
+
141
+ ```bash
142
+ npx @researchdatabox/redbox-dev-tools init redbox-hook-my-client --template standard
143
+ ```
144
+
145
+ ### `check`
146
+
147
+ Validate that the current hook package does not directly pin shared Redbox runtime or toolchain dependencies.
148
+
149
+ ```bash
150
+ npx @researchdatabox/redbox-dev-tools check
151
+ ```
152
+
153
+ ### `migrate-hook-dependencies`
154
+
155
+ Rewrite the current hook `package.json` to the minimal shared dependency contract.
156
+
157
+ ```bash
158
+ npx @researchdatabox/redbox-dev-tools migrate-hook-dependencies
159
+ ```
160
+
161
+ ### `install-skills`
162
+
163
+ Install the bundled agent skills using the `vercel-labs/skills` CLI. Bundled agent skills are curated prompt packs that teach supported agents how to work with ReDBox conventions, file layouts, and workflows. Install them to enable consistent, repo-aware assistance from your agent.
164
+
165
+ Prerequisites
166
+
167
+ - Install the external Skills CLI: `npx @vercel/skills --help` (or follow the install instructions in the Skills docs).
168
+ - Authenticate if required by your agent runtime (some agents prompt for login on first run).
169
+
170
+ Usage
171
+
172
+ - `-a <agent>`: Target agent runtime (for example `claude-code`).
173
+ - `--skill <pattern>`: Skill name or glob pattern (for example `redbox-*` or `*`).
174
+ - Skills are optional but recommended for consistent guidance and guardrails.
175
+
176
+ This will:
177
+
178
+ - Copy the bundled skill definitions from this package into the Skills CLI workspace.
179
+ - Register the skills for the specified agent runtime.
180
+ - Make the skills available for subsequent agent sessions.
181
+
182
+ ```bash
183
+ npx @researchdatabox/redbox-dev-tools install-skills -a claude-code --skill 'redbox-*'
184
+ ```
185
+
186
+ For advanced options, see the `vercel-labs/skills` documentation: https://github.com/vercel-labs/skills
187
+
188
+ ### `migrate-form-config`
189
+
190
+ Migrate a legacy v4 JavaScript form config to the v5 TypeScript form framework format.
191
+
192
+ ```bash
193
+ npx @researchdatabox/redbox-dev-tools migrate-form-config \
194
+ --input /path/to/legacy-form.js \
195
+ --output /path/to/migrated-form.ts
196
+ ```
197
+
198
+ ### `generate form-component`
199
+
200
+ Generate end-to-end scaffold for a new form component in Angular and `sails-ng-common`.
201
+
202
+ ```bash
203
+ npx @researchdatabox/redbox-dev-tools generate form-component my-widget --app form
204
+ ```
205
+
206
+ Optional Angular service scaffold:
207
+
208
+ ```bash
209
+ npx @researchdatabox/redbox-dev-tools generate form-component my-widget --app form --with-service
210
+ ```
211
+
212
+ ### `help`
213
+
214
+ Show CLI help and usage information.
215
+
216
+ ```bash
217
+ npx @researchdatabox/redbox-dev-tools help
218
+ ```
219
+
220
+ ### `completion`
221
+
222
+ Output shell completion scripts for `bash`, `zsh`, `fish`, and `powershell`.
223
+
224
+ ```bash
225
+ npx @researchdatabox/redbox-dev-tools completion <shell>
226
+ ```
227
+
228
+ Install examples:
229
+
230
+ ```bash
231
+ # bash
232
+ npx @researchdatabox/redbox-dev-tools completion bash > ~/.local/share/bash-completion/completions/redbox-dev-tools
233
+
234
+ # zsh
235
+ mkdir -p ~/.zsh/completions
236
+ npx @researchdatabox/redbox-dev-tools completion zsh > ~/.zsh/completions/_redbox-dev-tools
237
+ # then ensure your ~/.zshrc includes:
238
+ # fpath=(~/.zsh/completions $fpath)
239
+ # autoload -U compinit && compinit
240
+
241
+ # fish
242
+ npx @researchdatabox/redbox-dev-tools completion fish > ~/.config/fish/completions/redbox-dev-tools.fish
243
+
244
+ # powershell
245
+ npx @researchdatabox/redbox-dev-tools completion powershell > ~/.config/powershell/redbox-dev-tools-completion.ps1
246
+ # then source it from your PowerShell profile
247
+ ```
248
+
249
+ ## Contributing
250
+
251
+ See the main [ReDBox Portal repository](https://github.com/redbox-mint/redbox-portal) for contribution guidelines.
252
+
253
+ ## License
254
+
255
+ ISC
package/bin/cli.js ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+
3
+ require('../dist/cli.js');
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+
3
+ require('../dist/bin/run-hook-mocha.js');
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+
3
+ require('../dist/bin/run-hook-tsc.js');
@@ -0,0 +1,145 @@
1
+ // This file is a helper for dev only. It makes it easier to run webpack when parts of the mono repo are in different stages of being built. Refer to the redbox-core webpack.ts for how the hook runs webpack
2
+ const redboxCore = require('@researchdatabox/redbox-core');
3
+
4
+ const ensureTsNode = () => {
5
+ try {
6
+ require('ts-node/register/transpile-only');
7
+ return true;
8
+ } catch (e) {
9
+ return false;
10
+ }
11
+ };
12
+
13
+ let defineWebpackHook = redboxCore.defineWebpackHook || (redboxCore.default && redboxCore.default.defineWebpackHook);
14
+ if (!defineWebpackHook) {
15
+ try {
16
+ defineWebpackHook = require('@researchdatabox/redbox-core/dist/hooks/webpack').defineWebpackHook;
17
+ } catch (e) {}
18
+ }
19
+ if (!defineWebpackHook && ensureTsNode()) {
20
+ try {
21
+ defineWebpackHook = require('@researchdatabox/redbox-core/src/hooks/webpack.ts').defineWebpackHook;
22
+ } catch (e) {}
23
+ }
24
+
25
+ // Resolve webpack config: prefer exported `Config.webpack.config`, fall back to repo `config/webpack.js`.
26
+ let webpackConfig = [];
27
+ try {
28
+ // prefer repo config file
29
+ const repoWebpack = require(path.resolve(process.cwd(), 'config/webpack'));
30
+ if (repoWebpack && repoWebpack.webpack) {
31
+ webpackConfig = repoWebpack.webpack.config ? repoWebpack.webpack.config : repoWebpack.webpack;
32
+ } else {
33
+ webpackConfig = repoWebpack && repoWebpack.config ? repoWebpack.config : repoWebpack;
34
+ }
35
+ } catch (e) {
36
+ // ignore
37
+ }
38
+ if (!webpackConfig || (Array.isArray(webpackConfig) && webpackConfig.length === 0)) {
39
+ try {
40
+ const Config = redboxCore.Config || (redboxCore.default && redboxCore.default.Config);
41
+ if (Config && Config.webpack && Config.webpack.config) {
42
+ webpackConfig = Config.webpack.config;
43
+ }
44
+ } catch (e) {
45
+ // ignore
46
+ }
47
+ }
48
+ if (!webpackConfig || (Array.isArray(webpackConfig) && webpackConfig.length === 0)) {
49
+ try {
50
+ const distWebpack = require('@researchdatabox/redbox-core/dist/config/webpack.config');
51
+ webpackConfig = distWebpack && distWebpack.webpack ? distWebpack.webpack.config : distWebpack.config || distWebpack;
52
+ } catch (e) {}
53
+ }
54
+ if (!webpackConfig || (Array.isArray(webpackConfig) && webpackConfig.length === 0)) {
55
+ if (ensureTsNode()) {
56
+ try {
57
+ const srcWebpack = require('@researchdatabox/redbox-core/src/config/webpack.config.ts');
58
+ webpackConfig = srcWebpack && srcWebpack.webpack ? srcWebpack.webpack.config : srcWebpack.config || srcWebpack;
59
+ } catch (e) {}
60
+ }
61
+ }
62
+
63
+ sails = {
64
+ config: {
65
+ webpack: {
66
+ config: webpackConfig,
67
+ },
68
+ },
69
+ log: {
70
+ info: function (msg, data = null) {
71
+ console.info(msg, data);
72
+ },
73
+ warn: function (msg, data = null) {
74
+ console.warn(msg, data);
75
+ },
76
+ error: function (msg, data = null) {
77
+ console.error(msg, data);
78
+ },
79
+ },
80
+ };
81
+ async function main() {
82
+ if (!defineWebpackHook) {
83
+ console.warn('defineWebpackHook not available from @researchdatabox/redbox-core; running webpack directly');
84
+ // Fallback: run webpack directly using resolved config
85
+ const webpack = require('webpack');
86
+
87
+ if (!sails.config.webpack) {
88
+ sails.log.warn('sails-hook-webpack: No Webpack options have been defined.');
89
+ return;
90
+ }
91
+
92
+ if (
93
+ !sails.config.webpack.config ||
94
+ (Array.isArray(sails.config.webpack.config) && sails.config.webpack.config.length === 0)
95
+ ) {
96
+ sails.log.warn('sails-hook-webpack: Configure your config/webpack.js file.');
97
+ return;
98
+ }
99
+
100
+ if (process.env.NODE_ENV !== 'docker' || process.env.WEBPACK_SKIP === 'true') {
101
+ sails.log.warn(`sails-hook-webpack: Configured to skip webpack.`);
102
+ return;
103
+ }
104
+
105
+ if (process.env.WEBPACK_CSS_MINI === 'true') {
106
+ try {
107
+ sails.config.webpack.config[0].optimization.minimize = true;
108
+ sails.log.info(`Webpack wrapper is configured for CSS minimization.`);
109
+ } catch (e) {}
110
+ }
111
+
112
+ const compiler = webpack(sails.config.webpack.config);
113
+
114
+ const logCompileInfo = (err, stats) => {
115
+ if (err) {
116
+ sails.log.error('sails-hook-webpack: Build error: \n\n', err);
117
+ }
118
+ try {
119
+ sails.log[stats.hasErrors() ? 'error' : 'info'](
120
+ `sails-hook-webpack:\n${stats.toString({ colors: true, chunks: true })}`
121
+ );
122
+ } catch (e) {}
123
+ };
124
+
125
+ let called = false;
126
+ const compileCallback = (err, stats) => {
127
+ logCompileInfo(err, stats);
128
+ if (called) return;
129
+ called = true;
130
+ if (err || (stats && stats.hasErrors && stats.hasErrors())) {
131
+ console.error(err || stats.toString());
132
+ throw new Error('sails-hook-webpack failed');
133
+ }
134
+ console.log('Webpack wrapper done!');
135
+ };
136
+
137
+ compiler.run(compileCallback);
138
+ return;
139
+ }
140
+ await defineWebpackHook(sails).initialize(() => {
141
+ console.log('Webpack wrapper done!');
142
+ });
143
+ }
144
+
145
+ main();
@@ -0,0 +1,16 @@
1
+ {
2
+ "extends": "@tsconfig/node24/tsconfig.json",
3
+ "compilerOptions": {
4
+ "target": "ES2024",
5
+ "lib": ["ES2024"],
6
+ "module": "nodenext",
7
+ "moduleResolution": "nodenext",
8
+ "esModuleInterop": true,
9
+ "forceConsistentCasingInFileNames": true,
10
+ "skipLibCheck": true,
11
+ "types": ["node"],
12
+ "inlineSourceMap": true,
13
+ "experimentalDecorators": true,
14
+ "emitDecoratorMetadata": true
15
+ }
16
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,49 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const module_1 = __importDefault(require("module"));
7
+ const path_1 = __importDefault(require("path"));
8
+ const child_process_1 = require("child_process");
9
+ const typescript_1 = __importDefault(require("typescript"));
10
+ const hook_tsconfig_1 = require("../utils/hook-tsconfig");
11
+ function getResolvedCompilerOptions(projectPath) {
12
+ const resolvedProjectPath = path_1.default.resolve(process.cwd(), projectPath);
13
+ const configFile = typescript_1.default.readConfigFile(resolvedProjectPath, typescript_1.default.sys.readFile);
14
+ if (configFile.error) {
15
+ throw new Error(typescript_1.default.flattenDiagnosticMessageText(configFile.error.messageText, '\n'));
16
+ }
17
+ const parsedConfig = typescript_1.default.parseJsonConfigFileContent(configFile.config, typescript_1.default.sys, path_1.default.dirname(resolvedProjectPath), undefined, resolvedProjectPath);
18
+ if (parsedConfig.errors.length > 0) {
19
+ throw new Error(typescript_1.default.flattenDiagnosticMessageText(parsedConfig.errors[0].messageText, '\n'));
20
+ }
21
+ const convertedConfig = typescript_1.default.convertToTSConfig(parsedConfig, resolvedProjectPath, typescript_1.default.sys);
22
+ return convertedConfig.compilerOptions ?? {};
23
+ }
24
+ const redboxCorePackageJson = require.resolve('@researchdatabox/redbox-core/package.json');
25
+ const redboxCoreDir = path_1.default.dirname(redboxCorePackageJson);
26
+ const workspaceNodeModules = path_1.default.resolve(redboxCoreDir, '..', '..', 'node_modules');
27
+ const coreNodeModules = path_1.default.join(redboxCoreDir, 'node_modules');
28
+ const existingNodePath = process.env.NODE_PATH ? process.env.NODE_PATH.split(path_1.default.delimiter) : [];
29
+ const tsNodeProject = process.env.TS_NODE_PROJECT ?? 'tsconfig.json';
30
+ const existingCompilerOptions = process.env.TS_NODE_COMPILER_OPTIONS
31
+ ? JSON.parse(process.env.TS_NODE_COMPILER_OPTIONS)
32
+ : {};
33
+ const resolvedCompilerOptions = getResolvedCompilerOptions(tsNodeProject);
34
+ const hookCompilerOptions = (0, hook_tsconfig_1.createHookCompilerOptions)(tsNodeProject);
35
+ process.env.NODE_PATH = [workspaceNodeModules, coreNodeModules, ...existingNodePath]
36
+ .filter((value, index, values) => value && values.indexOf(value) === index)
37
+ .join(path_1.default.delimiter);
38
+ process.env.TS_NODE_SKIP_PROJECT = 'true';
39
+ process.env.TS_NODE_COMPILER_OPTIONS = JSON.stringify({
40
+ ...resolvedCompilerOptions,
41
+ ...existingCompilerOptions,
42
+ ...hookCompilerOptions,
43
+ });
44
+ module_1.default._initPaths();
45
+ const result = (0, child_process_1.spawnSync)(process.execPath, [require.resolve('mocha/bin/mocha.js'), ...process.argv.slice(2)], {
46
+ stdio: 'inherit',
47
+ env: process.env,
48
+ });
49
+ process.exit(result.status ?? 1);
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const child_process_1 = require("child_process");
4
+ const hook_tsconfig_1 = require("../utils/hook-tsconfig");
5
+ const args = [...process.argv.slice(2)];
6
+ const projectArgIndex = args.findIndex(arg => arg === '-p' || arg === '--project');
7
+ const projectPath = projectArgIndex >= 0 ? args[projectArgIndex + 1] : 'tsconfig.json';
8
+ const tempTsconfigPath = (0, hook_tsconfig_1.createHookTsConfig)(projectPath ?? 'tsconfig.json');
9
+ if (projectArgIndex >= 0) {
10
+ args.splice(projectArgIndex, 2, '-p', tempTsconfigPath);
11
+ }
12
+ else {
13
+ args.unshift('-p', tempTsconfigPath);
14
+ }
15
+ const result = (0, child_process_1.spawnSync)(process.execPath, [require.resolve('typescript/bin/tsc'), ...args], {
16
+ stdio: 'inherit',
17
+ });
18
+ (0, hook_tsconfig_1.cleanupHookTsConfig)(tempTsconfigPath);
19
+ process.exit(result.status ?? 1);
@@ -0,0 +1,9 @@
1
+ import { RouteMapping } from './generators/controller';
2
+ import { ModelAttribute, ModelAssociation } from './generators/model';
3
+ import { NavigationMapping, LanguageDefaultEntry } from './utils/config-helper';
4
+ export declare function parseAttributes(val: string): ModelAttribute[];
5
+ export declare function parseRoutes(val: string): RouteMapping[];
6
+ export declare function parseNavMappings(val: string): NavigationMapping[];
7
+ export declare function parseLanguageDefaults(val: string): LanguageDefaultEntry[];
8
+ export declare function parseBelongsTo(val: string): ModelAssociation[];
9
+ export declare function parseHasMany(val: string): ModelAssociation[];
@@ -0,0 +1,131 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.parseAttributes = parseAttributes;
4
+ exports.parseRoutes = parseRoutes;
5
+ exports.parseNavMappings = parseNavMappings;
6
+ exports.parseLanguageDefaults = parseLanguageDefaults;
7
+ exports.parseBelongsTo = parseBelongsTo;
8
+ exports.parseHasMany = parseHasMany;
9
+ // Helper functions for parsing model options
10
+ function parseAttributes(val) {
11
+ return val.split(',').map(attr => {
12
+ const parts = attr.trim().split(':');
13
+ const name = parts[0];
14
+ const type = (parts[1] || 'string');
15
+ const required = parts.includes('required');
16
+ const unique = parts.includes('unique');
17
+ return { name, type, required, unique };
18
+ });
19
+ }
20
+ // Helper function for parsing route mappings
21
+ // Format: action:verb:path[:role1:role2:...] (e.g., "listItems:get:/api/items:Admin:Researcher,deleteItem:delete:/api/items/:id:Admin")
22
+ function parseRoutes(val) {
23
+ return val.split(',').map(route => {
24
+ const parts = route.trim().split(':');
25
+ if (parts.length < 2) {
26
+ throw new Error(`Invalid route format: ${route}. Expected action:verb:path or action:path`);
27
+ }
28
+ if (parts.length === 2) {
29
+ // action:path format (verb defaults to get)
30
+ return { action: parts[0], verb: 'get', path: parts[1] };
31
+ }
32
+ // action:verb:path[:role1:role2:...] format
33
+ const action = parts[0];
34
+ const verb = parts[1].toLowerCase();
35
+ const path = parts[2];
36
+ const auth = parts.length > 3 ? parts.slice(3) : undefined;
37
+ return { action, verb, path, auth };
38
+ });
39
+ }
40
+ const NAV_TYPES = new Set(['menu', 'menuRoot', 'menu-root', 'homePanel', 'home-panel', 'adminSection', 'admin-section', 'adminFooter', 'admin-footer']);
41
+ function normalizeNavType(type) {
42
+ switch (type) {
43
+ case 'menu-root':
44
+ return 'menuRoot';
45
+ case 'home-panel':
46
+ return 'homePanel';
47
+ case 'admin-section':
48
+ return 'adminSection';
49
+ case 'admin-footer':
50
+ return 'adminFooter';
51
+ default:
52
+ return type;
53
+ }
54
+ }
55
+ // Format: [action:]type[:containerId]:labelKey[:itemId]
56
+ function parseNavMappings(val) {
57
+ return val.split(',').map(entry => {
58
+ const rawParts = entry.trim().split(':').filter(p => p.length > 0);
59
+ if (rawParts.length < 2) {
60
+ throw new Error(`Invalid navigation format: ${entry}. Expected action:type:containerId:labelKey or type:containerId:labelKey.`);
61
+ }
62
+ let action;
63
+ let typeToken = rawParts[0];
64
+ let parts = rawParts.slice(1);
65
+ if (!NAV_TYPES.has(typeToken)) {
66
+ action = rawParts[0];
67
+ typeToken = rawParts[1] || '';
68
+ parts = rawParts.slice(2);
69
+ }
70
+ if (!NAV_TYPES.has(typeToken)) {
71
+ throw new Error(`Invalid navigation type: ${typeToken}. Allowed: menu, menuRoot, homePanel, adminSection, adminFooter.`);
72
+ }
73
+ const target = normalizeNavType(typeToken);
74
+ if (target === 'menuRoot' || target === 'adminFooter') {
75
+ if (parts.length < 1) {
76
+ throw new Error(`Invalid navigation format: ${entry}. Expected ${target}:labelKey[:itemId].`);
77
+ }
78
+ const labelKey = parts[0];
79
+ const itemId = parts[1];
80
+ return { action, target, labelKey, itemId };
81
+ }
82
+ if (parts.length < 2) {
83
+ throw new Error(`Invalid navigation format: ${entry}. Expected ${target}:containerId:labelKey[:itemId].`);
84
+ }
85
+ const containerId = parts[0];
86
+ const labelKey = parts[1];
87
+ const itemId = parts[2];
88
+ return { action, target, containerId, labelKey, itemId };
89
+ });
90
+ }
91
+ // Format: key=value[:lang]
92
+ function parseLanguageDefaults(val) {
93
+ return val.split(',').map(entry => {
94
+ const trimmed = entry.trim();
95
+ const eqIdx = trimmed.indexOf('=');
96
+ if (eqIdx === -1) {
97
+ throw new Error(`Invalid language default format: ${entry}. Expected key=value[:lang].`);
98
+ }
99
+ const key = trimmed.slice(0, eqIdx).trim();
100
+ const valuePart = trimmed.slice(eqIdx + 1).trim();
101
+ const valueParts = valuePart.split(':');
102
+ const language = valueParts.length > 1 ? valueParts.pop() : undefined;
103
+ const value = valueParts.join(':');
104
+ if (!key || !value) {
105
+ throw new Error(`Invalid language default format: ${entry}. Expected key=value[:lang].`);
106
+ }
107
+ return { key, value, language };
108
+ });
109
+ }
110
+ function parseBelongsTo(val) {
111
+ return val.split(',').map(assoc => {
112
+ const parts = assoc.trim().split(':');
113
+ return {
114
+ name: parts[0],
115
+ type: 'belongsTo',
116
+ model: parts[1] || parts[0]
117
+ };
118
+ });
119
+ }
120
+ function parseHasMany(val) {
121
+ return val.split(',').map(assoc => {
122
+ const parts = assoc.trim().split(':');
123
+ return {
124
+ name: parts[0],
125
+ type: 'hasMany',
126
+ model: parts[1] || parts[0],
127
+ via: parts[2],
128
+ dominant: parts.includes('dominant')
129
+ };
130
+ });
131
+ }
package/dist/cli.d.ts ADDED
@@ -0,0 +1 @@
1
+ export {};