Skip to content

Commit d8d4a8f

Browse files
committed
CCM-12896: Preprocess schemas to remove allOf
1 parent 94c5867 commit d8d4a8f

21 files changed

+593
-61
lines changed

package-lock.json

Lines changed: 369 additions & 47 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@
6161
"utils/sender-management",
6262
"src/cloudevents",
6363
"src/digital-letters-events",
64+
"src/python-schema-generator",
6465
"src/typescript-schema-generator",
6566
"tests/playwright"
6667
]

project.code-workspace

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,10 +79,10 @@
7979
},
8080
"terminal.integrated.scrollback": 10000,
8181
"jest.virtualFolders": [
82-
8382
{ "name": "key-generation", "rootPath": "lambdas/key-generation" },
8483
{ "name": "mesh-poll", "rootPath": "lambdas/mesh-poll" },
8584
{ "name": "refresh-apim-access-token", "rootPath": "lambdas/refresh-apim-access-token" },
85+
{ "name": "python-schema-generator", "rootPath": "src/python-schema-generator" },
8686
{ "name": "ttl-create-lambda", "rootPath": "lambdas/ttl-create-lambda/" },
8787
{ "name": "ttl-handle-expiry-lambda", "rootPath": "lambdas/ttl-handle-expiry-lambda" },
8888
{ "name": "ttl-poll-lambda", "rootPath": "lambdas/ttl-poll-lambda" },
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
schemas

src/python-schema-generator/Makefile

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
# Variables
22
SCHEMA_SRC_DIR := ../../schemas/digital-letters/2025-10-draft/events
33
OUTPUT_DIR := ../digital-letters-events/digital_letters_events/models
4-
SCRIPTS_DIR := scripts
4+
SRC_DIR := src
5+
SCHEMAS_DIR := $(SRC_DIR)/schemas
56

67
# Default target
78
.PHONY: all clean generate install install-dev test coverage help
@@ -10,9 +11,12 @@ all: generate
1011

1112
# Install production dependencies
1213
install:
13-
@echo "Installing production dependencies..."
14+
@echo "Installing Python production dependencies..."
1415
@pip install -r requirements.txt
1516
@echo "Production dependencies installed!"
17+
@echo "Installing Node production dependencies..."
18+
@npm install
19+
@echo "Node production dependencies installed!"
1620

1721
# Install development dependencies
1822
install-dev:
@@ -24,8 +28,9 @@ install-dev:
2428
generate: install
2529
@echo "Generating Pydantic models from JSON schemas..."
2630
@mkdir -p $(OUTPUT_DIR)
27-
@python $(SCRIPTS_DIR)/generate_models.py \
28-
--input-dir $(SCHEMA_SRC_DIR) \
31+
@npm run merge
32+
@python $(SRC_DIR)/generate_models.py \
33+
--input-dir $(SCHEMAS_DIR) \
2934
--output-dir $(OUTPUT_DIR)
3035
@echo "Pydantic models generated in $(OUTPUT_DIR)/"
3136

@@ -50,6 +55,7 @@ coverage: install-dev
5055
clean:
5156
@echo "Cleaning generated models..."
5257
@rm -rf $(OUTPUT_DIR) htmlcov .pytest_cache coverage.xml
58+
@rm -rf $(SCHEMAS_DIR)
5359
@echo "Clean complete!"
5460

5561
# Show help

src/python-schema-generator/README.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ if event_data.type == "uk.nhs.notify.digital.letters.letter.available.v1":
104104

105105
The generator consists of:
106106

107-
- `scripts/generate_models.py` - Main CLI script
108-
- `scripts/schema_processor.py` - Schema loading and processing
109-
- `scripts/model_generator.py` - Pydantic model generation logic
110-
- `scripts/file_utils.py` - File system utilities
107+
- `src/generate_models.py` - Main CLI script
108+
- `src/schema_processor.py` - Schema loading and processing
109+
- `src/model_generator.py` - Pydantic model generation logic
110+
- `src/file_utils.py` - File system utilities
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import { baseJestConfig } from '../../jest.config.base';
2+
3+
const config = {
4+
...baseJestConfig,
5+
coveragePathIgnorePatterns: [
6+
...(baseJestConfig.coveragePathIgnorePatterns ?? []),
7+
'src/merge-allof-cli.ts',
8+
],
9+
};
10+
11+
export default config;
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
{
2+
"dependencies": {
3+
"json-schema-merge-allof": "^0.8.1",
4+
"utils": "^0.0.1"
5+
},
6+
"description": "A tool to generate Python classes for the application's event schemas.",
7+
"devDependencies": {
8+
"@tsconfig/node22": "^22.0.5",
9+
"@types/jest": "^29.5.14",
10+
"@types/json-schema-merge-allof": "^0.6.5",
11+
"@types/node": "^25.0.2",
12+
"eslint": "^9.39.2",
13+
"jest": "^29.7.0",
14+
"mock-fs": "^5.5.0"
15+
},
16+
"name": "python-schema-generator",
17+
"private": true,
18+
"scripts": {
19+
"lint": "eslint scripts",
20+
"lint:fix": "eslint scripts --fix",
21+
"merge": "tsx src/merge-allof-cli.ts",
22+
"test:unit": "jest",
23+
"typecheck": "tsc --noEmit"
24+
},
25+
"version": "1.0.0"
26+
}
File renamed without changes.
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
/* eslint-disable security/detect-non-literal-fs-filename */
2+
3+
import { eventSchemasDir } from 'file-utils';
4+
import { mergeAllOfInSchemas } from 'merge-allof';
5+
import mockFs from 'mock-fs';
6+
import { readdirSync } from 'node:fs';
7+
import path from 'node:path';
8+
9+
jest.mock('json-schema-to-typescript');
10+
11+
describe('merge-allof', () => {
12+
const outputDir = path.resolve(__dirname, '..', 'schemas');
13+
14+
beforeEach(() => {
15+
mockFs({
16+
[eventSchemasDir]: {
17+
'one.flattened.schema.json': '{"title": "One"}',
18+
'two.flattened.schema.json': '{"title": "Two"}',
19+
'three.flattened.schema.json': '{"title": "Three"}',
20+
},
21+
});
22+
23+
jest.spyOn(console, 'log').mockImplementation(() => {});
24+
jest.spyOn(console, 'group').mockImplementation(() => {});
25+
});
26+
27+
afterEach(() => {
28+
mockFs.restore();
29+
});
30+
31+
it('should generate a schema with merged allOfs for each schema', () => {
32+
mergeAllOfInSchemas();
33+
34+
const mergedSchemas = readdirSync(outputDir);
35+
36+
expect(mergedSchemas.length).toBe(3);
37+
expect(mergedSchemas).toEqual(
38+
expect.arrayContaining([
39+
'one.flattened.schema.json',
40+
'two.flattened.schema.json',
41+
'three.flattened.schema.json',
42+
]),
43+
);
44+
});
45+
});

0 commit comments

Comments
 (0)