Skip to content

Commit

Permalink
fix: Generate unique pointer correctly (#13635)
Browse files Browse the repository at this point in the history
  • Loading branch information
TomasEng committed Sep 25, 2024
1 parent 034c44d commit 714001c
Show file tree
Hide file tree
Showing 5 changed files with 110 additions and 11 deletions.
33 changes: 27 additions & 6 deletions frontend/packages/schema-model/src/lib/SchemaModel.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import {
allOfNodeChildMock,
allOfNodeMock,
arrayNodeMock,
combinationDefNodeChild1Mock,
combinationDefNodeMock,
combinationNodeWithMultipleChildrenMock,
defNodeMock,
defNodeWithChildrenChildMock,
Expand All @@ -16,6 +18,7 @@ import {
parentNodeMock,
referenceDefinitionMock,
referenceNodeMock,
referenceToCombinationDefNodeMock,
referenceToObjectNodeMock,
requiredNodeMock,
rootNodeMock,
Expand Down Expand Up @@ -145,18 +148,24 @@ describe('SchemaModel', () => {
});

describe('getSchemaPointerByUniquePointer', () => {
const uniqueGrandChildPointer =
'#/properties/referenceToParent/properties/child/properties/grandchild';
const uniqueChildPointer = '#/properties/referenceToParent/properties/child';

it('Returns the schema pointer for a given unique pointer', () => {
it('Returns the schema pointer for a given unique pointer to an object', () => {
const uniqueGrandChildPointer =
'#/properties/referenceToParent/properties/child/properties/grandchild';
const uniqueChildPointer = '#/properties/referenceToParent/properties/child';
expect(schemaModel.getSchemaPointerByUniquePointer(uniqueChildPointer)).toEqual(
defNodeWithChildrenChildMock.schemaPointer,
);
expect(schemaModel.getSchemaPointerByUniquePointer(uniqueGrandChildPointer)).toEqual(
defNodeWithChildrenGrandchildMock.schemaPointer,
);
});

it('Returns the schema pointer for a given unique pointer to a combination', () => {
const uniquePointer = '#/properties/referenceToCombinationDef/oneOf/0';
const expectedResult = combinationDefNodeChild1Mock.schemaPointer;
const result = schemaModel.getSchemaPointerByUniquePointer(uniquePointer);
expect(result).toEqual(expectedResult);
});
});

describe('getUniquePointer', () => {
Expand All @@ -172,7 +181,7 @@ describe('SchemaModel', () => {
);
});

it('Returns a pointer reflecting the path to a given node in a reference', () => {
it('Returns a pointer reflecting the path to a given node in a reference to an object', () => {
const expectedChildPointer = '#/properties/referenceToParent/properties/child';
const expectedGrandchildPointer =
'#/properties/referenceToParent/properties/child/properties/grandchild';
Expand All @@ -190,6 +199,14 @@ describe('SchemaModel', () => {
),
).toEqual(expectedGrandchildPointer);
});

it('Returns a pointer reflecting the path to a given node in a reference to a combination', () => {
const { schemaPointer } = combinationDefNodeChild1Mock;
const uniquePointerOfParent = referenceToCombinationDefNodeMock.schemaPointer;
const result = schemaModel.getUniquePointer(schemaPointer, uniquePointerOfParent);
const expectedResult = '#/properties/referenceToCombinationDef/oneOf/0';
expect(result).toEqual(expectedResult);
});
});

describe('hasNode', () => {
Expand Down Expand Up @@ -229,6 +246,7 @@ describe('SchemaModel', () => {
unusedDefinitionMock,
unusedDefinitionWithSameNameAsExistingObjectMock,
referenceDefinitionMock,
combinationDefNodeMock,
]);
});
});
Expand All @@ -244,6 +262,7 @@ describe('SchemaModel', () => {
referenceToObjectNodeMock,
nodeWithSameNameAsStringNodeMock,
combinationNodeWithMultipleChildrenMock,
referenceToCombinationDefNodeMock,
]);
});
});
Expand All @@ -264,6 +283,8 @@ describe('SchemaModel', () => {
referenceDefinitionMock,
nodeWithSameNameAsStringNodeMock,
combinationNodeWithMultipleChildrenMock,
referenceToCombinationDefNodeMock,
combinationDefNodeMock,
]);
});
});
Expand Down
8 changes: 4 additions & 4 deletions frontend/packages/schema-model/src/lib/SchemaModel.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import {
CombinationKind,
FieldType,
Keyword,
type NodePosition,
type UiSchemaNode,
type UiSchemaNodes,
Expand Down Expand Up @@ -31,6 +30,7 @@ import { replaceStart } from 'app-shared/utils/stringUtils';
import {
createDefinitionPointer,
createPropertyPointer,
extractCategoryFromPointer,
extractNameFromPointer,
makePointerFromArray,
} from './pointerUtils';
Expand Down Expand Up @@ -90,7 +90,7 @@ export class SchemaModel {
const parentNodePointer = this.getParentSchemaPointerByUniquePointer(uniquePointer);
return makePointerFromArray([
parentNodePointer,
Keyword.Properties,
extractCategoryFromPointer(uniquePointer),
extractNameFromPointer(uniquePointer),
]);
}
Expand All @@ -109,8 +109,8 @@ export class SchemaModel {

public getUniquePointer(schemaPointer: string, uniqueParentPointer?: string): string {
if (!uniqueParentPointer || !isDefinitionPointer(schemaPointer)) return schemaPointer;

return `${uniqueParentPointer}/properties/${extractNameFromPointer(schemaPointer)}`;
const category = extractCategoryFromPointer(schemaPointer);
return `${uniqueParentPointer}/${category}/${extractNameFromPointer(schemaPointer)}`;
}

public hasNode(schemaPointer: string): boolean {
Expand Down
25 changes: 25 additions & 0 deletions frontend/packages/schema-model/src/lib/pointerUtils.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {
changeNameInPointer,
createDefinitionPointer,
createPropertyPointer,
extractCategoryFromPointer,
extractNameFromPointer,
makePointerFromArray,
} from './pointerUtils';
Expand All @@ -13,6 +14,7 @@ import {
simpleParentNodeMock,
stringNodeMock,
} from '../../test/uiSchemaMock';
import { CombinationKind, Keyword } from '@altinn/schema-model/types';

describe('pointerUtils', () => {
test('makePointerFromArray', () => {
Expand Down Expand Up @@ -65,6 +67,29 @@ describe('pointerUtils', () => {
});
});

describe('extractCategoryFromPointer', () => {
it('Returns "properties" when the pointer is a property pointer', () => {
expect(extractCategoryFromPointer('#/properties/hello')).toBe(Keyword.Properties);
expect(extractCategoryFromPointer('#/anyOf/hello/properties/world')).toBe(Keyword.Properties);
expect(extractCategoryFromPointer('#/$defs/test/properties/hello')).toBe(Keyword.Properties);
});

it('Returns the combination kind when the pointer is a combination pointer', () => {
expect(extractCategoryFromPointer('#/allOf/0')).toBe(CombinationKind.AllOf);
expect(extractCategoryFromPointer('#/properties/test/anyOf/1')).toBe(CombinationKind.AnyOf);
expect(extractCategoryFromPointer('#/allOf/test/oneOf/2')).toBe(CombinationKind.OneOf);
expect(extractCategoryFromPointer('#/$defs/test/anyOf/3')).toBe(CombinationKind.AnyOf);
});

it('Returns "$defs" when the pointer is a definition pointer', () => {
expect(extractCategoryFromPointer('#/$defs/test')).toBe(Keyword.Definitions);
});

it('Returns undefined when the pointer is the root pointer', () => {
expect(extractCategoryFromPointer('#')).toBe(undefined);
});
});

describe('changeNameInPointer', () => {
it('Changes the last part of the pointer', () => {
expect(changeNameInPointer('#/$defs/hello', 'world')).toBe('#/$defs/world');
Expand Down
20 changes: 19 additions & 1 deletion frontend/packages/schema-model/src/lib/pointerUtils.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import type { UiSchemaNode } from '../types';
import { Keyword, ObjectKind } from '../types';
import { CombinationKind, Keyword, ObjectKind } from '../types';

import { ROOT_POINTER } from './constants';
import type { FieldNode } from '../types/FieldNode';
import type { CombinationNode } from '../types/CombinationNode';
Expand Down Expand Up @@ -45,6 +46,23 @@ export const extractNameFromPointer = (pointer: string): string => {
return parts.pop();
};

export const extractCategoryFromPointer = (
pointer: string,
): Keyword.Properties | Keyword.Definitions | CombinationKind | undefined => {
const parts = pointer.split('/');
const category = parts[parts.length - 2];
switch (category) {
case Keyword.Properties:
case Keyword.Definitions:
case CombinationKind.AllOf:
case CombinationKind.AnyOf:
case CombinationKind.OneOf:
return category;
default:
return undefined;
}
};

export const changeNameInPointer = (pointer: string, newName: string): string => {
const parts = pointer.split('/');
parts.pop();
Expand Down
35 changes: 35 additions & 0 deletions frontend/packages/schema-model/test/uiSchemaMock.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,11 @@ const combinationNodeChild1Pointer = '#/properties/combinationNodeWithMultipleCh
const combinationNodeChild2Pointer = '#/properties/combinationNodeWithMultipleChildren/anyOf/1';
const combinationNodeChild3Pointer = '#/properties/combinationNodeWithMultipleChildren/anyOf/2';

const combinationDefNodePointer = '#/$defs/combinationDef';
const combinationDefNodeChild1Pointer = '#/$defs/combinationDef/oneOf/0';
const combinationDefNodeChild2Pointer = '#/$defs/combinationDef/oneOf/1';
const referenceToCombinationDefNodePointer = '#/properties/referenceToCombinationDef';

export const nodeMockBase: UiSchemaNode = {
objectKind: ObjectKind.Field,
fieldType: FieldType.String,
Expand Down Expand Up @@ -77,6 +82,8 @@ export const rootNodeMock: FieldNode = {
referenceDefinitionPointer,
nodeWithSameNameAsStringNodePointer,
combinationNodeWithMultipleChildrenPointer,
referenceToCombinationDefNodePointer,
combinationDefNodePointer,
],
};

Expand Down Expand Up @@ -274,6 +281,30 @@ export const combinationNodeChild3Mock: FieldNode = {
title: 'Child 3',
};

export const combinationDefNodeMock: CombinationNode = {
...nodeMockBase,
schemaPointer: combinationDefNodePointer,
objectKind: ObjectKind.Combination,
combinationType: CombinationKind.OneOf,
children: [combinationDefNodeChild1Pointer, combinationDefNodeChild2Pointer],
};

export const combinationDefNodeChild1Mock: FieldNode = {
...nodeMockBase,
schemaPointer: combinationDefNodeChild1Pointer,
};

export const combinationDefNodeChild2Mock: FieldNode = {
...nodeMockBase,
schemaPointer: combinationDefNodeChild2Pointer,
};

export const referenceToCombinationDefNodeMock: ReferenceNode = {
...defaultReferenceNode,
schemaPointer: referenceToCombinationDefNodePointer,
reference: combinationDefNodePointer,
};

export const uiSchemaMock: UiSchemaNodes = [
rootNodeMock,
parentNodeMock,
Expand Down Expand Up @@ -305,4 +336,8 @@ export const uiSchemaMock: UiSchemaNodes = [
combinationNodeChild1Mock,
combinationNodeChild2Mock,
combinationNodeChild3Mock,
combinationDefNodeMock,
combinationDefNodeChild1Mock,
combinationDefNodeChild2Mock,
referenceToCombinationDefNodeMock,
];

0 comments on commit 714001c

Please sign in to comment.