@graph-knowledge/api 0.1.0
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/README.md +396 -0
- package/package.json +44 -0
- package/src/index.d.ts +18 -0
- package/src/index.js +19 -0
- package/src/lib/clients/firebase-auth-client.d.ts +24 -0
- package/src/lib/clients/firebase-auth-client.js +76 -0
- package/src/lib/clients/firebase-firestore-client.d.ts +22 -0
- package/src/lib/clients/firebase-firestore-client.js +79 -0
- package/src/lib/config/api-config.d.ts +20 -0
- package/src/lib/config/api-config.js +0 -0
- package/src/lib/constants/element-defaults.d.ts +15 -0
- package/src/lib/constants/element-defaults.js +19 -0
- package/src/lib/errors/api-errors.d.ts +33 -0
- package/src/lib/errors/api-errors.js +51 -0
- package/src/lib/graph-knowledge-api.d.ts +106 -0
- package/src/lib/graph-knowledge-api.js +154 -0
- package/src/lib/interfaces/auth-client.interface.d.ts +35 -0
- package/src/lib/interfaces/auth-client.interface.js +0 -0
- package/src/lib/interfaces/batch-operations.interface.d.ts +46 -0
- package/src/lib/interfaces/batch-operations.interface.js +0 -0
- package/src/lib/interfaces/document-operations.interface.d.ts +51 -0
- package/src/lib/interfaces/document-operations.interface.js +0 -0
- package/src/lib/interfaces/element-operations.interface.d.ts +57 -0
- package/src/lib/interfaces/element-operations.interface.js +0 -0
- package/src/lib/interfaces/element-validator.interface.d.ts +42 -0
- package/src/lib/interfaces/element-validator.interface.js +0 -0
- package/src/lib/interfaces/firestore-client.interface.d.ts +62 -0
- package/src/lib/interfaces/firestore-client.interface.js +0 -0
- package/src/lib/interfaces/node-operations.interface.d.ts +62 -0
- package/src/lib/interfaces/node-operations.interface.js +0 -0
- package/src/lib/models/document.model.d.ts +73 -0
- package/src/lib/models/document.model.js +13 -0
- package/src/lib/models/index.d.ts +6 -0
- package/src/lib/models/index.js +5 -0
- package/src/lib/operations/batch-operations.d.ts +30 -0
- package/src/lib/operations/batch-operations.js +181 -0
- package/src/lib/operations/document-operations.d.ts +20 -0
- package/src/lib/operations/document-operations.js +108 -0
- package/src/lib/operations/element-operations.d.ts +33 -0
- package/src/lib/operations/element-operations.js +175 -0
- package/src/lib/operations/node-operations.d.ts +22 -0
- package/src/lib/operations/node-operations.js +89 -0
- package/src/lib/testing/index.d.ts +2 -0
- package/src/lib/testing/index.js +3 -0
- package/src/lib/testing/mock-auth-client.d.ts +26 -0
- package/src/lib/testing/mock-auth-client.js +49 -0
- package/src/lib/testing/mock-firestore-client.d.ts +32 -0
- package/src/lib/testing/mock-firestore-client.js +126 -0
- package/src/lib/types/api-types.d.ts +61 -0
- package/src/lib/types/api-types.js +0 -0
- package/src/lib/types/element-input-types.d.ts +237 -0
- package/src/lib/types/element-input-types.js +3 -0
- package/src/lib/utils/link-level-manager.d.ts +66 -0
- package/src/lib/utils/link-level-manager.js +200 -0
- package/src/lib/utils/uuid.d.ts +5 -0
- package/src/lib/utils/uuid.js +16 -0
- package/src/lib/validators/document-validator.d.ts +22 -0
- package/src/lib/validators/document-validator.js +68 -0
- package/src/lib/validators/element-type-validators/base-element-validator.d.ts +35 -0
- package/src/lib/validators/element-type-validators/base-element-validator.js +96 -0
- package/src/lib/validators/element-type-validators/connector-validator.d.ts +13 -0
- package/src/lib/validators/element-type-validators/connector-validator.js +66 -0
- package/src/lib/validators/element-type-validators/custom-shape-validator.d.ts +22 -0
- package/src/lib/validators/element-type-validators/custom-shape-validator.js +44 -0
- package/src/lib/validators/element-type-validators/rectangle-validator.d.ts +11 -0
- package/src/lib/validators/element-type-validators/rectangle-validator.js +31 -0
- package/src/lib/validators/element-type-validators/text-validator.d.ts +14 -0
- package/src/lib/validators/element-type-validators/text-validator.js +66 -0
- package/src/lib/validators/element-type-validators/uml-validators.d.ts +58 -0
- package/src/lib/validators/element-type-validators/uml-validators.js +123 -0
- package/src/lib/validators/element-validator-registry.d.ts +18 -0
- package/src/lib/validators/element-validator-registry.js +58 -0
- package/src/lib/validators/node-validator.d.ts +26 -0
- package/src/lib/validators/node-validator.js +90 -0
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { ValidationError } from "../../errors/api-errors";
|
|
2
|
+
/**
|
|
3
|
+
* Base class for element type validators.
|
|
4
|
+
* Provides common validation logic for position, dimensions, and colors.
|
|
5
|
+
*/
|
|
6
|
+
export class BaseElementValidator {
|
|
7
|
+
/**
|
|
8
|
+
* Validates common element properties (position, dimensions, rotation).
|
|
9
|
+
* @param input The element input to validate
|
|
10
|
+
* @throws ValidationError if validation fails
|
|
11
|
+
*/
|
|
12
|
+
validateCommon(input) {
|
|
13
|
+
this.validatePosition(input);
|
|
14
|
+
this.validateDimensions(input);
|
|
15
|
+
this.validateRotation(input);
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Validates position properties (x, y).
|
|
19
|
+
*/
|
|
20
|
+
validatePosition(input) {
|
|
21
|
+
if (typeof input.x !== "number" || isNaN(input.x)) {
|
|
22
|
+
throw new ValidationError("x must be a valid number", "x");
|
|
23
|
+
}
|
|
24
|
+
if (typeof input.y !== "number" || isNaN(input.y)) {
|
|
25
|
+
throw new ValidationError("y must be a valid number", "y");
|
|
26
|
+
}
|
|
27
|
+
if (input.x < 0) {
|
|
28
|
+
throw new ValidationError("x must be non-negative", "x");
|
|
29
|
+
}
|
|
30
|
+
if (input.y < 0) {
|
|
31
|
+
throw new ValidationError("y must be non-negative", "y");
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Validates dimension properties (width, height).
|
|
36
|
+
*/
|
|
37
|
+
validateDimensions(input) {
|
|
38
|
+
if (input.width !== undefined) {
|
|
39
|
+
if (typeof input.width !== "number" || isNaN(input.width)) {
|
|
40
|
+
throw new ValidationError("width must be a valid number", "width");
|
|
41
|
+
}
|
|
42
|
+
if (input.width < 0) {
|
|
43
|
+
throw new ValidationError("width must be non-negative", "width");
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
if (input.height !== undefined) {
|
|
47
|
+
if (typeof input.height !== "number" || isNaN(input.height)) {
|
|
48
|
+
throw new ValidationError("height must be a valid number", "height");
|
|
49
|
+
}
|
|
50
|
+
if (input.height < 0) {
|
|
51
|
+
throw new ValidationError("height must be non-negative", "height");
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Validates rotation property.
|
|
57
|
+
*/
|
|
58
|
+
validateRotation(input) {
|
|
59
|
+
if (input.rotation !== undefined) {
|
|
60
|
+
if (typeof input.rotation !== "number" || isNaN(input.rotation)) {
|
|
61
|
+
throw new ValidationError("rotation must be a valid number", "rotation");
|
|
62
|
+
}
|
|
63
|
+
if (input.rotation < 0 || input.rotation >= 360) {
|
|
64
|
+
throw new ValidationError("rotation must be in range [0, 360)", "rotation");
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Validates a hex color string.
|
|
70
|
+
* @param value The color value to validate
|
|
71
|
+
* @param field The field name for error messages
|
|
72
|
+
*/
|
|
73
|
+
validateColor(value, field) {
|
|
74
|
+
if (value === undefined)
|
|
75
|
+
return;
|
|
76
|
+
if (typeof value !== "string") {
|
|
77
|
+
throw new ValidationError(`${field} must be a string`, field);
|
|
78
|
+
}
|
|
79
|
+
if (!value.match(/^#([0-9A-Fa-f]{3}|[0-9A-Fa-f]{6})$/)) {
|
|
80
|
+
throw new ValidationError(`${field} must be a valid hex color (e.g., #FF0000)`, field);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Validates stroke width.
|
|
85
|
+
*/
|
|
86
|
+
validateStrokeWidth(value, field) {
|
|
87
|
+
if (value === undefined)
|
|
88
|
+
return;
|
|
89
|
+
if (typeof value !== "number" || isNaN(value)) {
|
|
90
|
+
throw new ValidationError(`${field} must be a valid number`, field);
|
|
91
|
+
}
|
|
92
|
+
if (value < 0) {
|
|
93
|
+
throw new ValidationError(`${field} must be non-negative`, field);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { IElementTypeValidator } from "../../interfaces/element-validator.interface";
|
|
2
|
+
import { AnyElementInput } from "../../types/element-input-types";
|
|
3
|
+
import { BaseElementValidator } from "./base-element-validator";
|
|
4
|
+
/**
|
|
5
|
+
* Validator for connector elements.
|
|
6
|
+
*/
|
|
7
|
+
export declare class ConnectorValidator extends BaseElementValidator implements IElementTypeValidator {
|
|
8
|
+
readonly elementType = "connector";
|
|
9
|
+
validate(input: AnyElementInput): void;
|
|
10
|
+
private validateAnchor;
|
|
11
|
+
private validateLineStyle;
|
|
12
|
+
private validateMarker;
|
|
13
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { ValidationError } from "../../errors/api-errors";
|
|
2
|
+
import { BaseElementValidator } from "./base-element-validator";
|
|
3
|
+
/**
|
|
4
|
+
* Valid connector anchor points matching the graph editor's snap geometry labels.
|
|
5
|
+
*/
|
|
6
|
+
const VALID_ANCHORS = [
|
|
7
|
+
"edge-top",
|
|
8
|
+
"edge-right",
|
|
9
|
+
"edge-bottom",
|
|
10
|
+
"edge-left",
|
|
11
|
+
"center"
|
|
12
|
+
];
|
|
13
|
+
const VALID_LINE_STYLES = ["solid", "dashed", "dotted"];
|
|
14
|
+
const VALID_MARKERS = ["none", "arrow", "diamond", "circle"];
|
|
15
|
+
/**
|
|
16
|
+
* Validator for connector elements.
|
|
17
|
+
*/
|
|
18
|
+
export class ConnectorValidator extends BaseElementValidator {
|
|
19
|
+
elementType = "connector";
|
|
20
|
+
validate(input) {
|
|
21
|
+
if (input.type !== "connector") {
|
|
22
|
+
throw new ValidationError(`Expected type "connector", got "${input.type}"`, "type");
|
|
23
|
+
}
|
|
24
|
+
const connectorInput = input;
|
|
25
|
+
// Note: Connectors don't use x/y positions - they're determined by connected elements
|
|
26
|
+
// So we don't call validateCommon() which requires x/y
|
|
27
|
+
// Required fields
|
|
28
|
+
if (!connectorInput.startElementId ||
|
|
29
|
+
typeof connectorInput.startElementId !== "string") {
|
|
30
|
+
throw new ValidationError("startElementId is required", "startElementId");
|
|
31
|
+
}
|
|
32
|
+
if (!connectorInput.endElementId ||
|
|
33
|
+
typeof connectorInput.endElementId !== "string") {
|
|
34
|
+
throw new ValidationError("endElementId is required", "endElementId");
|
|
35
|
+
}
|
|
36
|
+
// Validate connector-specific properties
|
|
37
|
+
this.validateAnchor(connectorInput.startAnchor, "startAnchor");
|
|
38
|
+
this.validateAnchor(connectorInput.endAnchor, "endAnchor");
|
|
39
|
+
this.validateColor(connectorInput.strokeColor, "strokeColor");
|
|
40
|
+
this.validateStrokeWidth(connectorInput.strokeWidth, "strokeWidth");
|
|
41
|
+
this.validateLineStyle(connectorInput.lineStyle);
|
|
42
|
+
this.validateMarker(connectorInput.startMarker, "startMarker");
|
|
43
|
+
this.validateMarker(connectorInput.endMarker, "endMarker");
|
|
44
|
+
}
|
|
45
|
+
validateAnchor(value, field) {
|
|
46
|
+
if (value === undefined)
|
|
47
|
+
return;
|
|
48
|
+
if (!VALID_ANCHORS.includes(value)) {
|
|
49
|
+
throw new ValidationError(`${field} must be one of: ${VALID_ANCHORS.join(", ")}`, field);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
validateLineStyle(value) {
|
|
53
|
+
if (value === undefined)
|
|
54
|
+
return;
|
|
55
|
+
if (!VALID_LINE_STYLES.includes(value)) {
|
|
56
|
+
throw new ValidationError(`lineStyle must be one of: ${VALID_LINE_STYLES.join(", ")}`, "lineStyle");
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
validateMarker(value, field) {
|
|
60
|
+
if (value === undefined)
|
|
61
|
+
return;
|
|
62
|
+
if (!VALID_MARKERS.includes(value)) {
|
|
63
|
+
throw new ValidationError(`${field} must be one of: ${VALID_MARKERS.join(", ")}`, field);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { IElementTypeValidator } from "../../interfaces/element-validator.interface";
|
|
2
|
+
import { AnyElementInput } from "../../types/element-input-types";
|
|
3
|
+
import { BaseElementValidator } from "./base-element-validator";
|
|
4
|
+
/**
|
|
5
|
+
* Validator for custom shape elements.
|
|
6
|
+
* Handles elements with type "custom:{shapeId}".
|
|
7
|
+
*/
|
|
8
|
+
export declare class CustomShapeValidator extends BaseElementValidator implements IElementTypeValidator {
|
|
9
|
+
private readonly shapeId;
|
|
10
|
+
/**
|
|
11
|
+
* Creates a validator for a specific custom shape.
|
|
12
|
+
* @param shapeId The custom shape ID this validator handles
|
|
13
|
+
*/
|
|
14
|
+
constructor(shapeId: string);
|
|
15
|
+
get elementType(): string;
|
|
16
|
+
validate(input: AnyElementInput): void;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Factory function to create a custom shape validator.
|
|
20
|
+
* @param shapeId The custom shape ID
|
|
21
|
+
*/
|
|
22
|
+
export declare function createCustomShapeValidator(shapeId: string): CustomShapeValidator;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { ValidationError } from "../../errors/api-errors";
|
|
2
|
+
import { BaseElementValidator } from "./base-element-validator";
|
|
3
|
+
/**
|
|
4
|
+
* Validator for custom shape elements.
|
|
5
|
+
* Handles elements with type "custom:{shapeId}".
|
|
6
|
+
*/
|
|
7
|
+
export class CustomShapeValidator extends BaseElementValidator {
|
|
8
|
+
shapeId;
|
|
9
|
+
/**
|
|
10
|
+
* Creates a validator for a specific custom shape.
|
|
11
|
+
* @param shapeId The custom shape ID this validator handles
|
|
12
|
+
*/
|
|
13
|
+
constructor(shapeId) {
|
|
14
|
+
super();
|
|
15
|
+
this.shapeId = shapeId;
|
|
16
|
+
}
|
|
17
|
+
get elementType() {
|
|
18
|
+
return `custom:${this.shapeId}`;
|
|
19
|
+
}
|
|
20
|
+
validate(input) {
|
|
21
|
+
if (!input.type.startsWith("custom:")) {
|
|
22
|
+
throw new ValidationError(`Expected custom shape type, got "${input.type}"`, "type");
|
|
23
|
+
}
|
|
24
|
+
const customInput = input;
|
|
25
|
+
// Validate common properties
|
|
26
|
+
this.validateCommon(customInput);
|
|
27
|
+
// customShapeId is required
|
|
28
|
+
if (!customInput.customShapeId ||
|
|
29
|
+
typeof customInput.customShapeId !== "string") {
|
|
30
|
+
throw new ValidationError("customShapeId is required for custom shapes", "customShapeId");
|
|
31
|
+
}
|
|
32
|
+
// Validate optional style properties
|
|
33
|
+
this.validateColor(customInput.fillColor, "fillColor");
|
|
34
|
+
this.validateColor(customInput.strokeColor, "strokeColor");
|
|
35
|
+
this.validateStrokeWidth(customInput.strokeWidth, "strokeWidth");
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Factory function to create a custom shape validator.
|
|
40
|
+
* @param shapeId The custom shape ID
|
|
41
|
+
*/
|
|
42
|
+
export function createCustomShapeValidator(shapeId) {
|
|
43
|
+
return new CustomShapeValidator(shapeId);
|
|
44
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { IElementTypeValidator } from "../../interfaces/element-validator.interface";
|
|
2
|
+
import { AnyElementInput } from "../../types/element-input-types";
|
|
3
|
+
import { BaseElementValidator } from "./base-element-validator";
|
|
4
|
+
/**
|
|
5
|
+
* Validator for rectangle elements.
|
|
6
|
+
*/
|
|
7
|
+
export declare class RectangleValidator extends BaseElementValidator implements IElementTypeValidator {
|
|
8
|
+
readonly elementType = "rectangle";
|
|
9
|
+
validate(input: AnyElementInput): void;
|
|
10
|
+
private validateCornerRadius;
|
|
11
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { ValidationError } from "../../errors/api-errors";
|
|
2
|
+
import { BaseElementValidator } from "./base-element-validator";
|
|
3
|
+
/**
|
|
4
|
+
* Validator for rectangle elements.
|
|
5
|
+
*/
|
|
6
|
+
export class RectangleValidator extends BaseElementValidator {
|
|
7
|
+
elementType = "rectangle";
|
|
8
|
+
validate(input) {
|
|
9
|
+
if (input.type !== "rectangle") {
|
|
10
|
+
throw new ValidationError(`Expected type "rectangle", got "${input.type}"`, "type");
|
|
11
|
+
}
|
|
12
|
+
const rectangleInput = input;
|
|
13
|
+
// Validate common properties
|
|
14
|
+
this.validateCommon(rectangleInput);
|
|
15
|
+
// Validate rectangle-specific properties
|
|
16
|
+
this.validateColor(rectangleInput.fillColor, "fillColor");
|
|
17
|
+
this.validateColor(rectangleInput.strokeColor, "strokeColor");
|
|
18
|
+
this.validateStrokeWidth(rectangleInput.strokeWidth, "strokeWidth");
|
|
19
|
+
this.validateCornerRadius(rectangleInput.cornerRadius);
|
|
20
|
+
}
|
|
21
|
+
validateCornerRadius(value) {
|
|
22
|
+
if (value === undefined)
|
|
23
|
+
return;
|
|
24
|
+
if (typeof value !== "number" || isNaN(value)) {
|
|
25
|
+
throw new ValidationError("cornerRadius must be a valid number", "cornerRadius");
|
|
26
|
+
}
|
|
27
|
+
if (value < 0) {
|
|
28
|
+
throw new ValidationError("cornerRadius must be non-negative", "cornerRadius");
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { IElementTypeValidator } from "../../interfaces/element-validator.interface";
|
|
2
|
+
import { AnyElementInput } from "../../types/element-input-types";
|
|
3
|
+
import { BaseElementValidator } from "./base-element-validator";
|
|
4
|
+
/**
|
|
5
|
+
* Validator for text elements.
|
|
6
|
+
*/
|
|
7
|
+
export declare class TextValidator extends BaseElementValidator implements IElementTypeValidator {
|
|
8
|
+
readonly elementType = "text";
|
|
9
|
+
validate(input: AnyElementInput): void;
|
|
10
|
+
private validateFontSize;
|
|
11
|
+
private validateFontWeight;
|
|
12
|
+
private validateTextAlign;
|
|
13
|
+
private validateLineHeight;
|
|
14
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { ValidationError } from "../../errors/api-errors";
|
|
2
|
+
import { BaseElementValidator } from "./base-element-validator";
|
|
3
|
+
/**
|
|
4
|
+
* Validator for text elements.
|
|
5
|
+
*/
|
|
6
|
+
export class TextValidator extends BaseElementValidator {
|
|
7
|
+
elementType = "text";
|
|
8
|
+
validate(input) {
|
|
9
|
+
if (input.type !== "text") {
|
|
10
|
+
throw new ValidationError(`Expected type "text", got "${input.type}"`, "type");
|
|
11
|
+
}
|
|
12
|
+
const textInput = input;
|
|
13
|
+
// Validate common properties
|
|
14
|
+
this.validateCommon(textInput);
|
|
15
|
+
// Text content is required
|
|
16
|
+
if (textInput.text === undefined || textInput.text === null) {
|
|
17
|
+
throw new ValidationError("text is required for text elements", "text");
|
|
18
|
+
}
|
|
19
|
+
if (typeof textInput.text !== "string") {
|
|
20
|
+
throw new ValidationError("text must be a string", "text");
|
|
21
|
+
}
|
|
22
|
+
// Validate text-specific properties
|
|
23
|
+
this.validateColor(textInput.fillColor, "fillColor");
|
|
24
|
+
this.validateFontSize(textInput.fontSize);
|
|
25
|
+
this.validateFontWeight(textInput.fontWeight);
|
|
26
|
+
this.validateTextAlign(textInput.textAlign);
|
|
27
|
+
this.validateLineHeight(textInput.lineHeight);
|
|
28
|
+
}
|
|
29
|
+
validateFontSize(value) {
|
|
30
|
+
if (value === undefined)
|
|
31
|
+
return;
|
|
32
|
+
if (typeof value !== "number" || isNaN(value)) {
|
|
33
|
+
throw new ValidationError("fontSize must be a valid number", "fontSize");
|
|
34
|
+
}
|
|
35
|
+
if (value <= 0) {
|
|
36
|
+
throw new ValidationError("fontSize must be positive", "fontSize");
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
validateFontWeight(value) {
|
|
40
|
+
if (value === undefined)
|
|
41
|
+
return;
|
|
42
|
+
if (typeof value !== "number" || isNaN(value)) {
|
|
43
|
+
throw new ValidationError("fontWeight must be a valid number", "fontWeight");
|
|
44
|
+
}
|
|
45
|
+
if (value < 100 || value > 900) {
|
|
46
|
+
throw new ValidationError("fontWeight must be between 100 and 900", "fontWeight");
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
validateTextAlign(value) {
|
|
50
|
+
if (value === undefined)
|
|
51
|
+
return;
|
|
52
|
+
if (!["left", "center", "right"].includes(value)) {
|
|
53
|
+
throw new ValidationError('textAlign must be "left", "center", or "right"', "textAlign");
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
validateLineHeight(value) {
|
|
57
|
+
if (value === undefined)
|
|
58
|
+
return;
|
|
59
|
+
if (typeof value !== "number" || isNaN(value)) {
|
|
60
|
+
throw new ValidationError("lineHeight must be a valid number", "lineHeight");
|
|
61
|
+
}
|
|
62
|
+
if (value <= 0) {
|
|
63
|
+
throw new ValidationError("lineHeight must be positive", "lineHeight");
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { IElementTypeValidator } from "../../interfaces/element-validator.interface";
|
|
2
|
+
import { AnyElementInput } from "../../types/element-input-types";
|
|
3
|
+
import { BaseElementValidator } from "./base-element-validator";
|
|
4
|
+
/**
|
|
5
|
+
* Base validator for UML elements.
|
|
6
|
+
* Provides common validation for UML-specific properties.
|
|
7
|
+
*/
|
|
8
|
+
declare abstract class BaseUmlValidator extends BaseElementValidator implements IElementTypeValidator {
|
|
9
|
+
abstract readonly elementType: string;
|
|
10
|
+
validate(input: AnyElementInput): void;
|
|
11
|
+
/**
|
|
12
|
+
* Override in subclasses for type-specific validation.
|
|
13
|
+
*/
|
|
14
|
+
protected validateSpecific(_input: AnyElementInput): void;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Validator for UML class elements.
|
|
18
|
+
*/
|
|
19
|
+
export declare class UmlClassValidator extends BaseUmlValidator {
|
|
20
|
+
readonly elementType = "uml-class";
|
|
21
|
+
protected validateSpecific(input: AnyElementInput): void;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Validator for UML interface elements.
|
|
25
|
+
*/
|
|
26
|
+
export declare class UmlInterfaceValidator extends BaseUmlValidator {
|
|
27
|
+
readonly elementType = "uml-interface";
|
|
28
|
+
protected validateSpecific(input: AnyElementInput): void;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Validator for UML component elements.
|
|
32
|
+
*/
|
|
33
|
+
export declare class UmlComponentValidator extends BaseUmlValidator {
|
|
34
|
+
readonly elementType = "uml-component";
|
|
35
|
+
protected validateSpecific(input: AnyElementInput): void;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Validator for UML package elements.
|
|
39
|
+
*/
|
|
40
|
+
export declare class UmlPackageValidator extends BaseUmlValidator {
|
|
41
|
+
readonly elementType = "uml-package";
|
|
42
|
+
protected validateSpecific(input: AnyElementInput): void;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Validator for UML artifact elements.
|
|
46
|
+
*/
|
|
47
|
+
export declare class UmlArtifactValidator extends BaseUmlValidator {
|
|
48
|
+
readonly elementType = "uml-artifact";
|
|
49
|
+
protected validateSpecific(input: AnyElementInput): void;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Validator for UML note elements.
|
|
53
|
+
*/
|
|
54
|
+
export declare class UmlNoteValidator extends BaseUmlValidator {
|
|
55
|
+
readonly elementType = "uml-note";
|
|
56
|
+
protected validateSpecific(input: AnyElementInput): void;
|
|
57
|
+
}
|
|
58
|
+
export {};
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import { ValidationError } from "../../errors/api-errors";
|
|
2
|
+
import { BaseElementValidator } from "./base-element-validator";
|
|
3
|
+
/**
|
|
4
|
+
* Base validator for UML elements.
|
|
5
|
+
* Provides common validation for UML-specific properties.
|
|
6
|
+
*/
|
|
7
|
+
class BaseUmlValidator extends BaseElementValidator {
|
|
8
|
+
validate(input) {
|
|
9
|
+
if (input.type !== this.elementType) {
|
|
10
|
+
throw new ValidationError(`Expected type "${this.elementType}", got "${input.type}"`, "type");
|
|
11
|
+
}
|
|
12
|
+
// Validate common properties - cast is safe since we've verified the type
|
|
13
|
+
// and UML elements always have required x/y
|
|
14
|
+
this.validateCommon(input);
|
|
15
|
+
// Validate UML-common properties
|
|
16
|
+
const umlInput = input;
|
|
17
|
+
this.validateColor(umlInput["fillColor"], "fillColor");
|
|
18
|
+
this.validateColor(umlInput["strokeColor"], "strokeColor");
|
|
19
|
+
this.validateStrokeWidth(umlInput["strokeWidth"], "strokeWidth");
|
|
20
|
+
// Delegate to subclass for type-specific validation
|
|
21
|
+
this.validateSpecific(input);
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Override in subclasses for type-specific validation.
|
|
25
|
+
*/
|
|
26
|
+
validateSpecific(_input) {
|
|
27
|
+
// Default: no additional validation
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Validator for UML class elements.
|
|
32
|
+
*/
|
|
33
|
+
export class UmlClassValidator extends BaseUmlValidator {
|
|
34
|
+
elementType = "uml-class";
|
|
35
|
+
validateSpecific(input) {
|
|
36
|
+
const classInput = input;
|
|
37
|
+
if (classInput["name"] !== undefined &&
|
|
38
|
+
typeof classInput["name"] !== "string") {
|
|
39
|
+
throw new ValidationError("name must be a string", "name");
|
|
40
|
+
}
|
|
41
|
+
if (classInput["attributes"] !== undefined &&
|
|
42
|
+
typeof classInput["attributes"] !== "string") {
|
|
43
|
+
throw new ValidationError("attributes must be a string", "attributes");
|
|
44
|
+
}
|
|
45
|
+
if (classInput["methods"] !== undefined &&
|
|
46
|
+
typeof classInput["methods"] !== "string") {
|
|
47
|
+
throw new ValidationError("methods must be a string", "methods");
|
|
48
|
+
}
|
|
49
|
+
if (classInput["stereotype"] !== undefined &&
|
|
50
|
+
typeof classInput["stereotype"] !== "string") {
|
|
51
|
+
throw new ValidationError("stereotype must be a string", "stereotype");
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Validator for UML interface elements.
|
|
57
|
+
*/
|
|
58
|
+
export class UmlInterfaceValidator extends BaseUmlValidator {
|
|
59
|
+
elementType = "uml-interface";
|
|
60
|
+
validateSpecific(input) {
|
|
61
|
+
const interfaceInput = input;
|
|
62
|
+
if (interfaceInput["name"] !== undefined &&
|
|
63
|
+
typeof interfaceInput["name"] !== "string") {
|
|
64
|
+
throw new ValidationError("name must be a string", "name");
|
|
65
|
+
}
|
|
66
|
+
if (interfaceInput["methods"] !== undefined &&
|
|
67
|
+
typeof interfaceInput["methods"] !== "string") {
|
|
68
|
+
throw new ValidationError("methods must be a string", "methods");
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Validator for UML component elements.
|
|
74
|
+
*/
|
|
75
|
+
export class UmlComponentValidator extends BaseUmlValidator {
|
|
76
|
+
elementType = "uml-component";
|
|
77
|
+
validateSpecific(input) {
|
|
78
|
+
const componentInput = input;
|
|
79
|
+
if (componentInput["name"] !== undefined &&
|
|
80
|
+
typeof componentInput["name"] !== "string") {
|
|
81
|
+
throw new ValidationError("name must be a string", "name");
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Validator for UML package elements.
|
|
87
|
+
*/
|
|
88
|
+
export class UmlPackageValidator extends BaseUmlValidator {
|
|
89
|
+
elementType = "uml-package";
|
|
90
|
+
validateSpecific(input) {
|
|
91
|
+
const packageInput = input;
|
|
92
|
+
if (packageInput["name"] !== undefined &&
|
|
93
|
+
typeof packageInput["name"] !== "string") {
|
|
94
|
+
throw new ValidationError("name must be a string", "name");
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Validator for UML artifact elements.
|
|
100
|
+
*/
|
|
101
|
+
export class UmlArtifactValidator extends BaseUmlValidator {
|
|
102
|
+
elementType = "uml-artifact";
|
|
103
|
+
validateSpecific(input) {
|
|
104
|
+
const artifactInput = input;
|
|
105
|
+
if (artifactInput["name"] !== undefined &&
|
|
106
|
+
typeof artifactInput["name"] !== "string") {
|
|
107
|
+
throw new ValidationError("name must be a string", "name");
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Validator for UML note elements.
|
|
113
|
+
*/
|
|
114
|
+
export class UmlNoteValidator extends BaseUmlValidator {
|
|
115
|
+
elementType = "uml-note";
|
|
116
|
+
validateSpecific(input) {
|
|
117
|
+
const noteInput = input;
|
|
118
|
+
if (noteInput["text"] !== undefined &&
|
|
119
|
+
typeof noteInput["text"] !== "string") {
|
|
120
|
+
throw new ValidationError("text must be a string", "text");
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { IElementTypeValidator, IElementValidatorRegistry } from "../interfaces/element-validator.interface";
|
|
2
|
+
import { AnyElementInput } from "../types/element-input-types";
|
|
3
|
+
/**
|
|
4
|
+
* Registry for element type validators.
|
|
5
|
+
* Implements Open/Closed principle - new validators can be registered
|
|
6
|
+
* without modifying this class.
|
|
7
|
+
*/
|
|
8
|
+
export declare class ElementValidatorRegistry implements IElementValidatorRegistry {
|
|
9
|
+
private readonly validators;
|
|
10
|
+
constructor();
|
|
11
|
+
/**
|
|
12
|
+
* Registers built-in validators for standard element types.
|
|
13
|
+
*/
|
|
14
|
+
private registerBuiltInValidators;
|
|
15
|
+
register(validator: IElementTypeValidator): void;
|
|
16
|
+
getValidator(elementType: string): IElementTypeValidator | undefined;
|
|
17
|
+
validate(input: AnyElementInput): void;
|
|
18
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { ValidationError } from "../errors/api-errors";
|
|
2
|
+
import { RectangleValidator } from "./element-type-validators/rectangle-validator";
|
|
3
|
+
import { TextValidator } from "./element-type-validators/text-validator";
|
|
4
|
+
import { ConnectorValidator } from "./element-type-validators/connector-validator";
|
|
5
|
+
import { UmlClassValidator, UmlInterfaceValidator, UmlComponentValidator, UmlPackageValidator, UmlArtifactValidator, UmlNoteValidator } from "./element-type-validators/uml-validators";
|
|
6
|
+
import { CustomShapeValidator } from "./element-type-validators/custom-shape-validator";
|
|
7
|
+
/**
|
|
8
|
+
* Registry for element type validators.
|
|
9
|
+
* Implements Open/Closed principle - new validators can be registered
|
|
10
|
+
* without modifying this class.
|
|
11
|
+
*/
|
|
12
|
+
export class ElementValidatorRegistry {
|
|
13
|
+
validators = new Map();
|
|
14
|
+
constructor() {
|
|
15
|
+
// Register built-in validators
|
|
16
|
+
this.registerBuiltInValidators();
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Registers built-in validators for standard element types.
|
|
20
|
+
*/
|
|
21
|
+
registerBuiltInValidators() {
|
|
22
|
+
this.register(new RectangleValidator());
|
|
23
|
+
this.register(new TextValidator());
|
|
24
|
+
this.register(new ConnectorValidator());
|
|
25
|
+
this.register(new UmlClassValidator());
|
|
26
|
+
this.register(new UmlInterfaceValidator());
|
|
27
|
+
this.register(new UmlComponentValidator());
|
|
28
|
+
this.register(new UmlPackageValidator());
|
|
29
|
+
this.register(new UmlArtifactValidator());
|
|
30
|
+
this.register(new UmlNoteValidator());
|
|
31
|
+
}
|
|
32
|
+
register(validator) {
|
|
33
|
+
this.validators.set(validator.elementType, validator);
|
|
34
|
+
}
|
|
35
|
+
getValidator(elementType) {
|
|
36
|
+
// Check for exact match first
|
|
37
|
+
const validator = this.validators.get(elementType);
|
|
38
|
+
if (validator) {
|
|
39
|
+
return validator;
|
|
40
|
+
}
|
|
41
|
+
// Handle custom shapes - create validator on demand
|
|
42
|
+
if (elementType.startsWith("custom:")) {
|
|
43
|
+
const shapeId = elementType.substring(7); // Remove "custom:" prefix
|
|
44
|
+
const customValidator = new CustomShapeValidator(shapeId);
|
|
45
|
+
// Cache for future use
|
|
46
|
+
this.validators.set(elementType, customValidator);
|
|
47
|
+
return customValidator;
|
|
48
|
+
}
|
|
49
|
+
return undefined;
|
|
50
|
+
}
|
|
51
|
+
validate(input) {
|
|
52
|
+
const validator = this.getValidator(input.type);
|
|
53
|
+
if (!validator) {
|
|
54
|
+
throw new ValidationError(`Unknown element type: ${input.type}`, "type");
|
|
55
|
+
}
|
|
56
|
+
validator.validate(input);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { CreateNodeInput, UpdateNodeInput } from "../types/api-types";
|
|
2
|
+
/**
|
|
3
|
+
* Validator for node operations.
|
|
4
|
+
*/
|
|
5
|
+
export declare class NodeValidator {
|
|
6
|
+
/**
|
|
7
|
+
* Validates input for node creation.
|
|
8
|
+
* @param input The creation input to validate
|
|
9
|
+
* @throws ValidationError if validation fails
|
|
10
|
+
*/
|
|
11
|
+
validateCreate(input: CreateNodeInput): void;
|
|
12
|
+
/**
|
|
13
|
+
* Validates input for node update.
|
|
14
|
+
* @param input The update input to validate
|
|
15
|
+
* @throws ValidationError if validation fails
|
|
16
|
+
*/
|
|
17
|
+
validateUpdate(input: UpdateNodeInput): void;
|
|
18
|
+
/**
|
|
19
|
+
* Validates canvas dimensions.
|
|
20
|
+
*/
|
|
21
|
+
private validateCanvasDimensions;
|
|
22
|
+
/**
|
|
23
|
+
* Validates node level.
|
|
24
|
+
*/
|
|
25
|
+
private validateLevel;
|
|
26
|
+
}
|