Skip to content

Commit

Permalink
Requirement 17 & 18
Browse files Browse the repository at this point in the history
  • Loading branch information
joostfarla committed Feb 27, 2024
1 parent 77dd6ea commit 1f872de
Show file tree
Hide file tree
Showing 7 changed files with 251 additions and 27 deletions.
46 changes: 23 additions & 23 deletions docs/assets/index-BCtqdiW3.js → docs/assets/index-BN30DA_l.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion docs/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>JSON-FG Linter</title>
<script type="module" crossorigin src="/json-fg-linter/assets/index-BCtqdiW3.js"></script>
<script type="module" crossorigin src="/json-fg-linter/assets/index-BN30DA_l.js"></script>
<link rel="stylesheet" crossorigin href="/json-fg-linter/assets/index-BhK0hqxH.css">
</head>
<body>
Expand Down
4 changes: 4 additions & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ export type FeatureDocument = Feature | FeatureCollection;
export interface Feature {
type: DocumentTypes.FEATURE;
conformsTo?: string[];
featureType?: string | string[];
featureSchema?: string;
time: Time | null;
place: Geometry | null;
geometry: Point | MultiPoint | LineString | MultiLineString | Polygon | MultiPolygon | null;
Expand All @@ -19,6 +21,8 @@ export interface Feature {
export interface FeatureCollection {
type: DocumentTypes.FEATURE_COLLECTION;
conformsTo?: string[];
featureType?: string | string[];
featureSchema?: string;
features: Feature[];
}

Expand Down
6 changes: 4 additions & 2 deletions src/validation/rules/3d-metadata.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ rules.push({
return {
pointer: '/conformsTo',
message:
'When having 3D geometries, the "conformsTo" member of the JSON document SHALL include at least the 3D conformance class.',
'When having 3D geometries, the "conformsTo" member of the JSON document SHALL include at least the 3D ' +
'conformance class.',
};
}
},
Expand All @@ -30,7 +31,8 @@ rules.push({
return {
pointer: '/conformsTo',
message:
'When having 3D geometries, the "conformsTo" member of the JSON document SHALL include at least the 3D conformance class.',
'When having 3D geometries, the "conformsTo" member of the JSON document SHALL include at least the 3D ' +
'conformance class.',
};
}
},
Expand Down
3 changes: 2 additions & 1 deletion src/validation/rules/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import threedMetadata from './3d-metadata';
import coreMetadata from './core-metadata';
import coreTemporal from './core-temporal';
import typesSchemasMetadata from './types-schemas-metadata';

export default [...coreMetadata, ...coreTemporal, ...threedMetadata];
export default [...coreMetadata, ...coreTemporal, ...threedMetadata, ...typesSchemasMetadata];
122 changes: 122 additions & 0 deletions src/validation/rules/types-schemas-metadata.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
import { DocumentTypes, Feature, FeatureCollection } from '../../types';
import { applyRules } from '../ruleValidation';
import { CC_CORE_URI } from './core-metadata';
import metadata, { CC_TYPES_SCHEMAS_URI } from './types-schemas-metadata';

describe('Requirement 17A', () => {
test('Fails when a feature contains a "featureType" member and does not include the Feature Types and Schemas conformance class', () => {
const violations = applyRules(metadata, {
type: DocumentTypes.FEATURE,
conformsTo: [CC_CORE_URI],
featureType: 'app:building',
} as Feature);

expect(violations.length).toBe(1);
});

test('Fails when a feature collection contains a "featureType" member and does not include the Feature Types and Schemas conformance class', () => {
const violations = applyRules(metadata, {
type: DocumentTypes.FEATURE_COLLECTION,
conformsTo: [CC_CORE_URI],
featureType: 'app:building',
} as FeatureCollection);

expect(violations.length).toBe(1);
});

test('Fails when a feature collection member contains a "featureType" member and does not include the Feature Types and Schemas conformance class', () => {
const violations = applyRules(metadata, {
type: DocumentTypes.FEATURE_COLLECTION,
conformsTo: [CC_CORE_URI],
features: [
{
type: DocumentTypes.FEATURE,
featureType: 'app:building',
},
],
} as FeatureCollection);

expect(violations.length).toBe(1);
});
});

describe('Requirement 18A', () => {
test('Fails when a feature conforms to the Feature Types and Schemas conformance class and does not contain a "featureType" member', () => {
const violations = applyRules(metadata, {
type: DocumentTypes.FEATURE,
conformsTo: [CC_CORE_URI, CC_TYPES_SCHEMAS_URI],
} as Feature);

expect(violations.length).toBe(1);
});
});

describe('Requirement 18B', () => {
test('Succeeds when a feature collection contains a "featureType" member', () => {
const violations = applyRules(metadata, {
type: DocumentTypes.FEATURE_COLLECTION,
conformsTo: [CC_CORE_URI, CC_TYPES_SCHEMAS_URI],
featureType: 'app:building',
features: [
{
type: DocumentTypes.FEATURE,
},
],
} as FeatureCollection);

expect(violations.length).toBe(0);
});

test('Succeeds when a feature collection contains a "featureType" member in every individual feature', () => {
const violations = applyRules(metadata, {
type: DocumentTypes.FEATURE_COLLECTION,
conformsTo: [CC_CORE_URI, CC_TYPES_SCHEMAS_URI],
features: [
{
type: DocumentTypes.FEATURE,
featureType: 'app:building',
},
{
type: DocumentTypes.FEATURE,
featureType: 'app:building',
},
],
} as FeatureCollection);

expect(violations.length).toBe(0);
});

test('Fails when both a feature collection and individual features contain a "featureType" member', () => {
const violations = applyRules(metadata, {
type: DocumentTypes.FEATURE_COLLECTION,
conformsTo: [CC_CORE_URI, CC_TYPES_SCHEMAS_URI],
featureType: 'app:building',
features: [
{
type: DocumentTypes.FEATURE,
featureType: 'app:building',
},
],
} as FeatureCollection);

expect(violations.length).toBe(1);
});

test('Fails when not every individual feature contains a "featureType" member', () => {
const violations = applyRules(metadata, {
type: DocumentTypes.FEATURE_COLLECTION,
conformsTo: [CC_CORE_URI, CC_TYPES_SCHEMAS_URI],
features: [
{
type: DocumentTypes.FEATURE,
featureType: 'app:building',
},
{
type: DocumentTypes.FEATURE,
},
],
} as FeatureCollection);

expect(violations.length).toBe(1);
});
});
95 changes: 95 additions & 0 deletions src/validation/rules/types-schemas-metadata.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import { FeatureDocument } from '../../types';
import { Rule } from '../ruleValidation';

export const CC_TYPES_SCHEMAS_URI = 'http://www.opengis.net/spec/json-fg-1/0.2/conf/types-schemas';

export const CC_TYPES_SCHEMAS_CURIE = '[ogc-json-fg-1-0.2:types-schemas]';

const conformsToTypesSchemas = (doc: FeatureDocument) =>
doc.conformsTo !== undefined &&
(doc.conformsTo.includes(CC_TYPES_SCHEMAS_URI) || doc.conformsTo.includes(CC_TYPES_SCHEMAS_CURIE));

const rules: Rule[] = [];

rules.push({
name: '/req/types-schemas/metadata',
validateFeature: (feature, isRoot) => {
if (isRoot && feature.featureType !== undefined && !conformsToTypesSchemas(feature)) {
return {
pointer: '/conformsTo',
message:
'When the "featureType" member is present, the "conformsTo" member of the JSON document SHALL include at ' +
'least the Feature Types and Schemas conformance class.',
};
}
},
validateFeatureCollection: featureCollection => {
if (
(featureCollection.featureType !== undefined ||
featureCollection.features.some(feature => feature.featureType !== undefined)) &&
!conformsToTypesSchemas(featureCollection)
) {
return {
pointer: '/conformsTo',
message:
'When the "featureType" member is present, the "conformsTo" member of the JSON document SHALL include at ' +
'least the Feature Types and Schemas conformance class.',
};
}
},
});

rules.push({
name: '/req/types-schemas/feature-type',
validateFeature: (feature, isRoot) => {
if (isRoot && conformsToTypesSchemas(feature) && feature.featureType === undefined) {
return {
pointer: '/conformsTo',
message:
'When the document conforms to the Feature Types and Schemas conformance class, the "featureType" member ' +
'must be present.',
};
}
},
validateFeatureCollection: featureCollection => {
if (
conformsToTypesSchemas(featureCollection) &&
featureCollection.featureType === undefined &&
featureCollection.features.every(feature => feature.featureType === undefined)
) {
return {
pointer: '/conformsTo',
message:
'When the document conforms to the Feature Types and Schemas conformance class, the "featureType" member ' +
'must be present in either the collection or in every individual feature.',
};
}

if (
conformsToTypesSchemas(featureCollection) &&
featureCollection.featureType !== undefined &&
featureCollection.features.some(feature => feature.featureType !== undefined)
) {
return {
pointer: '/conformsTo',
message:
'When the document contains a "featureType" member, individual members may not contain a "featureType" member.',
};
}

if (
conformsToTypesSchemas(featureCollection) &&
featureCollection.featureType === undefined &&
featureCollection.features.some(feature => feature.featureType !== undefined) &&
!featureCollection.features.every(feature => feature.featureType !== undefined)
) {
return {
pointer: '/conformsTo',
message:
'When the document does not contain a "featureType" member, every individual feature must contain a "featureType" member.',
};
}
},
});

export default rules;

0 comments on commit 1f872de

Please sign in to comment.