Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Initial setup of a generic application type #215

Merged
merged 9 commits into from
Jul 29, 2024
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Application } from "../../../../types/schemas/application";
import {Application} from '../../../../types/schemas/application';

const version = process.env['VERSION'] || '@next';

Expand Down
219 changes: 219 additions & 0 deletions schemas/prototypeApplication.json
Original file line number Diff line number Diff line change
@@ -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"
}
4 changes: 2 additions & 2 deletions scripts/build-schema.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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]}
Expand Down
6 changes: 5 additions & 1 deletion types/schemas/application/enums/ApplicationTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<TKey extends ApplicationTypeKeys> = {
value: TKey;
description: (typeof ApplicationTypes)[TKey];
};

type ExtractPrimaryKeys<T> = T extends `${infer K}.${string}` ? K : T;

export type PrimaryApplicationType = ExtractPrimaryKeys<ApplicationTypeKeys>;

type ApplicationTypeMap = {
[K in ApplicationTypeKeys]: GenericApplicationType<K>;
};
Expand Down
39 changes: 39 additions & 0 deletions types/schemas/prototypeApplication/ApplicationData.ts
Original file line number Diff line number Diff line change
@@ -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 PrimaryApplicationType> =
TPrimary extends keyof ApplicationDataVariants
? ApplicationDataVariants[TPrimary]
: ApplicationDataBase;
28 changes: 28 additions & 0 deletions types/schemas/prototypeApplication/User.ts
Original file line number Diff line number Diff line change
@@ -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 PrimaryApplicationType> =
TPrimary extends keyof UserVariants ? UserVariants[TPrimary] : UserBase;
62 changes: 62 additions & 0 deletions types/schemas/prototypeApplication/index.ts
Original file line number Diff line number Diff line change
@@ -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<TPrimary>;
application: ApplicationData<TPrimary>;
};
}

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<ApplicationTypeKeys, 'wtt' | 'wtt.consent' | 'wtt.notice'>
>;

/**
* @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',
// },
// },
// };