New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

@travetto/schema

Package Overview
Dependencies
Maintainers
1
Versions
329
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@travetto/schema - npm Package Compare versions

Comparing version 3.1.2 to 3.1.3

2

package.json
{
"name": "@travetto/schema",
"version": "3.1.2",
"version": "3.1.3",
"description": "Data type registry for runtime validation, reflection and binding.",

@@ -5,0 +5,0 @@ "keywords": [

@@ -5,3 +5,3 @@ import { Class } from '@travetto/base';

import { SchemaRegistry } from '../service/registry';
import { ViewFieldsConfig } from '../service/types';
import { ClassConfig, ViewFieldsConfig } from '../service/types';
import { DeepPartial } from '../types';

@@ -15,3 +15,3 @@ import { ValidatorFn } from '../validate/types';

*/
export function Schema() { // Auto is used during compilation
export function Schema(cfg?: Partial<Pick<ClassConfig, 'subTypeField' | 'baseType'>>) { // Auto is used during compilation
return <T, U extends Class<T>>(target: U): U => {

@@ -21,3 +21,3 @@ target.from ??= function <V>(this: Class<V>, data: DeepPartial<V>, view?: string): V {

};
SchemaRegistry.getOrCreatePending(target);
SchemaRegistry.register(target, cfg);
return target;

@@ -55,3 +55,3 @@ };

*/
export function SubType<T>(name: string) {
export function SubType<T>(name?: string) {
return (target: Class<Partial<T>>): void => {

@@ -58,0 +58,0 @@ SchemaRegistry.registerSubTypes(target, name);

@@ -1,2 +0,3 @@

import { Class, AppError, ObjectUtil, ClassInstance, ConcreteClass } from '@travetto/base';
import { RootIndex } from '@travetto/manifest';
import { Class, AppError } from '@travetto/base';
import { MetadataRegistry, RootRegistry, ChangeEvent } from '@travetto/registry';

@@ -8,16 +9,7 @@

function hasType<T>(o: unknown): o is { type: Class<T> | string } {
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
return !!o && !ObjectUtil.isPrimitive(o) && 'type' in (o as object) && !!(o as Record<string, string>)['type'];
}
const classToSubTypeName = (cls: Class): string => cls.name
.replace(/([A-Z])([A-Z][a-z])/g, (all, l, r) => `${l}_${r.toLowerCase()}`)
.replace(/([a-z]|\b)([A-Z])/g, (all, l, r) => l ? `${l}_${r.toLowerCase()}` : r.toLowerCase())
.toLowerCase();
function isWithType<T>(o: T, cfg: ClassConfig | undefined): o is T & { type?: string } {
return !!cfg && !!cfg.subType && 'type' in cfg.views[AllViewⲐ].schema;
}
function getConstructor<T>(o: T): ConcreteClass<T> {
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
return (o as unknown as ClassInstance<T>).constructor;
}
/**

@@ -30,4 +22,4 @@ * Schema registry for listening to changes

#subTypes = new Map<Class, Map<string, Class>>();
#typeKeys = new Map<Class, string>();
#pendingViews = new Map<Class, Map<string, ViewFieldsConfig<unknown>>>();
#baseSchema = new Map<Class, Class>();

@@ -38,10 +30,18 @@ constructor() {

#computeSubTypeName(cls: Class): string {
if (!this.#typeKeys.has(cls)) {
this.#typeKeys.set(cls, cls.name
.replace(/([A-Z])([A-Z][a-z])/g, (all, l, r) => `${l}_${r.toLowerCase()}`)
.replace(/([a-z]|\b)([A-Z])/g, (all, l, r) => l ? `${l}_${r.toLowerCase()}` : r.toLowerCase())
.toLowerCase());
/**
* Find base schema class for a given class
*/
getBaseSchema(cls: Class): Class {
if (!this.#baseSchema.has(cls)) {
let conf = this.get(cls) ?? this.getOrCreatePending(cls);
let parent = cls;
while (conf && !conf.baseType) {
parent = this.getParentClass(parent)!;
conf = this.get(parent) ?? this.pending.get(MetadataRegistry.id(parent));
}
this.#baseSchema.set(cls, conf ? parent : cls);
}
return this.#typeKeys.get(cls)!;
return this.#baseSchema.get(cls)!;
}

@@ -54,5 +54,3 @@

getSubTypeName(cls: Class): string | undefined {
if (this.get(cls).subType) {
return this.#computeSubTypeName(cls);
}
return this.get(cls).subTypeName;
}

@@ -90,4 +88,8 @@

ensureInstanceTypeField<T>(cls: Class, o: T): void {
if (isWithType(o, this.get(cls)) && !o.type) { // Do we have a type field defined
o.type = this.#computeSubTypeName(cls); // Assign if missing
const schema = this.get(cls);
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
const typeField = (schema.subTypeField) as keyof T;
if (schema.subTypeName && typeField in schema.views[AllViewⲐ].schema && !o[typeField]) { // Do we have a type field defined
// @ts-expect-error
o[typeField] = schema.subTypeName; // Assign if missing
}

@@ -120,23 +122,18 @@ }

resolveSubTypeForInstance<T>(cls: Class<T>, o: T): Class {
return this.resolveSubType(cls, hasType<T>(o) ? o.type : getConstructor(o));
}
const base = this.getBaseSchema(cls);
const clsSchema = this.get(cls);
const baseSchema = this.get(base);
/**
* Resolve the sub type for a class and a type
* @param cls The base class
* @param type The sub tye value
*/
resolveSubType(cls: Class, type: Class | string): Class {
if (this.#subTypes.has(cls)) {
const typeId = type && (typeof type === 'string' ? type : type.Ⲑid);
if (type) {
return this.#subTypes.get(cls)!.get(typeId) ?? cls;
if (clsSchema.subTypeName || baseSchema.baseType) { // We have a sub type
// @ts-expect-error
const type = o[baseSchema.subTypeField] ?? clsSchema.subTypeName ?? baseSchema.subTypeName;
const ret = this.#subTypes.get(base)!.get(type)!;
// @ts-expect-error
if (ret && !(new ret() instanceof cls)) {
throw new AppError(`Resolved class ${ret.name} is not assignable to ${cls.name}`);
}
} else if (this.get(cls)?.subType) {
const expectedType = this.#typeKeys.get(cls);
if (expectedType && typeof type === 'string' && expectedType !== type) {
throw new AppError(`Data of type ${type} does not match expected class type ${expectedType}`, 'data');
}
return ret;
} else {
return cls;
}
return cls;
}

@@ -148,4 +145,5 @@

*/
getSubTypesForClass(cls: Class): Map<string, Class> | undefined {
return this.#subTypes.get(cls);
getSubTypesForClass(cls: Class): Class[] | undefined {
const res = this.#subTypes.get(cls)?.values();
return res ? [...res] : undefined;
}

@@ -156,26 +154,25 @@

* @param cls The class to register against
* @param type The subtype name
* @param name The subtype name
*/
registerSubTypes(cls: Class, type?: string): string {
registerSubTypes(cls: Class, name?: string): void {
// Mark as subtype
(this.get(cls) ?? this.getOrCreatePending(cls)).subType = true;
const config = (this.get(cls) ?? this.getOrCreatePending(cls));
let base: Class | undefined = this.getBaseSchema(cls);
type ??= this.#computeSubTypeName(cls)!;
if (!this.#subTypes.has(base)) {
this.#subTypes.set(base, new Map());
}
this.#typeKeys.set(cls, type);
let parent = this.getParentClass(cls)!;
let parentConfig = this.get(parent);
while (parentConfig) {
if (!this.#subTypes.has(parent)) {
this.#subTypes.set(parent, new Map());
if (base !== cls || config.baseType) {
config.subTypeField = (this.get(base) ?? this.getOrCreatePending(base)).subTypeField;
config.subTypeName = name ?? config.subTypeName ?? classToSubTypeName(cls);
this.#subTypes.get(base)!.set(config.subTypeName!, cls);
}
if (base !== cls) {
while (base && ('Ⲑid' in base)) {
this.#subTypes.get(base)!.set(config.subTypeName!, cls);
const parent = this.getParentClass(base);
base = parent ? this.getBaseSchema(parent) : undefined;
}
this.#subTypes.get(parent)!.set(type, cls);
this.#subTypes.get(parent)!.set(cls.Ⲑid, cls);
parent = this.getParentClass(parent!)!;
parentConfig = this.get(parent);
}
return type;
}

@@ -207,3 +204,4 @@

validators: [],
subType: false,
subTypeField: 'type',
baseType: RootIndex.getFunctionMetadata(cls)?.abstract,
metadata: {},

@@ -359,3 +357,3 @@ methods: {},

*/
mergeConfigs(dest: ClassConfig, src: Partial<ClassConfig>): ClassConfig {
mergeConfigs(dest: ClassConfig, src: Partial<ClassConfig>, inherited = false): ClassConfig {
dest.views[AllViewⲐ] = {

@@ -365,5 +363,9 @@ schema: { ...dest.views[AllViewⲐ].schema, ...src.views?.[AllViewⲐ].schema },

};
if (!inherited) {
dest.baseType = src.baseType ?? dest.baseType;
dest.subTypeName = src.subTypeName ?? dest.subTypeName;
}
dest.methods = { ...src.methods ?? {}, ...dest.methods ?? {} };
dest.metadata = { ...src.metadata ?? {}, ...dest.metadata ?? {} };
dest.subType = src.subType || dest.subType;
dest.subTypeField = src.subTypeField ?? dest.subTypeField;
dest.title = src.title || dest.title;

@@ -411,3 +413,3 @@ dest.validators = [...src.validators ?? [], ...dest.validators];

if (parentConfig) {
config = this.mergeConfigs(config, parentConfig);
config = this.mergeConfigs(config, parentConfig, true);
}

@@ -443,3 +445,3 @@ }

this.#subTypes.clear();
this.#typeKeys.delete(cls);
this.#baseSchema.delete(cls);
this.#accessorDescriptors.delete(cls);

@@ -446,0 +448,0 @@

@@ -67,6 +67,14 @@ import { Primitive, Class } from '@travetto/base';

/**
* Is the class a sub type
* Is the class a base type
*/
subType?: boolean;
baseType?: boolean;
/**
* Sub type name
*/
subTypeName?: string;
/**
* The field the subtype is determined by
*/
subTypeField: string;
/**
* Metadata that is related to the schema structure

@@ -73,0 +81,0 @@ */

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc