Skip to content

Commit

Permalink
feat: Initial setup of a generic application type (#215)
Browse files Browse the repository at this point in the history
  • Loading branch information
DafyddLlyr authored Jul 29, 2024
1 parent 89f9c37 commit 1134eaf
Show file tree
Hide file tree
Showing 6 changed files with 355 additions and 3 deletions.
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',
// },
// },
// };

0 comments on commit 1134eaf

Please sign in to comment.