diff --git a/RULES.md b/RULES.md index 3664049..76e35d4 100644 --- a/RULES.md +++ b/RULES.md @@ -1,4 +1,4 @@ -This project validates feeds up to version 3.1-RC of the [JSON Schemas](https://github.com/MobilityData/gbfs-json-schema). +This project validates feeds up to version 3.1-RC2 of the [JSON Schemas](https://github.com/MobilityData/gbfs-json-schema). # Files presence The validator will flag any missing file. It will inform the user if the missing file is required or not, as per the conditions in the GBFS version that it detects. diff --git a/gbfs-validator/README.md b/gbfs-validator/README.md index 458bbc2..aee965b 100644 --- a/gbfs-validator/README.md +++ b/gbfs-validator/README.md @@ -14,7 +14,7 @@ npm install gbfs-validator ``` ## Supported GBFS Versions -- 3.1-RC +- 3.1-RC2 - 3.0 - 2.3 - 2.2 diff --git a/gbfs-validator/__test__/fixtures/conditional_default_reserve_time.js b/gbfs-validator/__test__/fixtures/conditional_default_reserve_time.js index a4ce5fa..b0e709a 100644 --- a/gbfs-validator/__test__/fixtures/conditional_default_reserve_time.js +++ b/gbfs-validator/__test__/fixtures/conditional_default_reserve_time.js @@ -7,7 +7,7 @@ function build(opts = {}) { return { last_updated: "2024-05-23T15:30:00Z", ttl: 0, - version: '3.1-RC', + version: '3.1-RC2', data: { feeds: [ { @@ -36,7 +36,7 @@ function build(opts = {}) { return { last_updated: "2024-05-23T15:30:00Z", ttl: 0, - version: '3.1-RC', + version: '3.1-RC2', data: { system_id: 'shared_bike', name: [ @@ -57,7 +57,7 @@ function build(opts = {}) { return { last_updated: "2024-05-23T15:30:00Z", ttl: 0, - version: '3.1-RC', + version: '3.1-RC2', data: { vehicle_types: [ { @@ -135,7 +135,7 @@ function build(opts = {}) { return { last_updated: "2024-05-23T15:30:00Z", ttl: 0, - version: '3.1-RC', + version: '3.1-RC2', data: { plans: [ { diff --git a/gbfs-validator/__test__/gbfs.test.js b/gbfs-validator/__test__/gbfs.test.js index 2178568..250638b 100644 --- a/gbfs-validator/__test__/gbfs.test.js +++ b/gbfs-validator/__test__/gbfs.test.js @@ -3,15 +3,14 @@ const pjson = require('../package.json') const serverOpts = { port: 0, - host: '127.0.0.1', + host: '127.0.0.1' } describe('initialization', () => { - beforeAll(() => { // mocks process and pacakge.json for consistent tests const originalProcess = process - global.process = {...originalProcess, versions: {node: '16.0.1'}} + global.process = { ...originalProcess, versions: { node: '16.0.1' } } pjson.version = '1.1.1' }) @@ -125,7 +124,7 @@ describe('checkAutodiscovery method', () => { }/gbfs.json` ) - return gbfs.checkAutodiscovery().then(result => { + return gbfs.checkAutodiscovery().then((result) => { expect(result).toMatchObject({ errors: false, exists: true, @@ -147,7 +146,7 @@ describe('checkAutodiscovery method', () => { }/` ) - return gbfs.checkAutodiscovery().then(result => { + return gbfs.checkAutodiscovery().then((result) => { expect(result).toMatchObject({ errors: false, exists: true, @@ -169,7 +168,7 @@ describe('checkAutodiscovery method', () => { }/v2/` ) - return gbfs.checkAutodiscovery().then(result => { + return gbfs.checkAutodiscovery().then((result) => { expect(result).toMatchObject({ errors: false, exists: false, @@ -192,7 +191,7 @@ describe('checkAutodiscovery method', () => { { version: '2.0' } ) - return gbfs.checkAutodiscovery().then(result => { + return gbfs.checkAutodiscovery().then((result) => { expect(result).toMatchObject({ errors: false, exists: false, @@ -242,14 +241,14 @@ describe('getFile method', () => { } } - return gbfs.getFile('system_information', true).then(result => { + return gbfs.getFile('system_information', true).then((result) => { expect(result).toMatchObject({ body: expect.any(Array), required: true, type: 'system_information' }) - result.body.forEach(l => { + result.body.forEach((l) => { expect(l).toMatchObject({ exists: true, lang: 'en', @@ -278,14 +277,14 @@ describe('getFile method', () => { } } - return gbfs.getFile('do_not_exist', true).then(result => { + return gbfs.getFile('do_not_exist', true).then((result) => { expect(result).toMatchObject({ body: expect.any(Array), required: true, type: 'do_not_exist' }) - result.body.forEach(l => { + result.body.forEach((l) => { expect(l).toMatchObject({ body: null, exists: false, @@ -302,7 +301,7 @@ describe('getFile method', () => { }` const gbfs = new GBFS(`${url}`) - return gbfs.getFile('system_information', true).then(result => { + return gbfs.getFile('system_information', true).then((result) => { expect(result).toMatchObject({ required: true, exists: true, @@ -318,7 +317,7 @@ describe('getFile method', () => { }` const gbfs = new GBFS(`${url}/gbfs.json`) - return gbfs.getFile('do_not_exist', true).then(result => { + return gbfs.getFile('do_not_exist', true).then((result) => { expect(result).toMatchObject({ body: null, required: true, @@ -442,7 +441,7 @@ describe('validationFile method', () => { hasErrors: false }) - result.languages.forEach(l => { + result.languages.forEach((l) => { expect(l).toMatchObject({ body: expect.any(Object), exists: true, @@ -476,7 +475,7 @@ describe('validation method', () => { expect.assertions(1) - return gbfs.validation().then(result => { + return gbfs.validation().then((result) => { expect(result).toMatchObject({ summary: expect.objectContaining({ version: { detected: '2.2', validated: '2.2' }, @@ -512,7 +511,7 @@ describe('conditional vehicle_types file', () => { expect.assertions(1) - return gbfs.validation().then(result => { + return gbfs.validation().then((result) => { expect(result).toMatchObject({ summary: expect.objectContaining({ version: { detected: '2.2', validated: '2.2' } @@ -529,15 +528,14 @@ describe('conditional vehicle_types file', () => { }) }) -describe('required default_reserve_time on reservation price existing v3.1-RC', () => { - +describe('required default_reserve_time on reservation price existing v3.1-RC2', () => { beforeAll(async () => { gbfsFeedServer = require('./fixtures/conditional_default_reserve_time')() await gbfsFeedServer.listen(serverOpts) return gbfsFeedServer - }); + }) afterAll(() => { return gbfsFeedServer.close() @@ -547,15 +545,14 @@ describe('required default_reserve_time on reservation price existing v3.1-RC', const url = `http://${gbfsFeedServer.server.address().address}:${ gbfsFeedServer.server.address().port }` - const gbfs = new GBFS(`${url}/gbfs.json`); + const gbfs = new GBFS(`${url}/gbfs.json`) - expect.assertions(1); + expect.assertions(1) - return gbfs.validation().then(result => { - + return gbfs.validation().then((result) => { expect(result).toMatchObject({ summary: expect.objectContaining({ - version: { detected: '3.1-RC', validated: '3.1-RC' }, + version: { detected: '3.1-RC2', validated: '3.1-RC2' }, hasErrors: true, errorsCount: 3 }), @@ -583,13 +580,15 @@ describe('required default_reserve_time on reservation price existing v3.1-RC', expect.objectContaining( { instancePath: '/data/plans/3', - schemaPath: '#/properties/data/properties/plans/items/dependencies/reservation_price_flat_rate/not', - message: "must NOT be valid" + schemaPath: + '#/properties/data/properties/plans/items/dependencies/reservation_price_flat_rate/not', + message: 'must NOT be valid' }, { instancePath: '/data/plans/3', - schemaPath: '#/properties/data/properties/plans/items/dependencies/reservation_price_per_min/not', - message: "must NOT be valid" + schemaPath: + '#/properties/data/properties/plans/items/dependencies/reservation_price_per_min/not', + message: 'must NOT be valid' } ) ]) @@ -600,8 +599,8 @@ describe('required default_reserve_time on reservation price existing v3.1-RC', ]) }) }) - }); -}); + }) +}) describe('conditional required vehicle_type_id', () => { let gbfsFeedServer @@ -626,7 +625,7 @@ describe('conditional required vehicle_type_id', () => { expect.assertions(1) - return gbfs.validation().then(result => { + return gbfs.validation().then((result) => { expect(result).toMatchObject({ summary: expect.objectContaining({ version: { detected: '2.2', validated: '2.2' }, @@ -682,7 +681,7 @@ describe('conditional no required vehicle_type_id', () => { expect.assertions(1) - return gbfs.validation().then(result => { + return gbfs.validation().then((result) => { expect(result).toMatchObject({ summary: expect.objectContaining({ version: { detected: '2.2', validated: '2.2' } @@ -703,7 +702,8 @@ describe('conditional required vehicle_types_available', () => { let gbfsFeedServer beforeAll(async () => { - gbfsFeedServer = require('./fixtures/conditionnal_vehicle_types_available')() + gbfsFeedServer = + require('./fixtures/conditionnal_vehicle_types_available')() await gbfsFeedServer.listen(serverOpts) @@ -722,9 +722,9 @@ describe('conditional required vehicle_types_available', () => { expect.assertions(1) - return gbfs.validation().then(result => { - const file = result.files.find(f => f.file === 'station_status.json') - const errors = file.languages.map(l => l.errors) + return gbfs.validation().then((result) => { + const file = result.files.find((f) => f.file === 'station_status.json') + const errors = file.languages.map((l) => l.errors) expect(errors).toMatchObject([ [ @@ -766,9 +766,9 @@ describe('conditional plan_id', () => { expect.assertions(1) - return gbfs.validation().then(result => { - const file = result.files.find(f => f.file === 'vehicle_types.json') - const errors = file.languages.map(l => l.errors) + return gbfs.validation().then((result) => { + const file = result.files.find((f) => f.file === 'vehicle_types.json') + const errors = file.languages.map((l) => l.errors) expect(errors).toMatchObject([ [ diff --git a/gbfs-validator/package.json b/gbfs-validator/package.json index 88dc8bd..690f549 100644 --- a/gbfs-validator/package.json +++ b/gbfs-validator/package.json @@ -1,6 +1,6 @@ { "name": "gbfs-validator", - "version": "1.0.13", + "version": "1.0.14", "author": "MobilityData", "main": "index.js", "license": "MIT", diff --git a/gbfs-validator/versions/gbfs-json-schema b/gbfs-validator/versions/gbfs-json-schema index bfa90be..b8cfc2f 160000 --- a/gbfs-validator/versions/gbfs-json-schema +++ b/gbfs-validator/versions/gbfs-json-schema @@ -1 +1 @@ -Subproject commit bfa90be64272fd15fac687435bc9a9c5e71fc5ac +Subproject commit b8cfc2f54c934f8102d3da362145b93daba94ddf diff --git a/gbfs-validator/versions/partials/v3.1-RC/vehicle_types/default_reserve_time_require.js b/gbfs-validator/versions/partials/v3.1-RC/vehicle_types/default_reserve_time_require.js deleted file mode 100644 index c099614..0000000 --- a/gbfs-validator/versions/partials/v3.1-RC/vehicle_types/default_reserve_time_require.js +++ /dev/null @@ -1,54 +0,0 @@ -module.exports = ({ pricingPlansIdsWithReservationPrice }) => { - const partial = { - $id: 'pricing_plan_id.json#', - $merge: { - source: { - $ref: - 'https://github.com/MobilityData/gbfs/blob/v3.1-RC/gbfs.md#vehicle_typesjson' - }, - with: { - properties: { - data: { - properties: { - vehicle_types: { - items: { - // allOf avoids overwriting the existing if statement about max_range - "allOf": [ - { - if: { - "anyOf": [ - { - properties: { - default_pricing_plan_id: { - enum: pricingPlansIdsWithReservationPrice - } - } - }, - { - properties: { - pricing_plan_ids: { - contains: { - enum: pricingPlansIdsWithReservationPrice - } - } - } - } - ] - }, - then: { - required: ['default_reserve_time'] - } - } - ] - }, - } - } - } - } - } - } - } - - return partial; - } - \ No newline at end of file diff --git a/gbfs-validator/versions/partials/v3.1-RC/station_status/required_vehicle_types_available.js b/gbfs-validator/versions/partials/v3.1-RC2/station_status/required_vehicle_types_available.js similarity index 75% rename from gbfs-validator/versions/partials/v3.1-RC/station_status/required_vehicle_types_available.js rename to gbfs-validator/versions/partials/v3.1-RC2/station_status/required_vehicle_types_available.js index f804960..4ad26bd 100644 --- a/gbfs-validator/versions/partials/v3.1-RC/station_status/required_vehicle_types_available.js +++ b/gbfs-validator/versions/partials/v3.1-RC2/station_status/required_vehicle_types_available.js @@ -3,8 +3,7 @@ module.exports = ({ vehicleTypes }) => { $id: 'required_vehicle_types_available.json#', $merge: { source: { - $ref: - 'https://github.com/MobilityData/gbfs/blob/v3.1-RC/gbfs.md#station_statusjson' + $ref: 'https://github.com/MobilityData/gbfs-json-schema/blob/master/v3.1-RC2/station_status.json' }, with: { properties: { @@ -17,7 +16,7 @@ module.exports = ({ vehicleTypes }) => { items: { properties: { vehicle_type_id: { - enum: vehicleTypes.map(vt => vt.vehicle_type_id) + enum: vehicleTypes.map((vt) => vt.vehicle_type_id) } } } @@ -32,8 +31,7 @@ module.exports = ({ vehicleTypes }) => { }, $patch: { source: { - $ref: - 'https://github.com/MobilityData/gbfs/blob/v3.1-RC/gbfs.md#station_statusjson' + $ref: 'https://github.com/MobilityData/gbfs-json-schema/blob/master/v3.1-RC2/station_status.json' }, with: [ { diff --git a/gbfs-validator/versions/partials/v3.1-RC/system_information/required_store_uri.js b/gbfs-validator/versions/partials/v3.1-RC2/system_information/required_store_uri.js similarity index 82% rename from gbfs-validator/versions/partials/v3.1-RC/system_information/required_store_uri.js rename to gbfs-validator/versions/partials/v3.1-RC2/system_information/required_store_uri.js index 8823b62..2ded7c9 100644 --- a/gbfs-validator/versions/partials/v3.1-RC/system_information/required_store_uri.js +++ b/gbfs-validator/versions/partials/v3.1-RC2/system_information/required_store_uri.js @@ -3,8 +3,7 @@ module.exports = ({ android = false, ios = false }) => { $id: 'required_ios_store_uri.json#', $patch: { source: { - $ref: - 'https://github.com/MobilityData/gbfs/blob/v3.1-RC/gbfs.md#system_informationjson' + $ref: 'https://github.com/MobilityData/gbfs-json-schema/blob/master/v3.1-RC2/system_information.json' }, with: [ { @@ -16,8 +15,7 @@ module.exports = ({ android = false, ios = false }) => { }, $merge: { source: { - $ref: - 'https://github.com/MobilityData/gbfs/blob/v3.1-RC/gbfs.md#system_informationjson' + $ref: 'https://github.com/MobilityData/gbfs-json-schema/blob/master/v3.1-RC2/system_information.json' }, with: { properties: { @@ -42,7 +40,9 @@ module.exports = ({ android = false, ios = false }) => { } if (ios) { - partial.$merge.with.properties.data.properties.rental_apps.required.push('ios') + partial.$merge.with.properties.data.properties.rental_apps.required.push( + 'ios' + ) partial.$merge.with.properties.data.properties.rental_apps.properties.ios.required.push( 'store_uri' ) diff --git a/gbfs-validator/versions/partials/v3.1-RC/vehicle_status/required_vehicle_type_id.js b/gbfs-validator/versions/partials/v3.1-RC2/vehicle_status/required_vehicle_type_id.js similarity index 79% rename from gbfs-validator/versions/partials/v3.1-RC/vehicle_status/required_vehicle_type_id.js rename to gbfs-validator/versions/partials/v3.1-RC2/vehicle_status/required_vehicle_type_id.js index ffc9453..78db1fc 100644 --- a/gbfs-validator/versions/partials/v3.1-RC/vehicle_status/required_vehicle_type_id.js +++ b/gbfs-validator/versions/partials/v3.1-RC2/vehicle_status/required_vehicle_type_id.js @@ -3,15 +3,14 @@ module.exports = ({ vehicleTypes }) => { $id: 'required_vehicle_type_id.json#' } - const motorVehicleTypes = vehicleTypes.filter(vt => + const motorVehicleTypes = vehicleTypes.filter((vt) => ['electric_assist', 'electric', 'combustion'].includes(vt.propulsion_type) ) if (motorVehicleTypes.length) { partial.$merge = { source: { - $ref: - 'https://github.com/MobilityData/gbfs/blob/v3.1-RC/gbfs.md#vehicle_statusjson' + $ref: 'https://github.com/MobilityData/gbfs-json-schema/blob/master/v3.1-RC2/vehicle_status.json' }, with: { properties: { @@ -28,7 +27,7 @@ module.exports = ({ vehicleTypes }) => { if: { properties: { vehicle_type_id: { - enum: motorVehicleTypes.map(vt => vt.vehicle_type_id) + enum: motorVehicleTypes.map((vt) => vt.vehicle_type_id) } }, // "required" so it only trigger "then" when "vehicle_type_id" is present. @@ -48,8 +47,7 @@ module.exports = ({ vehicleTypes }) => { partial.$patch = { source: { - $ref: - 'https://github.com/MobilityData/gbfs/blob/v3.1-RC/gbfs.md#vehicle_statusjson' + $ref: 'https://github.com/MobilityData/gbfs-json-schema/blob/master/v3.1-RC2/vehicle_status.json' }, with: [ { diff --git a/gbfs-validator/versions/partials/v3.1-RC2/vehicle_types/default_reserve_time_require.js b/gbfs-validator/versions/partials/v3.1-RC2/vehicle_types/default_reserve_time_require.js new file mode 100644 index 0000000..3b1ced9 --- /dev/null +++ b/gbfs-validator/versions/partials/v3.1-RC2/vehicle_types/default_reserve_time_require.js @@ -0,0 +1,52 @@ +module.exports = ({ pricingPlansIdsWithReservationPrice }) => { + const partial = { + $id: 'pricing_plan_id.json#', + $merge: { + source: { + $ref: 'https://github.com/MobilityData/gbfs-json-schema/blob/master/v3.1-RC2/vehicle_types.json' + }, + with: { + properties: { + data: { + properties: { + vehicle_types: { + items: { + // allOf avoids overwriting the existing if statement about max_range + allOf: [ + { + if: { + anyOf: [ + { + properties: { + default_pricing_plan_id: { + enum: pricingPlansIdsWithReservationPrice + } + } + }, + { + properties: { + pricing_plan_ids: { + contains: { + enum: pricingPlansIdsWithReservationPrice + } + } + } + } + ] + }, + then: { + required: ['default_reserve_time'] + } + } + ] + } + } + } + } + } + } + } + } + + return partial +} diff --git a/gbfs-validator/versions/partials/v3.1-RC/vehicle_types/pricing_plan_id.js b/gbfs-validator/versions/partials/v3.1-RC2/vehicle_types/pricing_plan_id.js similarity index 66% rename from gbfs-validator/versions/partials/v3.1-RC/vehicle_types/pricing_plan_id.js rename to gbfs-validator/versions/partials/v3.1-RC2/vehicle_types/pricing_plan_id.js index fde812f..8f3c9c5 100644 --- a/gbfs-validator/versions/partials/v3.1-RC/vehicle_types/pricing_plan_id.js +++ b/gbfs-validator/versions/partials/v3.1-RC2/vehicle_types/pricing_plan_id.js @@ -1,10 +1,9 @@ module.exports = ({ pricingPlans }) => { - const partial = { + const partial = { $id: 'pricing_plan_id.json#', $merge: { source: { - $ref: - 'https://github.com/MobilityData/gbfs/blob/v3.1-RC/gbfs.md#vehicle_typesjson' + $ref: 'https://github.com/MobilityData/gbfs-json-schema/blob/master/v3.1-RC2/vehicle_types.json' }, with: { properties: { @@ -14,9 +13,9 @@ module.exports = ({ pricingPlans }) => { items: { properties: { default_pricing_plan_id: { - enum: pricingPlans.map(p => p.plan_id) + enum: pricingPlans.map((p) => p.plan_id) } - }, + } } } } @@ -26,5 +25,5 @@ module.exports = ({ pricingPlans }) => { } } - return partial; + return partial } diff --git a/gbfs-validator/versions/v3.1-RC.js b/gbfs-validator/versions/v3.1-RC.js deleted file mode 100644 index 6c35446..0000000 --- a/gbfs-validator/versions/v3.1-RC.js +++ /dev/null @@ -1,19 +0,0 @@ -module.exports = { - gbfsRequired: true, - files: options => { - return [ - { file: 'manifest', required: false }, - { file: 'gbfs_versions', required: false }, - { file: 'system_information', required: true }, - { file: 'vehicle_types', required: false }, - { file: 'station_information', required: options.docked }, - { file: 'station_status', required: options.docked }, - { file: 'vehicle_status', required: options.freefloating }, - { file: 'system_regions', required: false }, - { file: 'system_pricing_plans', required: false }, - { file: 'system_alerts', required: false }, - { file: 'geofencing_zones', required: false } - ] - } - } - \ No newline at end of file diff --git a/gbfs-validator/versions/v3.1-RC2.js b/gbfs-validator/versions/v3.1-RC2.js new file mode 100644 index 0000000..4c2e3d0 --- /dev/null +++ b/gbfs-validator/versions/v3.1-RC2.js @@ -0,0 +1,19 @@ +module.exports = { + gbfsRequired: true, + files: (options) => { + return [ + { file: 'manifest', required: false }, + { file: 'gbfs_versions', required: false }, + { file: 'system_information', required: true }, + { file: 'vehicle_types', required: false }, + { file: 'station_information', required: options.docked }, + { file: 'station_status', required: options.docked }, + { file: 'vehicle_status', required: options.freefloating }, + { file: 'vehicle_availability', required: false }, + { file: 'system_regions', required: false }, + { file: 'system_pricing_plans', required: false }, + { file: 'system_alerts', required: false }, + { file: 'geofencing_zones', required: false } + ] + } +} diff --git a/website/src/pages/Validator.vue b/website/src/pages/Validator.vue index d52de15..b990d5e 100644 --- a/website/src/pages/Validator.vue +++ b/website/src/pages/Validator.vue @@ -25,7 +25,7 @@ const state = reactive({ }, versions: [ { value: null, text: 'auto-detection' }, - { value: '3.1-RC', text: 'v3.1-RC' }, + { value: '3.1-RC2', text: 'v3.1-RC2' }, { value: '3.0', text: 'v3.0' }, { value: '2.3', text: 'v2.3' }, { value: '2.2', text: 'v2.2' },