typir
Version:
General purpose type checking library
91 lines • 4.02 kB
JavaScript
/******************************************************************************
* Copyright 2025 TypeFox GmbH
* This program and the accompanying materials are made available under the
* terms of the MIT License, which is available in the project root.
******************************************************************************/
import { isMap, isSet } from 'util/types';
import { Type } from '../../graph/type-node.js';
import { TypeInitializer } from '../../initialization/type-initializer.js';
import { TypeReference } from '../../initialization/type-reference.js';
import { CustomTypeInitializer } from './custom-initializer.js';
export class CustomKind {
constructor(services, options) {
this.$name = `CustomKind-${options.name}`;
this.services = services;
this.services.infrastructure.Kinds.register(this);
this.options = this.collectOptions(options);
}
collectOptions(options) {
return Object.assign({}, options);
}
get(properties) {
return new TypeReference(() => this.calculateIdentifier(properties), this.services);
}
create(typeDetails) {
return new CustomConfigurationChainImpl(this.services, this, typeDetails);
}
calculateIdentifier(properties) {
if (this.options.calculateTypeIdentifier) {
return this.options.calculateTypeIdentifier(properties);
}
else {
return `custom-${this.options.name /*is unique for all custom kinds*/}-${this.calculateIdentifierAll(properties)}`;
}
}
calculateIdentifierAll(properties) {
return Object.entries(properties)
.map(entry => `${entry[0]}:${this.calculateIdentifierSingle(entry[1])}`)
.join(',');
}
calculateIdentifierSingle(value) {
// all possible TypeDescriptors
if (typeof value === 'function') {
return this.services.infrastructure.TypeResolver.resolve(value).getIdentifier();
}
else if (value instanceof Type
|| value instanceof TypeInitializer
|| value instanceof TypeReference
|| this.services.Language.isLanguageNode(value)) {
return this.services.infrastructure.TypeResolver.resolve(value).getIdentifier();
}
// grouping with Array, Set, Map
else if (Array.isArray(value)) {
return `[${value.map(content => this.calculateIdentifierSingle(content)).join(',')}]`;
}
else if (isSet(value)) {
return `(${Array.from(value.entries()).map(content => this.calculateIdentifierSingle(content)).sort().join(',')})`; // stable order of elements required
}
else if (isMap(value)) {
return `{${Array.from(value.entries()).sort((c1, c2) => c1[0].localeCompare(c2[0])).map(content => `${content[0]}=${this.calculateIdentifierSingle(content[1])}`).join(',')}}`; // stable order of elements required
}
// primitives
else if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean' || typeof value === 'bigint' || typeof value === 'symbol') {
return String(value);
}
// composite with recursive object / index signature
else if (typeof value === 'object' && value !== null) {
return this.calculateIdentifierAll(value);
}
else {
throw new Error(`missing implementation for ${value}`);
}
}
}
export function isCustomKind(kind) {
return kind instanceof CustomKind;
}
class CustomConfigurationChainImpl {
constructor(services, kind, typeDetails) {
this.services = services;
this.kind = kind;
this.typeDetails = Object.assign(Object.assign({}, typeDetails), { inferenceRules: [] });
}
inferenceRule(rule) {
this.typeDetails.inferenceRules.push(rule);
return this;
}
finish() {
return new CustomTypeInitializer(this.kind, this.typeDetails);
}
}
//# sourceMappingURL=custom-kind.js.map