From a8e3f83490d42db03b3c623198ba78865ce54aa5 Mon Sep 17 00:00:00 2001 From: sinclair Date: Sun, 26 Nov 2023 23:28:20 +0900 Subject: [PATCH] Reimplement Indexed Accessors --- examples/index.ts | 4 +- src/type/resolve/exclude/exclude.ts | 73 ++++++++++++ src/type/resolve/exclude/index.ts | 29 +++++ src/type/resolve/index.ts | 1 + src/type/resolve/indexed/indexed-type.ts | 2 +- src/type/resolve/union/union.ts | 2 +- src/typebox.ts | 138 ++++++----------------- todo.md | 4 +- 8 files changed, 144 insertions(+), 109 deletions(-) create mode 100644 src/type/resolve/exclude/exclude.ts create mode 100644 src/type/resolve/exclude/index.ts diff --git a/examples/index.ts b/examples/index.ts index 53fc98e83..1135e0637 100644 --- a/examples/index.ts +++ b/examples/index.ts @@ -1,3 +1,5 @@ import { Type } from '@sinclair/typebox' -const A = Type.Extends(Type.String(), Type.Number(), Type.Literal(1), Type.Literal(2)) +const T = Type.TemplateLiteral('${A|B|C}') + +const A = Type.Extract(T, Type.Literal('D')) diff --git a/src/type/resolve/exclude/exclude.ts b/src/type/resolve/exclude/exclude.ts new file mode 100644 index 000000000..96c6c17a9 --- /dev/null +++ b/src/type/resolve/exclude/exclude.ts @@ -0,0 +1,73 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox + +The MIT License (MIT) + +Copyright (c) 2017-2023 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +import { Type, TSchema, Static, TTemplateLiteral, TLiteral, TNever, TUnion } from '../../../typebox' +import { TypeGuard } from '../../guard/index' +import { UnionResolver } from '../union/index' +import { ExtendsCheck, ExtendsResult } from '../extends/index' +import { TemplateLiteralToUnion } from '../template-literal/index' + +// prettier-ignore +export namespace ExcludeResolver { + // ------------------------------------------------------------------ + // Utility + // ------------------------------------------------------------------ + export type UnionToIntersect = (U extends unknown ? (arg: U) => 0 : never) extends (arg: infer I) => 0 ? I : never + export type UnionLast = UnionToIntersect 0 : never> extends (x: infer L) => 0 ? L : never + export type UnionToTuple> = [U] extends [never] ? [] : [...UnionToTuple>, L] + export type AssertRest = T extends E ? T : [] + export type AssertType = T extends E ? T : TNever + export type Assert = T extends E ? T : never + // ------------------------------------------------------------------ + // Resolve + // ------------------------------------------------------------------ + export type TExcludeTemplateLiteralResult = UnionResolver.Resolve }[T]>>> + export type TExcludeTemplateLiteral = Exclude, Static> extends infer S ? TExcludeTemplateLiteralResult> : never + export type TExcludeArray = AssertRest> extends Static ? never : T[K] + }[number]>> extends infer R extends TSchema[] ? UnionResolver.Resolve : never + + export type Resolve = + T extends TTemplateLiteral ? TExcludeTemplateLiteral : + T extends TUnion ? TExcludeArray : + T extends U + ? TNever + : T + export function Resolve(L: L, R: R): Resolve { + return ( + TypeGuard.TTemplateLiteral(L) ? Resolve(TemplateLiteralToUnion.Resolve(L), R) : + TypeGuard.TTemplateLiteral(R) ? Resolve(L, TemplateLiteralToUnion.Resolve(R)) : + TypeGuard.TUnion(L) ? (() => { + const narrowed = L.anyOf.filter((inner) => ExtendsCheck.Check(inner, R) === ExtendsResult.False) + return (narrowed.length === 1 ? narrowed[0] : Type.Union(narrowed)) + })() : + ExtendsCheck.Check(L, R) !== ExtendsResult.False ? Type.Never() : + L + ) as Resolve + } +} diff --git a/src/type/resolve/exclude/index.ts b/src/type/resolve/exclude/index.ts new file mode 100644 index 000000000..e44c31822 --- /dev/null +++ b/src/type/resolve/exclude/index.ts @@ -0,0 +1,29 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox + +The MIT License (MIT) + +Copyright (c) 2017-2023 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +export * from './exclude' diff --git a/src/type/resolve/index.ts b/src/type/resolve/index.ts index bcdb437bf..dbfc380da 100644 --- a/src/type/resolve/index.ts +++ b/src/type/resolve/index.ts @@ -30,6 +30,7 @@ export * from './awaited/index' export * from './composite/index' export * from './discard/index' export * from './distinct/index' +export * from './exclude/index' export * from './extends/index' export * from './extract/index' export * from './increment/index' diff --git a/src/type/resolve/indexed/indexed-type.ts b/src/type/resolve/indexed/indexed-type.ts index 9051f40cb..92066cae1 100644 --- a/src/type/resolve/indexed/indexed-type.ts +++ b/src/type/resolve/indexed/indexed-type.ts @@ -195,7 +195,7 @@ export namespace IndexedTypeResolver { ) export function Resolve(T: T, K: [...K]): Resolve { return ( - UnionResolver.Resolve(Keys(T, K)) + UnionResolver.Resolve(Keys(T, K as PropertyKey[])) ) as Resolve } } diff --git a/src/type/resolve/union/union.ts b/src/type/resolve/union/union.ts index 4134d2acd..2e4e21155 100644 --- a/src/type/resolve/union/union.ts +++ b/src/type/resolve/union/union.ts @@ -36,7 +36,7 @@ export namespace UnionResolver { T extends [TSchema] ? T[0] : Modifiers.ResolveOptionalUnion ) - export function Resolve(T: T): Resolve { + export function Resolve(T: [...T]): Resolve { return ( T.length === 0 ? Type.Never() : T.length === 1 ? T[0] : diff --git a/src/typebox.ts b/src/typebox.ts index 7ed4dbb02..0798bfdbc 100644 --- a/src/typebox.ts +++ b/src/typebox.ts @@ -43,8 +43,7 @@ import { CompositeResolver, Discard, ExtendsResolver, - ExtendsCheck, - ExtendsResult, + ExcludeResolver, ExtractResolver, IndexedTypeResolver, IndexedKeyResolver, @@ -59,7 +58,6 @@ import { PickResolver, TemplateLiteralSyntax, TemplateLiteralPattern, - TemplateLiteralToUnion, TemplateLiteralStatic, UnionResolver, } from './type/resolve/index' @@ -780,21 +778,15 @@ export class JsonTypeBuilder extends TypeBuilder { // ------------------------------------------------------------------------ /** `[Json]` Creates an Any type */ public Any(options: SchemaOptions = {}): TAny { - return ( - { ...options, [Kind]: 'Any' } - ) as unknown as TAny + return { ...options, [Kind]: 'Any' } as unknown as TAny } /** `[Json]` Creates an Array type */ public Array(schema: T, options: ArrayOptions = {}): TArray { - return ( - { ...options, [Kind]: 'Array', type: 'array', items: TypeClone.Type(schema) } - ) as unknown as TArray + return { ...options, [Kind]: 'Array', type: 'array', items: TypeClone.Type(schema) } as unknown as TArray } /** `[Json]` Creates a Boolean type */ public Boolean(options: SchemaOptions = {}): TBoolean { - return ( - { ...options, [Kind]: 'Boolean', type: 'boolean' } - ) as unknown as TBoolean + return { ...options, [Kind]: 'Boolean', type: 'boolean' } as unknown as TBoolean } /** `[Json]` Intrinsic function to Capitalize LiteralString types */ public Capitalize(T: T, options: SchemaOptions = {}): IntrinsicResolver.Resolve { @@ -815,39 +807,17 @@ export class JsonTypeBuilder extends TypeBuilder { /** `[Json]` Creates a Conditional type */ public Extends(L: L, R: R, T: T, F: F, options: SchemaOptions = {}): TExtends { const E = ExtendsResolver.Resolve(L, R, T, F) - return ( - TypeClone.Type(E, options) - ) as TExtends + return TypeClone.Type(E, options) as TExtends } /** `[Json]` Constructs a type by excluding from unionType all union members that are assignable to excludedMembers */ public Exclude(unionType: L, excludedMembers: R, options: SchemaOptions = {}): TExclude { - return ( - TypeGuard.TTemplateLiteral(unionType) ? this.Exclude(TemplateLiteralToUnion.Resolve(unionType), excludedMembers, options) : - TypeGuard.TTemplateLiteral(excludedMembers) ? this.Exclude(unionType, TemplateLiteralToUnion.Resolve(excludedMembers), options) : - TypeGuard.TUnion(unionType) ? (() => { - const narrowed = unionType.anyOf.filter((inner) => ExtendsCheck.Check(inner, excludedMembers) === ExtendsResult.False) - return (narrowed.length === 1 ? TypeClone.Type(narrowed[0], options) : this.Union(narrowed, options)) as TExclude - })() : - ExtendsCheck.Check(unionType, excludedMembers) !== ExtendsResult.False ? this.Never(options) : - TypeClone.Type(unionType, options) - ) as TExclude + const E = ExcludeResolver.Resolve(unionType, excludedMembers) + return TypeClone.Type(E, options) as TExclude } /** `[Json]` Constructs a type by extracting from type all union members that are assignable to union */ public Extract(type: L, union: R, options: SchemaOptions = {}): TExtract { const E = ExtractResolver.Resolve(type, union) - return ( - TypeClone.Type(E, options) - ) as TExtract - // return ( - // TypeGuard.TTemplateLiteral(type) ? this.Extract(TemplateLiteralToUnion.Resolve(type), union, options) : - // TypeGuard.TTemplateLiteral(union) ? this.Extract(type, TemplateLiteralToUnion.Resolve(union) as any, options) : - // TypeGuard.TUnion(type) ? (() => { - // const narrowed = type.anyOf.filter((inner) => ExtendsCheck.Check(inner, union) !== ExtendsResult.False) - // return (narrowed.length === 1 ? TypeClone.Type(narrowed[0], options) : this.Union(narrowed, options)) - // })() : - // ExtendsCheck.Check(type, union) !== ExtendsResult.False ? TypeClone.Type(type, options) : - // this.Never(options) - // ) as TExtract + return TypeClone.Type(E, options) as TExtract } /** `[Json]` Returns an Indexed property type for the given keys */ public Index>(T: T, K: K, options?: SchemaOptions): TIndex @@ -861,9 +831,7 @@ export class JsonTypeBuilder extends TypeBuilder { } /** `[Json]` Creates an Integer type */ public Integer(options: NumericOptions = {}): TInteger { - return ( - { ...options, [Kind]: 'Integer', type: 'integer' } - ) as unknown as TInteger + return { ...options, [Kind]: 'Integer', type: 'integer' } as unknown as TInteger } /** `[Json]` Creates an Intersect type */ public Intersect(T: [...T], options: IntersectOptions = {}): IntersectResolver.Resolve { @@ -882,16 +850,12 @@ export class JsonTypeBuilder extends TypeBuilder { } /** `[Json]` Creates a KeyOf type */ public KeyOf(schema: T, options: SchemaOptions = {}): KeyOfTypeResolver.Resolve { - const K = KeyOfTypeResolver.Resolve(schema) as TSchema - return ( - TypeClone.Type(K, options) - ) as KeyOfTypeResolver.Resolve + const K = KeyOfTypeResolver.Resolve(schema) + return TypeClone.Type(K, options) as KeyOfTypeResolver.Resolve } /** `[Json]` Creates a Literal type */ public Literal(value: T, options: SchemaOptions = {}): TLiteral { - return ( - { ...options, [Kind]: 'Literal', const: value, type: typeof value as 'string' | 'number' | 'boolean' } - ) as unknown as TLiteral + return { ...options, [Kind]: 'Literal', const: value, type: typeof value as 'string' | 'number' | 'boolean' } as unknown as TLiteral } /** `[Json]` Intrinsic function to Lowercase LiteralString types */ public Lowercase(T: T, options: SchemaOptions = {}): IntrinsicResolver.Resolve { @@ -899,27 +863,19 @@ export class JsonTypeBuilder extends TypeBuilder { } /** `[Json]` Creates a Never type */ public Never(options: SchemaOptions = {}): TNever { - return ( - { ...options, [Kind]: 'Never', not: {} } - ) as unknown as TNever + return { ...options, [Kind]: 'Never', not: {} } as unknown as TNever } /** `[Json]` Creates a Not type */ public Not(schema: T, options?: SchemaOptions): TNot { - return ( - { ...options, [Kind]: 'Not', not: TypeClone.Type(schema) } - ) as unknown as TNot + return { ...options, [Kind]: 'Not', not: TypeClone.Type(schema) } as unknown as TNot } /** `[Json]` Creates a Null type */ public Null(options: SchemaOptions = {}): TNull { - return ( - { ...options, [Kind]: 'Null', type: 'null' } - ) as unknown as TNull + return { ...options, [Kind]: 'Null', type: 'null' } as unknown as TNull } /** `[Json]` Creates a Number type */ public Number(options: NumericOptions = {}): TNumber { - return ( - { ...options, [Kind]: 'Number', type: 'number' } - ) as unknown as TNumber + return { ...options, [Kind]: 'Number', type: 'number' } as unknown as TNumber } /** `[Json]` Creates an Object type */ public Object(properties: T, options: ObjectOptions = {}): TObject { @@ -969,9 +925,7 @@ export class JsonTypeBuilder extends TypeBuilder { if (ValueGuard.IsUndefined(options.$id)) (options as any).$id = `T${TypeOrdinal++}` const thisType = callback({ [Kind]: 'This', $ref: `${options.$id}` } as any) thisType.$id = options.$id - return ( - { ...options, [Hint]: 'Recursive', ...thisType } - ) as unknown as TRecursive + return { ...options, [Hint]: 'Recursive', ...thisType } as unknown as TRecursive } /** `[Json]` Creates a Ref type. The referenced type must contain a $id */ public Ref(schema: T, options?: SchemaOptions): TRef @@ -995,9 +949,7 @@ export class JsonTypeBuilder extends TypeBuilder { } /** `[Json]` Creates a String type */ public String(options: StringOptions = {}): TString { - return ( - { ...options, [Kind]: 'String', type: 'string' } - ) as unknown as TString + return { ...options, [Kind]: 'String', type: 'string' } as unknown as TString } /** `[Json]` Creates a TemplateLiteral type from template dsl string */ public TemplateLiteral(syntax: T, options?: SchemaOptions): TemplateLiteralSyntax.Resolve @@ -1016,6 +968,7 @@ export class JsonTypeBuilder extends TypeBuilder { } /** `[Json]` Creates a Tuple type */ public Tuple(items: [...T], options: SchemaOptions = {}): TTuple { + // return TupleResolver.Resolve(T) const [additionalItems, minItems, maxItems] = [false, items.length, items.length] // prettier-ignore return ( @@ -1030,6 +983,7 @@ export class JsonTypeBuilder extends TypeBuilder { } /** `[Json]` Creates a Union type */ public Union(T: [...T], options: SchemaOptions = {}): UnionResolver.Resolve { + // return UnionResolver.Resolve(T) return ( T.length === 0 ? this.Never(options) : T.length === 1 ? TypeClone.Type(T[0], options) : @@ -1038,15 +992,11 @@ export class JsonTypeBuilder extends TypeBuilder { } /** `[Json]` Creates an Unknown type */ public Unknown(options: SchemaOptions = {}): TUnknown { - return ( - { ...options, [Kind]: 'Unknown' } - ) as unknown as TUnknown + return { ...options, [Kind]: 'Unknown' } as unknown as TUnknown } /** `[Json]` Creates a Unsafe type that will infers as the generic argument T */ public Unsafe(options: UnsafeOptions = {}): TUnsafe { - return ( - { ...options, [Kind]: options[Kind] || 'Unsafe' } - ) as unknown as TUnsafe + return { ...options, [Kind]: options[Kind] || 'Unsafe' } as unknown as TUnsafe } /** `[Json]` Intrinsic function to Uppercase LiteralString types */ public Uppercase(T: T, options: SchemaOptions = {}): IntrinsicResolver.Resolve { @@ -1060,9 +1010,7 @@ export class JsonTypeBuilder extends TypeBuilder { export class JavaScriptTypeBuilder extends JsonTypeBuilder { /** `[JavaScript]` Creates a AsyncIterator type */ public AsyncIterator(items: T, options: SchemaOptions = {}): TAsyncIterator { - return ( - { ...options, [Kind]: 'AsyncIterator', type: 'AsyncIterator', items: TypeClone.Type(items) } - ) as unknown as TAsyncIterator + return { ...options, [Kind]: 'AsyncIterator', type: 'AsyncIterator', items: TypeClone.Type(items) } as unknown as TAsyncIterator } /** `[JavaScript]` Constructs a type by recursively unwrapping Promise types */ public Awaited(T: T, options: SchemaOptions = {}): AwaitedResolver.Resolve { @@ -1070,9 +1018,7 @@ export class JavaScriptTypeBuilder extends JsonTypeBuilder { } /** `[JavaScript]` Creates a BigInt type */ public BigInt(options: NumericOptions = {}): TBigInt { - return ( - { ...options, [Kind]: 'BigInt', type: 'bigint' } - ) as TBigInt + return { ...options, [Kind]: 'BigInt', type: 'bigint' } as TBigInt } /** `[JavaScript]` Extracts the ConstructorParameters from the given Constructor type */ public ConstructorParameters>(schema: T, options: SchemaOptions = {}): TConstructorParameters { @@ -1080,21 +1026,15 @@ export class JavaScriptTypeBuilder extends JsonTypeBuilder { } /** `[JavaScript]` Creates a Constructor type */ public Constructor(parameters: [...T], returns: U, options?: SchemaOptions): TConstructor { - return ( - { ...options, [Kind]: 'Constructor', type: 'Constructor', parameters: TypeClone.Rest(parameters), returns: TypeClone.Type(returns) } - ) as unknown as TConstructor + return { ...options, [Kind]: 'Constructor', type: 'Constructor', parameters: TypeClone.Rest(parameters), returns: TypeClone.Type(returns) } as unknown as TConstructor } /** `[JavaScript]` Creates a Date type */ public Date(options: DateOptions = {}): TDate { - return ( - { ...options, [Kind]: 'Date', type: 'Date' } - ) as unknown as TDate + return { ...options, [Kind]: 'Date', type: 'Date' } as unknown as TDate } /** `[JavaScript]` Creates a Function type */ public Function(parameters: [...T], returns: U, options?: SchemaOptions): TFunction { - return ( - { ...options, [Kind]: 'Function', type: 'Function', parameters: TypeClone.Rest(parameters), returns: TypeClone.Type(returns) } - ) as unknown as TFunction + return { ...options, [Kind]: 'Function', type: 'Function', parameters: TypeClone.Rest(parameters), returns: TypeClone.Type(returns) } as unknown as TFunction } /** `[JavaScript]` Extracts the InstanceType from the given Constructor type */ public InstanceType>(schema: T, options: SchemaOptions = {}): TInstanceType { @@ -1102,9 +1042,7 @@ export class JavaScriptTypeBuilder extends JsonTypeBuilder { } /** `[JavaScript]` Creates an Iterator type */ public Iterator(items: T, options: SchemaOptions = {}): TIterator { - return ( - { ...options, [Kind]: 'Iterator', type: 'Iterator', items: TypeClone.Type(items) } - ) as unknown as TIterator + return { ...options, [Kind]: 'Iterator', type: 'Iterator', items: TypeClone.Type(items) } as unknown as TIterator } /** `[JavaScript]` Extracts the Parameters from the given Function type */ public Parameters>(schema: T, options: SchemaOptions = {}): TParameters { @@ -1112,9 +1050,7 @@ export class JavaScriptTypeBuilder extends JsonTypeBuilder { } /** `[JavaScript]` Creates a Promise type */ public Promise(item: T, options: SchemaOptions = {}): TPromise { - return ( - { ...options, [Kind]: 'Promise', type: 'Promise', item: TypeClone.Type(item) } - ) as unknown as TPromise + return { ...options, [Kind]: 'Promise', type: 'Promise', item: TypeClone.Type(item) } as unknown as TPromise } /** `[JavaScript]` Creates a String type from a Regular Expression pattern */ public RegExp(pattern: string, options?: SchemaOptions): TString @@ -1131,27 +1067,19 @@ export class JavaScriptTypeBuilder extends JsonTypeBuilder { } /** `[JavaScript]` Creates a Symbol type */ public Symbol(options?: SchemaOptions): TSymbol { - return ( - { ...options, [Kind]: 'Symbol', type: 'symbol' } - ) as unknown as TSymbol + return { ...options, [Kind]: 'Symbol', type: 'symbol' } as unknown as TSymbol } /** `[JavaScript]` Creates a Undefined type */ public Undefined(options: SchemaOptions = {}): TUndefined { - return ( - { ...options, [Kind]: 'Undefined', type: 'undefined' } - ) as unknown as TUndefined + return { ...options, [Kind]: 'Undefined', type: 'undefined' } as unknown as TUndefined } /** `[JavaScript]` Creates a Uint8Array type */ public Uint8Array(options: Uint8ArrayOptions = {}): TUint8Array { - return ( - { ...options, [Kind]: 'Uint8Array', type: 'Uint8Array' } - ) as unknown as TUint8Array + return { ...options, [Kind]: 'Uint8Array', type: 'Uint8Array' } as unknown as TUint8Array } /** `[JavaScript]` Creates a Void type */ public Void(options: SchemaOptions = {}): TVoid { - return ( - { ...options, [Kind]: 'Void', type: 'void' } - ) as unknown as TVoid + return { ...options, [Kind]: 'Void', type: 'void' } as unknown as TVoid } } /** Json Type Builder with Static Resolution for TypeScript */ diff --git a/todo.md b/todo.md index c65092b63..ffe9b88a0 100644 --- a/todo.md +++ b/todo.md @@ -1,4 +1,6 @@ - TemplateLiteral need to be able to compose with themselves. This works for general composition (i think) but not for key generation. - Investigate Transform Issue: https://github.com/sinclairzx81/typebox/issues/554 -- Clean up Composite (Should technically support Intersect and Union) \ No newline at end of file +- Clean up Composite (Should technically support Intersect and Union) +- Exclude, Extract and Extends could use a clean up +- Look for invalid import references \ No newline at end of file