Spaces:
Running
Running
File size: 2,320 Bytes
aa89cb5 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 | export type ObjectLocationSegment =
| { readonly kind: 'property'; readonly name: string }
| { readonly kind: 'index'; readonly index: number };
export type JsonFieldNamingProfile = 'camelCase' | 'snake_case' | 'PascalCase';
function lowerCamel(name: string): string {
const parts = name.split('_');
return parts[0] + parts.slice(1).map(part => part ? part[0].toUpperCase() + part.slice(1) : '').join('');
}
export function renderJsonFieldName(name: string, profile: JsonFieldNamingProfile): string {
if (profile === 'snake_case') return name;
const camel = lowerCamel(name);
if (profile === 'camelCase' || !camel) return camel;
return camel[0].toUpperCase() + camel.slice(1);
}
function escapeJsonPointer(value: string): string {
return value.replace(/~/g, '~0').replace(/\//g, '~1');
}
/** A casing-neutral location expressed with canonical KSML property names. */
export class ObjectLocation {
private constructor(public readonly segments: readonly ObjectLocationSegment[]) {}
static root(): ObjectLocation { return new ObjectLocation([]); }
static property(name: string): ObjectLocation { return ObjectLocation.root().property(name); }
property(name: string): ObjectLocation {
return new ObjectLocation([...this.segments, { kind: 'property', name }]);
}
index(index: number): ObjectLocation {
return new ObjectLocation([...this.segments, { kind: 'index', index }]);
}
prefixedBy(prefix: ObjectLocation): ObjectLocation {
return new ObjectLocation([...prefix.segments, ...this.segments]);
}
modelPath(): string {
return this.render(name => name);
}
nativePath(): string {
return this.render(lowerCamel);
}
instancePath(profile: JsonFieldNamingProfile = 'camelCase'): string {
return this.segments.map(segment => segment.kind === 'index'
? String(segment.index)
: escapeJsonPointer(renderJsonFieldName(segment.name, profile))).map(value => `/${value}`).join('');
}
toString(): string { return this.nativePath(); }
private render(propertyName: (name: string) => string): string {
let result = '';
for (const segment of this.segments) {
if (segment.kind === 'index') result += `[${segment.index}]`;
else result += `${result ? '.' : ''}${propertyName(segment.name)}`;
}
return result;
}
}
|