diff --git a/src/index.ts b/src/index.ts index 446c232..97c43c3 100644 --- a/src/index.ts +++ b/src/index.ts @@ -3,3 +3,4 @@ export * from './extraction/getValueFromType'; export * from './validation/getFlowValidation'; export * from './validation/getValueValidation'; export * from './schema/getSignatureSchema'; +export * from './schema/getTypeSchema'; diff --git a/src/schema/getTypeSchema.ts b/src/schema/getTypeSchema.ts new file mode 100644 index 0000000..763306d --- /dev/null +++ b/src/schema/getTypeSchema.ts @@ -0,0 +1,41 @@ +import {DataType} from "@code0-tech/sagittarius-graphql-types" +import ts from "typescript" +import {getSchema, Schema} from "../util/schema.util" +import {createCompilerHost, getSharedTypeDeclarations} from "../utils" + +/** + * Generates a schema for a given TypeScript type expression string. + * + * This function creates a virtual TypeScript environment, wraps the provided type expression + * into a type alias 'T', and extracts the schema for it. + * + * @param typeString - The TypeScript type expression (e.g., "string | number" or "{ a: string }"). + * @param dataTypes - An optional array of additional data type definitions to be included in the environment. + * @returns The generated Schema for the identified type, or undefined if no valid type was found or an error occurred. + */ +export const getTypeSchema = ( + typeString: string, + dataTypes: DataType[] = [], +): Schema | undefined => { + const fileName = "index.ts" + const typeDefs = getSharedTypeDeclarations(dataTypes) + const sourceCode = `${typeDefs}\ntype MyType = ${typeString}` + + const host = createCompilerHost(fileName, sourceCode) + const program = host.languageService.getProgram() + const sourceFile = program?.getSourceFile(fileName) + const checker = program?.getTypeChecker() + + if (!sourceFile || !checker) return undefined + + const targetStatement = sourceFile.statements + .filter((stmt): stmt is ts.TypeAliasDeclaration | ts.InterfaceDeclaration | ts.ClassDeclaration => + ts.isTypeAliasDeclaration(stmt) || ts.isInterfaceDeclaration(stmt) || ts.isClassDeclaration(stmt) + ).pop() + if (!targetStatement) return undefined + + const targetType = checker.getTypeAtLocation(targetStatement) + if (!targetType) return undefined + + return getSchema(checker, undefined, targetType, [], [], false) +} diff --git a/src/util/schema.util.ts b/src/util/schema.util.ts index 827b065..a7d25ca 100644 --- a/src/util/schema.util.ts +++ b/src/util/schema.util.ts @@ -113,31 +113,28 @@ export type Schema = */ export const getSchema = ( checker: ts.TypeChecker, - node: ts.VariableDeclaration, + node: ts.VariableDeclaration | undefined, parameterType: ts.Type, functionDeclarations: FunctionDeclaration[], functions: FunctionDefinition[], suggestions: boolean = true ): Schema => { // Collect all available suggestions for this parameter - const literalValueSuggestions = getValues(parameterType); - const referenceSuggestions = getReferences( - checker, - node!, - parameterType, - checker.getSymbolsInScope(node!, ts.SymbolFlags.Variable) - ); - const nodeSuggestions = getNodes( - checker, - functionDeclarations, - functions, - parameterType - ); const combinedSuggestions = suggestions ? { suggestions: [ - ...literalValueSuggestions, - ...referenceSuggestions, - ...nodeSuggestions, + ...getValues(parameterType), + ...(node ? getReferences( + checker, + node, + parameterType, + checker.getSymbolsInScope(node, ts.SymbolFlags.Variable) + ) : []), + ...getNodes( + checker, + functionDeclarations, + functions, + parameterType + ), ], } : {}; diff --git a/test/schema/schema.test.ts b/test/schema/schema.test.ts index fc10904..a082e31 100644 --- a/test/schema/schema.test.ts +++ b/test/schema/schema.test.ts @@ -1,6 +1,6 @@ import {describe, expect, it} from "vitest"; import {Flow} from "@code0-tech/sagittarius-graphql-types"; -import {getFlowValidation, getSignatureSchema} from "../../src"; +import {getFlowValidation, getSignatureSchema, getTypeSchema} from "../../src"; import {DATA_TYPES, FUNCTION_SIGNATURES} from "../data"; describe("Schema", () => { @@ -116,4 +116,10 @@ describe("Schema", () => { }); + it('3', () => { + const result = getTypeSchema("{text: NUMBER, bla?: LIST}", DATA_TYPES); + + //console.dir(result, {depth: null}) + }); + }) \ No newline at end of file