@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
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,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 {};
|