diff --git a/examples/application/data/planningPermission/fullHouseholderInConservationArea.ts b/examples/application/data/planningPermission/fullHouseholderInConservationArea.ts index b022088a..0dae1104 100644 --- a/examples/application/data/planningPermission/fullHouseholderInConservationArea.ts +++ b/examples/application/data/planningPermission/fullHouseholderInConservationArea.ts @@ -1,4 +1,4 @@ -import { Application } from "../../../../types/schemas/application"; +import {Application} from '../../../../types/schemas/application'; const version = process.env['VERSION'] || '@next'; diff --git a/schemas/prototypeApplication.json b/schemas/prototypeApplication.json new file mode 100644 index 00000000..ceec3738 --- /dev/null +++ b/schemas/prototypeApplication.json @@ -0,0 +1,219 @@ +{ + "$id": "@next", + "$schema": "http://json-schema.org/draft-07/schema#", + "anyOf": [ + { + "$ref": "#/definitions/PlanningPermissionApplication" + }, + { + "$ref": "#/definitions/PriorApprovalApplication" + }, + { + "$ref": "#/definitions/WorksToTreesApplications" + } + ], + "definitions": { + "ApplicationDataBase": { + "additionalProperties": false, + "description": "Base type for ApplicationData. Contains all shared properties across all application types", + "properties": { + "somethingShared": { + "type": "string" + } + }, + "required": [ + "somethingShared" + ], + "type": "object" + }, + "PPApplicationData": { + "additionalProperties": false, + "description": "Specific ApplicationData required for \"Planning Permission\" applications", + "properties": { + "ppSpecificProperty": { + "type": "number" + }, + "somethingShared": { + "type": "string" + } + }, + "required": [ + "ppSpecificProperty", + "somethingShared" + ], + "type": "object" + }, + "PPUser": { + "additionalProperties": false, + "properties": { + "ppSpecificProperty": { + "type": "boolean" + }, + "role": { + "enum": [ + "applicant", + "agent", + "proxy" + ], + "type": "string" + } + }, + "required": [ + "ppSpecificProperty", + "role" + ], + "type": "object" + }, + "PlanningPermissionApplication": { + "additionalProperties": false, + "properties": { + "applicationType": { + "const": "pp", + "type": "string" + }, + "data": { + "additionalProperties": false, + "properties": { + "application": { + "$ref": "#/definitions/PPApplicationData" + }, + "user": { + "$ref": "#/definitions/PPUser" + } + }, + "required": [ + "user", + "application" + ], + "type": "object" + } + }, + "required": [ + "applicationType", + "data" + ], + "type": "object" + }, + "PriorApprovalApplication": { + "additionalProperties": false, + "properties": { + "applicationType": { + "const": "pa", + "type": "string" + }, + "data": { + "additionalProperties": false, + "properties": { + "application": { + "$ref": "#/definitions/ApplicationDataBase" + }, + "user": { + "$ref": "#/definitions/UserBase" + } + }, + "required": [ + "user", + "application" + ], + "type": "object" + } + }, + "required": [ + "applicationType", + "data" + ], + "type": "object" + }, + "UserBase": { + "additionalProperties": false, + "properties": { + "role": { + "enum": [ + "applicant", + "agent", + "proxy" + ], + "type": "string" + } + }, + "required": [ + "role" + ], + "type": "object" + }, + "WTTApplicationData": { + "additionalProperties": false, + "description": "Specific ApplicationData required for \"Works to trees\" applications", + "properties": { + "somethingShared": { + "type": "string" + }, + "wttSpecificProperty": { + "type": "number" + } + }, + "required": [ + "somethingShared", + "wttSpecificProperty" + ], + "type": "object" + }, + "WTTUser": { + "additionalProperties": false, + "properties": { + "role": { + "enum": [ + "applicant", + "agent", + "proxy" + ], + "type": "string" + }, + "wttSpecificProperty": { + "type": "boolean" + } + }, + "required": [ + "role", + "wttSpecificProperty" + ], + "type": "object" + }, + "WorksToTreesApplications": { + "additionalProperties": false, + "properties": { + "applicationType": { + "enum": [ + "wtt", + "wtt.consent", + "wtt.notice" + ], + "type": "string" + }, + "data": { + "additionalProperties": false, + "properties": { + "application": { + "$ref": "#/definitions/WTTApplicationData" + }, + "user": { + "$ref": "#/definitions/WTTUser" + } + }, + "required": [ + "user", + "application" + ], + "type": "object" + } + }, + "required": [ + "applicationType", + "data" + ], + "type": "object" + } + }, + "description": "The root specification for a planning application in England generated by a digital planning service (prototype)", + "title": "PrototypeApplication" +} \ No newline at end of file diff --git a/scripts/build-schema.sh b/scripts/build-schema.sh index f16a8058..01b53d9d 100755 --- a/scripts/build-schema.sh +++ b/scripts/build-schema.sh @@ -7,8 +7,8 @@ version="${VERSION:-@next}" echo "Version set to $version" -dirs=("application") -types=("Application") +dirs=("application" "prototypeApplication") +types=("Application" "PrototypeApplication") for i in "${!dirs[@]}"; do dir=${dirs[$i]} diff --git a/types/schemas/application/enums/ApplicationTypes.ts b/types/schemas/application/enums/ApplicationTypes.ts index b9d516de..2de754ec 100644 --- a/types/schemas/application/enums/ApplicationTypes.ts +++ b/types/schemas/application/enums/ApplicationTypes.ts @@ -173,13 +173,17 @@ export const ApplicationTypes = { 'Works to trees - Notification of proposed works to a tree in a Conservation Area', }; -type ApplicationTypeKeys = keyof typeof ApplicationTypes; +export type ApplicationTypeKeys = keyof typeof ApplicationTypes; type GenericApplicationType = { value: TKey; description: (typeof ApplicationTypes)[TKey]; }; +type ExtractPrimaryKeys = T extends `${infer K}.${string}` ? K : T; + +export type PrimaryApplicationType = ExtractPrimaryKeys; + type ApplicationTypeMap = { [K in ApplicationTypeKeys]: GenericApplicationType; }; diff --git a/types/schemas/prototypeApplication/ApplicationData.ts b/types/schemas/prototypeApplication/ApplicationData.ts new file mode 100644 index 00000000..bd1eac9a --- /dev/null +++ b/types/schemas/prototypeApplication/ApplicationData.ts @@ -0,0 +1,39 @@ +import {PrimaryApplicationType} from '../application/enums/ApplicationTypes'; + +/** + * Base type for ApplicationData. Contains all shared properties across all application types + */ +export interface ApplicationDataBase { + somethingShared: string; +} + +/** + * @description Specific ApplicationData required for "Works to trees" applications + */ +export interface WTTApplicationData extends ApplicationDataBase { + wttSpecificProperty: number; +} + +/** + * @description Specific ApplicationData required for "Planning Permission" applications + */ +export interface PPApplicationData extends ApplicationDataBase { + ppSpecificProperty: number; +} + +/** + * TypeMap of PrimaryApplicationTypes to their specific ApplicationData models + */ +export interface ApplicationDataVariants { + wtt: WTTApplicationData; + pp: PPApplicationData; +} + +/** + * @internal + * Conditional type to return a specific or generic ApplicationData model, based on PrimaryApplicationType + */ +export type ApplicationData = + TPrimary extends keyof ApplicationDataVariants + ? ApplicationDataVariants[TPrimary] + : ApplicationDataBase; diff --git a/types/schemas/prototypeApplication/User.ts b/types/schemas/prototypeApplication/User.ts new file mode 100644 index 00000000..da248014 --- /dev/null +++ b/types/schemas/prototypeApplication/User.ts @@ -0,0 +1,28 @@ +import {PrimaryApplicationType} from '../application/enums/ApplicationTypes'; + +export interface UserBase { + role: 'applicant' | 'agent' | 'proxy'; +} + +export interface WTTUser extends UserBase { + wttSpecificProperty: boolean; +} + +export interface PPUser extends UserBase { + ppSpecificProperty: boolean; +} + +/** + * TypeMap of PrimaryApplicationTypes to their specific User models + */ +interface UserVariants { + wtt: WTTUser; + pp: PPUser; +} + +/** + * @internal + * Conditional type to return a specific or generic User model, based on PrimaryApplicationType + */ +export type User = + TPrimary extends keyof UserVariants ? UserVariants[TPrimary] : UserBase; diff --git a/types/schemas/prototypeApplication/index.ts b/types/schemas/prototypeApplication/index.ts new file mode 100644 index 00000000..065254e4 --- /dev/null +++ b/types/schemas/prototypeApplication/index.ts @@ -0,0 +1,62 @@ +import { + ApplicationTypeKeys, + PrimaryApplicationType, +} from '../application/enums/ApplicationTypes'; +import {ApplicationData} from './ApplicationData'; +import {User} from './User'; + +/** + * @internal + * The generic base type for all applications + * Takes a primary and granular application type which allows child properties to differ based on these inputs + * Deriving `TPrimary` from `TGranular` is possible in TS, but not in a way which is currently compatible with ts-json-schema-generator + */ +interface ApplicationSpecification< + TPrimary extends PrimaryApplicationType, + TGranular extends ApplicationTypeKeys, +> { + applicationType: TGranular; + data: { + user: User; + application: ApplicationData; + }; +} + +export type PlanningPermissionApplication = ApplicationSpecification< + 'pp', + 'pp' +>; +// TODO: All granular types + +export type PriorApprovalApplication = ApplicationSpecification<'pa', 'pa'>; +// TODO: All granular types + +export type WorksToTreesApplications = ApplicationSpecification< + 'wtt', + Extract +>; + +/** + * @title PrototypeApplication + * @description + * The root specification for a planning application in England generated by a digital planning service (prototype) + */ +export type PrototypeApplication = + | PlanningPermissionApplication + | PriorApprovalApplication + | WorksToTreesApplications; +// TODO: All the rest! + +// const test: App = { +// applicationType: 'wtt.consent', +// data: { +// user: { +// role: 'agent', +// wttSpecificProperty: true, +// }, +// application: { +// wttSpecificProperty: 123, +// somethingShared: 'abc', +// }, +// }, +// };