UNPKG

typir

Version:

General purpose type checking library

91 lines 4.02 kB
/****************************************************************************** * 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