@defra/forms-engine-plugin 5.0.0-alpha.25 → 5.0.0-alpha.26
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/.server/server/plugins/engine/components/helpers/geospatial.js +4 -3
- package/.server/server/plugins/engine/components/helpers/geospatial.js.map +1 -1
- package/.server/server/plugins/map/routes/index.d.ts +4 -0
- package/.server/server/plugins/map/routes/index.js +12 -4
- package/.server/server/plugins/map/routes/index.js.map +1 -1
- package/.server/server/plugins/map/routes/vts/README.md +38 -0
- package/.server/server/plugins/map/routes/vts/countries-5dp.geojson +4 -0
- package/.server/server/plugins/map/routes/vts/countries.geojson +10 -39283
- package/.server/server/plugins/map/types.d.ts +24 -2
- package/.server/server/plugins/map/types.js +9 -2
- package/.server/server/plugins/map/types.js.map +1 -1
- package/package.json +1 -1
- package/src/server/plugins/engine/components/helpers/geospatial.ts +6 -5
- package/src/server/plugins/map/routes/index.js +26 -4
- package/src/server/plugins/map/routes/vts/README.md +38 -0
- package/src/server/plugins/map/routes/vts/countries-5dp.geojson +4 -0
- package/src/server/plugins/map/routes/vts/countries.geojson +10 -39283
- package/src/server/plugins/map/types.js +9 -2
|
@@ -1,3 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @typedef {{
|
|
3
|
+
* ordnanceSurveyApiKey: string
|
|
4
|
+
* ordnanceSurveyApiSecret: string
|
|
5
|
+
* }} MapConfiguration
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Map proxy query params
|
|
9
|
+
* @typedef {object} MapProxyQuery
|
|
10
|
+
* @property {string} url - the proxied url
|
|
11
|
+
*/
|
|
12
|
+
/**
|
|
13
|
+
* Map geocode query params
|
|
14
|
+
* @typedef {object} MapGeocodeQuery
|
|
15
|
+
* @property {string} query - name query
|
|
16
|
+
*/
|
|
17
|
+
export const CountryMap: {
|
|
18
|
+
england: number;
|
|
19
|
+
'northern-ireland': number;
|
|
20
|
+
scotland: number;
|
|
21
|
+
wales: number;
|
|
22
|
+
};
|
|
1
23
|
export type MapConfiguration = {
|
|
2
24
|
ordnanceSurveyApiKey: string;
|
|
3
25
|
ordnanceSurveyApiSecret: string;
|
|
@@ -27,11 +49,11 @@ export type GeospatialCountriesQuery = {
|
|
|
27
49
|
/**
|
|
28
50
|
* - the country to omit
|
|
29
51
|
*/
|
|
30
|
-
omit
|
|
52
|
+
omit?: "england" | "wales" | "northern-ireland" | "scotland" | undefined;
|
|
31
53
|
/**
|
|
32
54
|
* - the country to include
|
|
33
55
|
*/
|
|
34
|
-
only
|
|
56
|
+
only?: "england" | "wales" | "northern-ireland" | "scotland" | undefined;
|
|
35
57
|
};
|
|
36
58
|
/**
|
|
37
59
|
* Map geocode get request
|
|
@@ -21,11 +21,18 @@
|
|
|
21
21
|
* @property {string} query - name query
|
|
22
22
|
*/
|
|
23
23
|
|
|
24
|
+
export const CountryMap = {
|
|
25
|
+
england: 1,
|
|
26
|
+
'northern-ireland': 3,
|
|
27
|
+
scotland: 2,
|
|
28
|
+
wales: 4
|
|
29
|
+
};
|
|
30
|
+
|
|
24
31
|
/**
|
|
25
32
|
* Geospatial countries query params
|
|
26
33
|
* @typedef {object} GeospatialCountriesQuery
|
|
27
|
-
* @property {
|
|
28
|
-
* @property {
|
|
34
|
+
* @property {keyof typeof CountryMap} [omit] - the country to omit
|
|
35
|
+
* @property {keyof typeof CountryMap} [only] - the country to include
|
|
29
36
|
*/
|
|
30
37
|
|
|
31
38
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","names":[],"sources":["../../../../src/server/plugins/map/types.js"],"sourcesContent":["/**\n * @typedef {{\n * ordnanceSurveyApiKey: string\n * ordnanceSurveyApiSecret: string\n * }} MapConfiguration\n */\n\n//\n// Route types\n//\n\n/**\n * Map proxy query params\n * @typedef {object} MapProxyQuery\n * @property {string} url - the proxied url\n */\n\n/**\n * Map geocode query params\n * @typedef {object} MapGeocodeQuery\n * @property {string} query - name query\n */\n\n/**\n * Geospatial countries query params\n * @typedef {object} GeospatialCountriesQuery\n * @property {
|
|
1
|
+
{"version":3,"file":"types.js","names":["CountryMap","england","scotland","wales"],"sources":["../../../../src/server/plugins/map/types.js"],"sourcesContent":["/**\n * @typedef {{\n * ordnanceSurveyApiKey: string\n * ordnanceSurveyApiSecret: string\n * }} MapConfiguration\n */\n\n//\n// Route types\n//\n\n/**\n * Map proxy query params\n * @typedef {object} MapProxyQuery\n * @property {string} url - the proxied url\n */\n\n/**\n * Map geocode query params\n * @typedef {object} MapGeocodeQuery\n * @property {string} query - name query\n */\n\nexport const CountryMap = {\n england: 1,\n 'northern-ireland': 3,\n scotland: 2,\n wales: 4\n}\n\n/**\n * Geospatial countries query params\n * @typedef {object} GeospatialCountriesQuery\n * @property {keyof typeof CountryMap} [omit] - the country to omit\n * @property {keyof typeof CountryMap} [only] - the country to include\n */\n\n/**\n * Map geocode get request\n * @typedef {object} MapProxyGetRequestRefs\n * @property {MapProxyQuery} Query - Request query\n */\n\n/**\n * Map geocode get request\n * @typedef {object} MapGeocodeGetRequestRefs\n * @property {MapGeocodeQuery} Query - Request query\n */\n\n/**\n * Map countries geojson get request\n * @typedef {object} GeospatialCountriesGetRequestRefs\n * @property {GeospatialCountriesQuery} Query - Request query\n */\n\n/**\n * @typedef {MapProxyGetRequestRefs} MapProxyRequestRefs\n * @typedef {MapGeocodeGetRequestRefs} MapGeocodeRequestRefs\n * @typedef {Request<MapGeocodeGetRequestRefs>} MapProxyGetRequest\n * @typedef {Request<MapGeocodeGetRequestRefs>} MapGeocodeGetRequest\n * @typedef {MapProxyGetRequest | MapGeocodeGetRequest } MapRequest\n */\n\n//\n// Service types\n//\n\n/**\n * @typedef {object} OsNamesFindResponse\n * @property {OsNamesFindHeader} header - Metadata about the search request and results.\n * @property {OsNamesFindResult[]} results - An array of matched place records from the search.\n */\n\n/**\n * @typedef {object} OsNamesFindHeader\n * @property {string} uri - The query URI (usually same as search text).\n * @property {string} query - The original text query string passed to the API.\n * @property {string} format - The response format returned (e.g., \"JSON\").\n * @property {number} maxresults - The maximum number of results requested.\n * @property {number} offset - The offset used in the search results.\n * @property {number} totalresults - The total number of results that matched the query.\n * @property {string} filter - The original filter string passed to the API.\n */\n\n/**\n * @typedef {object} OsNamesFindGazetteerEntry\n * @property {string} ID - Unique identifier for the place/feature.\n * @property {string} NAMES_URI - A URI (identifier) for this named feature.\n * @property {string} NAME1 - Primary name of the feature.\n * @property {string} TYPE - General type classification of the feature.\n * @property {string} LOCAL_TYPE - Local or more specific type classification.\n * @property {number} GEOMETRY_X - Easting coordinate (British National Grid).\n * @property {number} GEOMETRY_Y - Northing coordinate (British National Grid).\n * @property {number} MOST_DETAIL_VIEW_RES - Most detailed resolution available.\n * @property {number} LEAST_DETAIL_VIEW_RES - Least detailed resolution available.\n * @property {number} [MBR_XMIN] - Minimum bounding box X (easting).\n * @property {number} [MBR_YMIN] - Minimum bounding box Y (northing).\n * @property {number} [MBR_XMAX] - Maximum bounding box X (easting).\n * @property {number} [MBR_YMAX] - Maximum bounding box Y (northing).\n * @property {string} [DISTRICT_BOROUGH] - (Optional) District borough.\n * @property {string} [DISTRICT_BOROUGH_URI] - (Optional) URI for the district borough.\n * @property {string} [DISTRICT_BOROUGH_TYPE] - (Optional) Type of the district borough.\n * @property {string} [POSTCODE_DISTRICT] - (Optional) Postcode district.\n * @property {string} [POSTCODE_DISTRICT_URI] - (Optional) URI for the postcode district.\n * @property {string} [POPULATED_PLACE] - (Optional) Name of associated populated place.\n * @property {string} [POPULATED_PLACE_URI] - (Optional) URI of populated place.\n * @property {string} [POPULATED_PLACE_TYPE] - (Optional) Type of populated place.\n * @property {string} [COUNTY_UNITARY] - (Optional) County or unitary authority name.\n * @property {string} [COUNTY_UNITARY_URI] - (Optional) URI for county/unitary authority.\n * @property {string} [COUNTY_UNITARY_TYPE] - (Optional) Classification of county/unitary authority.\n * @property {string} [REGION] - (Optional) Region name.\n * @property {string} [REGION_URI] - (Optional) URI for region.\n * @property {string} [COUNTRY] - (Optional) Country name.\n * @property {string} [COUNTRY_URI] - (Optional) URI for country.\n */\n\n/**\n * OS names GAZETTEER_ENTRY response\n * @typedef {object} OsNamesFindResult\n * @property {OsNamesFindGazetteerEntry} GAZETTEER_ENTRY - Gazetteer entry\n */\n\n/**\n * @import { Request } from '@hapi/hapi'\n */\n"],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA,OAAO,MAAMA,UAAU,GAAG;EACxBC,OAAO,EAAE,CAAC;EACV,kBAAkB,EAAE,CAAC;EACrBC,QAAQ,EAAE,CAAC;EACXC,KAAK,EAAE;AACT,CAAC;;AAED;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA","ignoreList":[]}
|
package/package.json
CHANGED
|
@@ -16,7 +16,8 @@ import {
|
|
|
16
16
|
type FeatureProperties,
|
|
17
17
|
type Geometry
|
|
18
18
|
} from '../../types.js'
|
|
19
|
-
import {
|
|
19
|
+
import { countriesValidate } from '../../../map/routes/index.js'
|
|
20
|
+
import { CountryMap } from '../../../map/types.js'
|
|
20
21
|
|
|
21
22
|
const Joi = JoiBase.extend({
|
|
22
23
|
type: 'array',
|
|
@@ -157,8 +158,8 @@ export function getGeospatialSchema(
|
|
|
157
158
|
}
|
|
158
159
|
|
|
159
160
|
const validateCountryBounds: CustomValidator = (value, helpers) => {
|
|
160
|
-
const countryFeature =
|
|
161
|
-
(feature) => feature.id === country
|
|
161
|
+
const countryFeature = countriesValidate.features.find(
|
|
162
|
+
(feature) => feature.id === CountryMap[country]
|
|
162
163
|
)
|
|
163
164
|
|
|
164
165
|
if (!countryFeature) {
|
|
@@ -191,8 +192,8 @@ export function getEastingNorthingCountryValidator(
|
|
|
191
192
|
country: GeospatialFieldOptionsCountry
|
|
192
193
|
) {
|
|
193
194
|
const validateCountryBounds: CustomValidator = (value, helpers) => {
|
|
194
|
-
const countryFeature =
|
|
195
|
-
(feature) => feature.id === country
|
|
195
|
+
const countryFeature = countriesValidate.features.find(
|
|
196
|
+
(feature) => feature.id === CountryMap[country]
|
|
196
197
|
)
|
|
197
198
|
|
|
198
199
|
if (!countryFeature) {
|
|
@@ -7,18 +7,36 @@ import Joi from 'joi'
|
|
|
7
7
|
|
|
8
8
|
import { getAccessToken } from './get-os-token.js'
|
|
9
9
|
import { find } from '../service.js'
|
|
10
|
+
import { CountryMap } from '../types.js'
|
|
10
11
|
import {
|
|
11
12
|
get,
|
|
12
13
|
request as httpRequest
|
|
13
14
|
} from '../../../services/httpService.js'
|
|
14
15
|
|
|
15
|
-
const
|
|
16
|
+
const countriesDisplayFilePath = resolve(
|
|
17
|
+
import.meta.dirname,
|
|
18
|
+
'./vts/countries.geojson'
|
|
19
|
+
)
|
|
20
|
+
const countriesValidateFilePath = resolve(
|
|
21
|
+
import.meta.dirname,
|
|
22
|
+
'./vts/countries-5dp.geojson'
|
|
23
|
+
)
|
|
16
24
|
|
|
17
25
|
/**
|
|
18
26
|
* @type {FeatureCollection}
|
|
19
27
|
*/
|
|
20
28
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
21
|
-
export const countries = JSON.parse(
|
|
29
|
+
export const countries = JSON.parse(
|
|
30
|
+
fs.readFileSync(countriesDisplayFilePath, 'utf8')
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* @type {FeatureCollection}
|
|
35
|
+
*/
|
|
36
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
37
|
+
export const countriesValidate = JSON.parse(
|
|
38
|
+
fs.readFileSync(countriesValidateFilePath, 'utf8')
|
|
39
|
+
)
|
|
22
40
|
|
|
23
41
|
export const countrySchema = Joi.string().valid(
|
|
24
42
|
...Object.values(GeospatialFieldOptionsCountryEnum)
|
|
@@ -188,14 +206,18 @@ function getGeospatialCountries() {
|
|
|
188
206
|
if (omit) {
|
|
189
207
|
return {
|
|
190
208
|
...countries,
|
|
191
|
-
features: countries.features.filter(
|
|
209
|
+
features: countries.features.filter(
|
|
210
|
+
(feature) => feature.id !== CountryMap[omit]
|
|
211
|
+
)
|
|
192
212
|
}
|
|
193
213
|
}
|
|
194
214
|
|
|
195
215
|
if (only) {
|
|
196
216
|
return {
|
|
197
217
|
...countries,
|
|
198
|
-
features: countries.features.filter(
|
|
218
|
+
features: countries.features.filter(
|
|
219
|
+
(feature) => feature.id === CountryMap[only]
|
|
220
|
+
)
|
|
199
221
|
}
|
|
200
222
|
}
|
|
201
223
|
|
|
@@ -1,5 +1,43 @@
|
|
|
1
|
+
# VTS
|
|
2
|
+
|
|
1
3
|
File in this directory are sourced from https://github.com/OrdnanceSurvey/OS-Vector-Tile-API-Stylesheets
|
|
2
4
|
|
|
3
5
|
VTS_OUTDOOR_URL=https://raw.githubusercontent.com/OrdnanceSurvey/OS-Vector-Tile-API-Stylesheets/main/OS_VTS_3857_Outdoor.json
|
|
4
6
|
VTS_DARK_URL=https://raw.githubusercontent.com/OrdnanceSurvey/OS-Vector-Tile-API-Stylesheets/main/OS_VTS_3857_Dark.json
|
|
5
7
|
VTS_BLACK_AND_WHITE_URL=https://raw.githubusercontent.com/OrdnanceSurvey/OS-Vector-Tile-API-Stylesheets/main/OS_VTS_3857_Black_and_White.json
|
|
8
|
+
|
|
9
|
+
# Country boundaries
|
|
10
|
+
|
|
11
|
+
The [Office for National Statistics provides full-resolution boundaries](https://www.ons.gov.uk/methodology/geography/geographicalproducts/digitalboundaries) in two coastal forms.
|
|
12
|
+
We use "BFE" a full resolution — extent of the realm and generally extends to Mean Low Water rather than clipping at Mean High Water.
|
|
13
|
+
|
|
14
|
+
The latest version of the data is from 2025 and can be found at the following links:
|
|
15
|
+
|
|
16
|
+
https://geoportal.statistics.gov.uk/datasets/591803c2a3b94804a3d7895cc127d7c0_0/explore?location=50.529309%2C-4.098782%2C7
|
|
17
|
+
|
|
18
|
+
Download from: http://geoportal.statistics.gov.uk/ or https://geoportal.statistics.gov.uk/datasets/ons::countries-december-2025-boundaries-uk-bfe/about
|
|
19
|
+
|
|
20
|
+
The source data is for the 2025 revision is 179MB so needs to be reduced to allow rendering in a Web map and used for validation on the server. The downloaded file is named `boundaries-bfe.geojson`. `org2ogr` is used to produce two files:
|
|
21
|
+
|
|
22
|
+
## Server-side validation (boundaries-bfe-5dp.geojson)
|
|
23
|
+
|
|
24
|
+
This is the full file but with coordinate precision reduced from 14 to 5 decimal places, resulting in a smaller file of 83.7MB.
|
|
25
|
+
This data is then used server-side to validate points, shapes and lines that include country restrictions.
|
|
26
|
+
|
|
27
|
+
`ogr2ogr --config OGR_GEOJSON_MAX_OBJ_SIZE 0 -f GeoJSON boundaries-bfe-5dp.geojson boundaries-bfe.geojson -lco COORDINATE_PRECISION=5`
|
|
28
|
+
|
|
29
|
+
## Client-side display on map (boundaries-bfe-5dp.geojson)
|
|
30
|
+
|
|
31
|
+
To produce a file suitable for use in the map in the browser we use `ogr2ogr`'s `simplify` option.
|
|
32
|
+
|
|
33
|
+
`-simplify 0.001` uses the units of the input CRS. In EPSG:4326, that's degrees, not metres so a tolerance of 0.001° is roughly 111 metres north–south, which is quite a substantial simplification for coastal boundaries. For 0.001 to mean approximately one metre, we have to reproject to a suitable projected CRS (BNG, EPSG:27700) before simplifying:
|
|
34
|
+
|
|
35
|
+
The following command produces `boundaries-bng.geojson`, the source file reprojected to BNG.
|
|
36
|
+
|
|
37
|
+
`ogr2ogr --config OGR_GEOJSON_MAX_OBJ_SIZE 0 -f GeoJSON boundaries-bng.geojson boundaries-bfe.geojson -t_srs EPSG:27700`
|
|
38
|
+
|
|
39
|
+
We then use this to create a simplified dataset, `countries.geojson`, reprojected back in ESPG:4326:
|
|
40
|
+
|
|
41
|
+
`ogr2ogr --config OGR_GEOJSON_MAX_OBJ_SIZE 0 -f GeoJSON countries.geojson boundaries-bng.json -simplify 100 -t_srs EPSG:4326 -lco COORDINATE_PRECISION=5`
|
|
42
|
+
|
|
43
|
+
The result is a file of 940kB that is suitable to use in the web map.
|