@globaltypesystem/gts-ts 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/.eslintrc.json +16 -0
- package/.github/workflows/ci.yml +198 -0
- package/.gitmodules +3 -0
- package/.prettierrc +7 -0
- package/LICENSE +201 -0
- package/Makefile +64 -0
- package/README.md +298 -0
- package/dist/cast.d.ts +9 -0
- package/dist/cast.d.ts.map +1 -0
- package/dist/cast.js +153 -0
- package/dist/cast.js.map +1 -0
- package/dist/cli/index.d.ts +3 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +318 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/compatibility.d.ts +11 -0
- package/dist/compatibility.d.ts.map +1 -0
- package/dist/compatibility.js +176 -0
- package/dist/compatibility.js.map +1 -0
- package/dist/extract.d.ts +13 -0
- package/dist/extract.d.ts.map +1 -0
- package/dist/extract.js +194 -0
- package/dist/extract.js.map +1 -0
- package/dist/gts.d.ts +18 -0
- package/dist/gts.d.ts.map +1 -0
- package/dist/gts.js +472 -0
- package/dist/gts.js.map +1 -0
- package/dist/index.d.ts +29 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +97 -0
- package/dist/index.js.map +1 -0
- package/dist/query.d.ts +10 -0
- package/dist/query.d.ts.map +1 -0
- package/dist/query.js +171 -0
- package/dist/query.js.map +1 -0
- package/dist/relationships.d.ts +7 -0
- package/dist/relationships.d.ts.map +1 -0
- package/dist/relationships.js +80 -0
- package/dist/relationships.js.map +1 -0
- package/dist/server/index.d.ts +2 -0
- package/dist/server/index.d.ts.map +1 -0
- package/dist/server/index.js +132 -0
- package/dist/server/index.js.map +1 -0
- package/dist/server/server.d.ts +33 -0
- package/dist/server/server.d.ts.map +1 -0
- package/dist/server/server.js +678 -0
- package/dist/server/server.js.map +1 -0
- package/dist/server/types.d.ts +61 -0
- package/dist/server/types.d.ts.map +1 -0
- package/dist/server/types.js +3 -0
- package/dist/server/types.js.map +1 -0
- package/dist/store.d.ts +39 -0
- package/dist/store.d.ts.map +1 -0
- package/dist/store.js +1026 -0
- package/dist/store.js.map +1 -0
- package/dist/types.d.ts +111 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +29 -0
- package/dist/types.js.map +1 -0
- package/dist/x-gts-ref.d.ts +35 -0
- package/dist/x-gts-ref.d.ts.map +1 -0
- package/dist/x-gts-ref.js +304 -0
- package/dist/x-gts-ref.js.map +1 -0
- package/jest.config.js +13 -0
- package/package.json +54 -0
- package/src/cast.ts +179 -0
- package/src/cli/index.ts +315 -0
- package/src/compatibility.ts +201 -0
- package/src/extract.ts +213 -0
- package/src/gts.ts +550 -0
- package/src/index.ts +97 -0
- package/src/query.ts +191 -0
- package/src/relationships.ts +91 -0
- package/src/server/index.ts +112 -0
- package/src/server/server.ts +771 -0
- package/src/server/types.ts +74 -0
- package/src/store.ts +1178 -0
- package/src/types.ts +138 -0
- package/src/x-gts-ref.ts +349 -0
- package/tests/gts.test.ts +525 -0
- package/tsconfig.json +32 -0
package/src/types.ts
ADDED
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
export const GTS_PREFIX = 'gts.';
|
|
2
|
+
export const GTS_URI_PREFIX = 'gts://';
|
|
3
|
+
export const MAX_ID_LENGTH = 1024;
|
|
4
|
+
|
|
5
|
+
export interface GtsIDSegment {
|
|
6
|
+
num: number;
|
|
7
|
+
offset: number;
|
|
8
|
+
segment: string;
|
|
9
|
+
vendor: string;
|
|
10
|
+
package: string;
|
|
11
|
+
namespace: string;
|
|
12
|
+
type: string;
|
|
13
|
+
verMajor: number;
|
|
14
|
+
verMinor?: number;
|
|
15
|
+
isType: boolean;
|
|
16
|
+
isWildcard: boolean;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export interface GtsID {
|
|
20
|
+
id: string;
|
|
21
|
+
segments: GtsIDSegment[];
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export interface ValidationResult {
|
|
25
|
+
id: string;
|
|
26
|
+
ok: boolean;
|
|
27
|
+
valid?: boolean;
|
|
28
|
+
error: string;
|
|
29
|
+
is_wildcard?: boolean;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export interface ParseResult {
|
|
33
|
+
ok: boolean;
|
|
34
|
+
segments: GtsIDSegment[];
|
|
35
|
+
error?: string;
|
|
36
|
+
is_schema?: boolean;
|
|
37
|
+
is_wildcard?: boolean;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export interface MatchResult {
|
|
41
|
+
match: boolean;
|
|
42
|
+
pattern: string;
|
|
43
|
+
candidate: string;
|
|
44
|
+
error?: string;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export interface UUIDResult {
|
|
48
|
+
id: string;
|
|
49
|
+
uuid: string;
|
|
50
|
+
error?: string;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export interface ExtractResult {
|
|
54
|
+
id: string;
|
|
55
|
+
schema_id: string | null;
|
|
56
|
+
selected_entity_field?: string;
|
|
57
|
+
selected_schema_id_field?: string;
|
|
58
|
+
is_schema: boolean;
|
|
59
|
+
error?: string;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export interface AttributeResult {
|
|
63
|
+
path: string;
|
|
64
|
+
resolved: boolean;
|
|
65
|
+
value?: any;
|
|
66
|
+
error?: string;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export interface QueryResult {
|
|
70
|
+
query: string;
|
|
71
|
+
count: number;
|
|
72
|
+
items: any[];
|
|
73
|
+
error?: string;
|
|
74
|
+
limit?: number;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export interface RelationshipResult {
|
|
78
|
+
id: string;
|
|
79
|
+
relationships: string[];
|
|
80
|
+
brokenReferences: string[];
|
|
81
|
+
error?: string;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export interface CompatibilityResult {
|
|
85
|
+
compatible: boolean;
|
|
86
|
+
oldId: string;
|
|
87
|
+
newId: string;
|
|
88
|
+
mode: 'backward' | 'forward' | 'full';
|
|
89
|
+
errors: string[];
|
|
90
|
+
warnings: string[];
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export interface CastResult {
|
|
94
|
+
ok: boolean;
|
|
95
|
+
fromId: string;
|
|
96
|
+
toId: string;
|
|
97
|
+
result?: any;
|
|
98
|
+
error?: string;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export interface GtsConfig {
|
|
102
|
+
validateRefs: boolean;
|
|
103
|
+
strictMode: boolean;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
export interface JsonEntity {
|
|
107
|
+
id: string;
|
|
108
|
+
schemaId: string | null;
|
|
109
|
+
content: Record<string, any>;
|
|
110
|
+
isSchema: boolean;
|
|
111
|
+
references: Set<string>;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
export class InvalidGtsIDError extends Error {
|
|
115
|
+
constructor(
|
|
116
|
+
public gtsId: string,
|
|
117
|
+
public cause?: string
|
|
118
|
+
) {
|
|
119
|
+
super(cause ? `Invalid GTS identifier: ${gtsId}: ${cause}` : `Invalid GTS identifier: ${gtsId}`);
|
|
120
|
+
this.name = 'InvalidGtsIDError';
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
export class InvalidSegmentError extends Error {
|
|
125
|
+
constructor(
|
|
126
|
+
public num: number,
|
|
127
|
+
public offset: number,
|
|
128
|
+
public segment: string,
|
|
129
|
+
public cause?: string
|
|
130
|
+
) {
|
|
131
|
+
super(
|
|
132
|
+
cause
|
|
133
|
+
? `Invalid GTS segment #${num} @ offset ${offset}: '${segment}': ${cause}`
|
|
134
|
+
: `Invalid GTS segment #${num} @ offset ${offset}: '${segment}'`
|
|
135
|
+
);
|
|
136
|
+
this.name = 'InvalidSegmentError';
|
|
137
|
+
}
|
|
138
|
+
}
|
package/src/x-gts-ref.ts
ADDED
|
@@ -0,0 +1,349 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* x-gts-ref validation for GTS schemas
|
|
3
|
+
* Validates that string values match specified GTS ID patterns
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { Gts } from './gts';
|
|
7
|
+
import { GtsStore } from './store';
|
|
8
|
+
|
|
9
|
+
export interface XGtsRefValidationError {
|
|
10
|
+
fieldPath: string;
|
|
11
|
+
value: any;
|
|
12
|
+
refPattern: string;
|
|
13
|
+
reason: string;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export class XGtsRefValidator {
|
|
17
|
+
private store: GtsStore;
|
|
18
|
+
|
|
19
|
+
constructor(store: GtsStore) {
|
|
20
|
+
this.store = store;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Validate an instance against x-gts-ref constraints in schema
|
|
25
|
+
*/
|
|
26
|
+
validateInstance(instance: any, schema: any, instancePath: string = ''): XGtsRefValidationError[] {
|
|
27
|
+
const errors: XGtsRefValidationError[] = [];
|
|
28
|
+
this.visitInstance(instance, schema, instancePath, schema, errors);
|
|
29
|
+
return errors;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Validate x-gts-ref fields in a schema definition
|
|
34
|
+
*/
|
|
35
|
+
validateSchema(schema: any, schemaPath: string = '', rootSchema: any = null): XGtsRefValidationError[] {
|
|
36
|
+
if (!rootSchema) {
|
|
37
|
+
rootSchema = schema;
|
|
38
|
+
}
|
|
39
|
+
const errors: XGtsRefValidationError[] = [];
|
|
40
|
+
this.visitSchema(schema, schemaPath, rootSchema, errors);
|
|
41
|
+
return errors;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
private visitInstance(
|
|
45
|
+
instance: any,
|
|
46
|
+
schema: any,
|
|
47
|
+
path: string,
|
|
48
|
+
rootSchema: any,
|
|
49
|
+
errors: XGtsRefValidationError[]
|
|
50
|
+
): void {
|
|
51
|
+
if (!schema) return;
|
|
52
|
+
|
|
53
|
+
// Check for x-gts-ref constraint
|
|
54
|
+
if (schema['x-gts-ref'] !== undefined) {
|
|
55
|
+
if (typeof instance === 'string') {
|
|
56
|
+
const err = this.validateRefValue(instance, schema['x-gts-ref'], path, rootSchema);
|
|
57
|
+
if (err) {
|
|
58
|
+
errors.push(err);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Recurse into object properties
|
|
64
|
+
if (schema.type === 'object' && schema.properties) {
|
|
65
|
+
if (instance && typeof instance === 'object') {
|
|
66
|
+
for (const propName in schema.properties) {
|
|
67
|
+
if (propName in instance) {
|
|
68
|
+
const propPath = path ? `${path}.${propName}` : propName;
|
|
69
|
+
this.visitInstance(instance[propName], schema.properties[propName], propPath, rootSchema, errors);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// Recurse into array items
|
|
76
|
+
if (schema.type === 'array' && schema.items) {
|
|
77
|
+
if (Array.isArray(instance)) {
|
|
78
|
+
instance.forEach((item, idx) => {
|
|
79
|
+
const itemPath = `${path}[${idx}]`;
|
|
80
|
+
this.visitInstance(item, schema.items, itemPath, rootSchema, errors);
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
private visitSchema(schema: any, path: string, rootSchema: any, errors: XGtsRefValidationError[]): void {
|
|
87
|
+
if (!schema || typeof schema !== 'object') return;
|
|
88
|
+
|
|
89
|
+
// Check for x-gts-ref field
|
|
90
|
+
if (schema['x-gts-ref'] !== undefined) {
|
|
91
|
+
const refPath = path ? `${path}/x-gts-ref` : 'x-gts-ref';
|
|
92
|
+
const err = this.validateRefPattern(schema['x-gts-ref'], refPath, rootSchema);
|
|
93
|
+
if (err) {
|
|
94
|
+
errors.push(err);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// Recurse into nested structures
|
|
99
|
+
for (const key in schema) {
|
|
100
|
+
if (key === 'x-gts-ref') continue;
|
|
101
|
+
|
|
102
|
+
const nestedPath = path ? `${path}/${key}` : key;
|
|
103
|
+
const value = schema[key];
|
|
104
|
+
|
|
105
|
+
if (value && typeof value === 'object') {
|
|
106
|
+
if (Array.isArray(value)) {
|
|
107
|
+
value.forEach((item, idx) => {
|
|
108
|
+
if (item && typeof item === 'object') {
|
|
109
|
+
this.visitSchema(item, `${nestedPath}[${idx}]`, rootSchema, errors);
|
|
110
|
+
}
|
|
111
|
+
});
|
|
112
|
+
} else {
|
|
113
|
+
this.visitSchema(value, nestedPath, rootSchema, errors);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
private validateRefValue(
|
|
120
|
+
value: string,
|
|
121
|
+
refPattern: any,
|
|
122
|
+
fieldPath: string,
|
|
123
|
+
schema: any
|
|
124
|
+
): XGtsRefValidationError | null {
|
|
125
|
+
if (typeof refPattern !== 'string') {
|
|
126
|
+
return {
|
|
127
|
+
fieldPath,
|
|
128
|
+
value,
|
|
129
|
+
refPattern: String(refPattern),
|
|
130
|
+
reason: `Value must be a string, got ${typeof refPattern}`,
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
let resolvedPattern = refPattern;
|
|
135
|
+
|
|
136
|
+
// Resolve pattern if it's a relative reference
|
|
137
|
+
if (refPattern.startsWith('/')) {
|
|
138
|
+
const resolved = this.resolvePointer(schema, refPattern);
|
|
139
|
+
if (!resolved) {
|
|
140
|
+
return {
|
|
141
|
+
fieldPath,
|
|
142
|
+
value,
|
|
143
|
+
refPattern,
|
|
144
|
+
reason: `Cannot resolve reference path '${refPattern}'`,
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// Check if the resolved value is a pointer that needs further resolution
|
|
149
|
+
if (resolved.startsWith('/')) {
|
|
150
|
+
const furtherResolved = this.resolvePointer(schema, resolved);
|
|
151
|
+
if (!furtherResolved) {
|
|
152
|
+
return {
|
|
153
|
+
fieldPath,
|
|
154
|
+
value,
|
|
155
|
+
refPattern,
|
|
156
|
+
reason: `Cannot resolve nested reference '${refPattern}' -> '${resolved}'`,
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
resolvedPattern = furtherResolved;
|
|
160
|
+
} else {
|
|
161
|
+
resolvedPattern = resolved;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
if (!resolvedPattern.startsWith('gts.')) {
|
|
165
|
+
return {
|
|
166
|
+
fieldPath,
|
|
167
|
+
value,
|
|
168
|
+
refPattern,
|
|
169
|
+
reason: `Resolved reference '${refPattern}' -> '${resolvedPattern}' is not a GTS pattern`,
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// Validate against GTS pattern
|
|
175
|
+
return this.validateGtsPattern(value, resolvedPattern, fieldPath);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
private validateRefPattern(refPattern: any, fieldPath: string, rootSchema: any): XGtsRefValidationError | null {
|
|
179
|
+
if (typeof refPattern !== 'string') {
|
|
180
|
+
return {
|
|
181
|
+
fieldPath,
|
|
182
|
+
value: refPattern,
|
|
183
|
+
refPattern: '',
|
|
184
|
+
reason: `x-gts-ref value must be a string, got ${typeof refPattern}`,
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// Case 1: Absolute GTS pattern
|
|
189
|
+
if (refPattern.startsWith('gts.')) {
|
|
190
|
+
return this.validateGtsIDOrPattern(refPattern, fieldPath);
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// Case 2: Relative reference
|
|
194
|
+
if (refPattern.startsWith('/')) {
|
|
195
|
+
const resolved = this.resolvePointer(rootSchema, refPattern);
|
|
196
|
+
if (!resolved) {
|
|
197
|
+
return {
|
|
198
|
+
fieldPath,
|
|
199
|
+
value: refPattern,
|
|
200
|
+
refPattern,
|
|
201
|
+
reason: `Cannot resolve reference path '${refPattern}'`,
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
if (!Gts.isValidGtsID(resolved)) {
|
|
205
|
+
return {
|
|
206
|
+
fieldPath,
|
|
207
|
+
value: refPattern,
|
|
208
|
+
refPattern,
|
|
209
|
+
reason: `Resolved reference '${refPattern}' -> '${resolved}' is not a valid GTS identifier`,
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
return null;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
return {
|
|
216
|
+
fieldPath,
|
|
217
|
+
value: refPattern,
|
|
218
|
+
refPattern,
|
|
219
|
+
reason: `Invalid x-gts-ref value: '${refPattern}' must start with 'gts.' or '/'`,
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
private validateGtsIDOrPattern(pattern: string, fieldPath: string): XGtsRefValidationError | null {
|
|
224
|
+
if (pattern === 'gts.*') {
|
|
225
|
+
return null; // Valid wildcard
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
if (pattern.includes('*')) {
|
|
229
|
+
// Wildcard pattern - validate prefix
|
|
230
|
+
const prefix = pattern.replace('*', '');
|
|
231
|
+
if (!prefix.startsWith('gts.')) {
|
|
232
|
+
return {
|
|
233
|
+
fieldPath,
|
|
234
|
+
value: pattern,
|
|
235
|
+
refPattern: pattern,
|
|
236
|
+
reason: `Invalid GTS wildcard pattern: ${pattern}`,
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
return null;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
// Specific GTS ID
|
|
243
|
+
if (!Gts.isValidGtsID(pattern)) {
|
|
244
|
+
return {
|
|
245
|
+
fieldPath,
|
|
246
|
+
value: pattern,
|
|
247
|
+
refPattern: pattern,
|
|
248
|
+
reason: `Invalid GTS identifier: ${pattern}`,
|
|
249
|
+
};
|
|
250
|
+
}
|
|
251
|
+
return null;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
private validateGtsPattern(value: string, pattern: string, fieldPath: string): XGtsRefValidationError | null {
|
|
255
|
+
// Validate it's a valid GTS ID
|
|
256
|
+
if (!Gts.isValidGtsID(value)) {
|
|
257
|
+
return {
|
|
258
|
+
fieldPath,
|
|
259
|
+
value,
|
|
260
|
+
refPattern: pattern,
|
|
261
|
+
reason: `Value '${value}' is not a valid GTS identifier`,
|
|
262
|
+
};
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
// Check pattern match
|
|
266
|
+
if (pattern === 'gts.*') {
|
|
267
|
+
// Any valid GTS ID matches
|
|
268
|
+
} else if (pattern.endsWith('*')) {
|
|
269
|
+
const prefix = pattern.slice(0, -1);
|
|
270
|
+
if (!value.startsWith(prefix)) {
|
|
271
|
+
return {
|
|
272
|
+
fieldPath,
|
|
273
|
+
value,
|
|
274
|
+
refPattern: pattern,
|
|
275
|
+
reason: `Value '${value}' does not match pattern '${pattern}'`,
|
|
276
|
+
};
|
|
277
|
+
}
|
|
278
|
+
} else if (!value.startsWith(pattern)) {
|
|
279
|
+
return {
|
|
280
|
+
fieldPath,
|
|
281
|
+
value,
|
|
282
|
+
refPattern: pattern,
|
|
283
|
+
reason: `Value '${value}' does not match pattern '${pattern}'`,
|
|
284
|
+
};
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
// Optionally check if entity exists in store
|
|
288
|
+
if (this.store) {
|
|
289
|
+
const entity = this.store.get(value);
|
|
290
|
+
if (!entity) {
|
|
291
|
+
return {
|
|
292
|
+
fieldPath,
|
|
293
|
+
value,
|
|
294
|
+
refPattern: pattern,
|
|
295
|
+
reason: `Referenced entity '${value}' not found in registry`,
|
|
296
|
+
};
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
return null;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
/**
|
|
304
|
+
* Strip the "gts://" prefix from a value if present
|
|
305
|
+
*/
|
|
306
|
+
private stripGtsURIPrefix(value: string): string {
|
|
307
|
+
return value.replace(/^gts:\/\//, '');
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
/**
|
|
311
|
+
* Resolve a JSON Pointer in the schema
|
|
312
|
+
* Note: For /$id references, the gts:// prefix is stripped from the value
|
|
313
|
+
*/
|
|
314
|
+
private resolvePointer(schema: any, pointer: string): string {
|
|
315
|
+
const path = pointer.startsWith('/') ? pointer.slice(1) : pointer;
|
|
316
|
+
if (!path) return '';
|
|
317
|
+
|
|
318
|
+
const parts = path.split('/');
|
|
319
|
+
let current: any = schema;
|
|
320
|
+
|
|
321
|
+
for (const part of parts) {
|
|
322
|
+
if (!current || typeof current !== 'object') {
|
|
323
|
+
return '';
|
|
324
|
+
}
|
|
325
|
+
current = current[part];
|
|
326
|
+
if (current === undefined) {
|
|
327
|
+
return '';
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
// If current is a string, return it (stripping gts:// prefix if present)
|
|
332
|
+
if (typeof current === 'string') {
|
|
333
|
+
return this.stripGtsURIPrefix(current);
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
// If current is a dict with x-gts-ref, resolve it
|
|
337
|
+
if (current && typeof current === 'object' && current['x-gts-ref']) {
|
|
338
|
+
const xGtsRef = current['x-gts-ref'];
|
|
339
|
+
if (typeof xGtsRef === 'string') {
|
|
340
|
+
if (xGtsRef.startsWith('/')) {
|
|
341
|
+
return this.resolvePointer(schema, xGtsRef);
|
|
342
|
+
}
|
|
343
|
+
return xGtsRef;
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
return '';
|
|
348
|
+
}
|
|
349
|
+
}
|