Coder Social home page Coder Social logo

grantila / typeconv Goto Github PK

View Code? Open in Web Editor NEW
397.0 3.0 9.0 1.6 MB

Convert between JSON Schema, TypeScript, GraphQL, Open API and SureType

License: MIT License

TypeScript 80.72% JavaScript 19.28%
openapi3 jsonschema converter typescript graphql suretype

typeconv's Introduction

npm version downloads build status coverage status Node.JS version

typeconv is an extremely fast silver bullet type conversion utility.

It converts between any of its supported types, bidirectionally.

typeconv lets you convert between type systems which have core-types converters, such as JSON Schema, TypeScript, GraphQL, Open API and SureType. This package can be used as an API programatically or as an application (installed in node_modules/.bin or by using e.g. npx).

By taking advantage of the core-types (npm) toolbox for generic type handling, typeconv can convert and maintain source code location information, comments, descriptions etc. when converting between the different type systems. It is using the following converter packages:

These type systems don't share the same set of types and constraints. For example, JSON Schema has value constraints (like "a string must be longer than 5 characters") and GraphQL doesn't have null or key-value objects as a first-class type. Convertions will therefore produce the smallest common denominator of type information, but still be very useful. See core-types for more information on its supported types, and why not implement a new conversion package yourself!

TL;DR CLI

Convert files from TypeScript ("ts") to GraphQL ("gql"), put the generated files in the gql-schemas directory in the same directory structure as the source files:

$ typeconv -f ts -t gql -o gql-schemas 'types/**/*.ts'

This generates gql-schemas/*.graphql for each .ts file in types/ (and sub-directories).

Note that when using glob patterns, put them in quotes to not have the shell try to expand the pattern - typeconv will do it a lot better!

SureType

When converting from SureType, typeconv will extract all exported validators.

Versions

Since v2:

  • The package is a pure ESM module, no more CommonJS support. This will likely not affect CLI usages.
  • Node 12 support is dropped.

Contents

Conversion example

Converting the following JSON Schema:

{
	"definitions": {
		"User": {
			"type": "object",
			"title": "User type",
			"description": "This type holds the user information, such as name",
			"properties": { "name": { "type": "string", "title": "The real name" } },
			"required": [ "name" ]
		},
		"ChatLine": {
			"type": "object",
			"title": "A chat line",
			"properties": {
				"user": { "$ref": "#/definitions/User" },
				"line": { "type": "string" }
			},
			"required": [ "user", "line" ]
		}
	}
}

... to TypeScript will produce:

/*User type

This type holds the user information, such as name*/
export interface User {
	/*The real name*/
	name: string;
}

/*A chat line*/
export interface ChatLine {
	user: User;
	line: string;
}

or if converted into TypeScript declarations (for .d.ts files), export interface will be export declare interface.

... and to GraphQL will produce:

"""
# User type

This type holds the user information, such as name
"""
type User {
	"The real name"
	name: String!
}

"A chat line"
type ChatLine {
	user: User!
	line: String!
}

Conversions are bi-directional, so any of these type systems can convert to any other.

Usage

Command line

You can depend on typeconv, and if so, you'll have node_modules/.bin/typeconv installed. Or you run it with on-the-fly installation using npx, as npx typeconv args....

Use -f (or --from-type) to specify from which type system to convert, and -t (or --to-type) to specify which type system to convert to. Other options can be used to configure each configuration (both the from and the to) and these options are usually only available for a specific type system.

The types supported are gql (GraphQL), ts (TypeScript), jsc (JSON Schema), oapi (Open API) and st (SureType).

$ typeconv --help

Usage: typeconv [options] file ...

   Options:

   -h, --help                       Print (this) help screen
   --version                        Print the program version
   -v, --verbose                    Verbose informational output (default: false)
   --dry-run                        Prepare and perform conversion, but write no output (default: false)
   --(no-)hidden                    Include hidden files, i.e. files in .gitignore,
                                    files beginning with '.' and the '.git' directory
                                     (default: true)
   -f, --from-type <type>           Type system to convert from

                                       Values:
                                          ts    TypeScript
                                          jsc   JSON Schema
                                          gql   GraphQL
                                          oapi  Open API
                                          st    SureType
                                          ct    core-types

   -t, --to-type <type>             Type system to convert to

                                       Values:
                                          ts    TypeScript
                                          jsc   JSON Schema
                                          gql   GraphQL
                                          oapi  Open API
                                          st    SureType
                                          ct    core-types

   --(no-)shortcut                  Shortcut conversion if possible (bypassing core-types).
                                    This is possible between SureType, JSON Schema and Open API
                                    to preserve all features which would otherwise be erased.
                                     (default: true)
   -o, --output-directory <dir>     Output directory. Defaults to the same as the input files.
   -O, --output-extension <ext>     Output filename extension to use.
                                    Defaults to 'ts'/'d.ts', 'json', 'yaml' and 'graphql'.
                                    Use '-' to not save a file, but output to stdout instead.
   --(no-)strip-annotations         Removes all annotations (descriptions, comments, ...) (default: false)
   TypeScript
     --(no-)ts-declaration          Output TypeScript declarations (default: false)
     --(no-)ts-disable-lint-header  Output comments for disabling linting (default: true)
     --(no-)ts-descriptive-header   Output the header comment (default: true)
     --(no-)ts-use-unknown          Use 'unknown' type instead of 'any' (default: true)
     --ts-non-exported <method>     Strategy for non-exported types (default: include-if-referenced)

                                       Values:
                                          fail                   Fail conversion
                                          ignore                 Don't include non-exported types,
                                                                 even if referenced
                                          include                Include non-exported types
                                          inline                 Don't include non-exported types,
                                                                 inline them if necessary.
                                                                 Will fail on cyclic types
                                          include-if-referenced  Include non-exported types only if they
                                                                 are referenced from exported types

     --ts-namespaces <method>       Namespace strategy. (default: ignore)

                                       Values:
                                          ignore           Ignore namespaces entirely (default).
                                                           - When converting from TypeScript, types in namespaces
                                                           aren't exported.
                                                           - When converting to TypeScript, no attempt to
                                                           reconstruct namespaces is performed.
                                          hoist            When converting from TypeScript, hoist types inside
                                                           namespaces to top-level, so that the types are
                                                           included, but without their namespace.
                                                           This can cause conflicts, in which case deeper
                                                           declarations will be dropped in favor of more top-
                                                           level declarations.
                                                           In case of same-level (namespace depth) declarations
                                                           with the same name, only one will be exported in a
                                                           non-deterministic manner.
                                          dot              When converting from TypeScript, join the namespaces
                                                           and the exported type with a dot (.).
                                                           When converting to TypeScript, try to reconstruct
                                                           namespaces by splitting the name on dot (.).
                                          underscore       When converting from TypeScript, join the namespaces
                                                           and the exported type with an underscore (_).
                                                           When converting to TypeScript, try to reconstruct
                                                           namespaces by splitting the name on underscore (_).
                                          reconstruct-all  When converting to TypeScript, try to reconstruct
                                                           namespaces by splitting the name on both dot and
                                                           underscore.

   GraphQL
     --gql-unsupported <method>     Method to use for unsupported types

                                       Values:
                                          ignore  Ignore (skip) type
                                          warn    Ignore type, but warn
                                          error   Throw an error

     --gql-null-typename <name>     Custom type name to use for null
   Open API
     --oapi-format <fmt>            Output format for Open API (default: yaml)

                                       Values:
                                          json  JSON
                                          yaml  YAML ('yml' is also allowed)

     --oapi-title <title>           Open API title to use in output document.
                                    Defaults to the input filename.
     --oapi-version <version>       Open API document version to use in output document. (default: 1)
   SureType
     --st-ref-method <method>       SureType reference export method (default: provided)

                                       Values:
                                          no-refs   Don't ref anything, inline all types
                                          provided  Reference types that are explicitly exported
                                          ref-all   Ref all provided types and those with names

     --st-missing-ref <method>      What to do when detecting an unresolvable reference (default: warn)

                                       Values:
                                          ignore  Ignore; skip type or cast to any
                                          warn    Same as 'ignore', but warn
                                          error   Fail conversion

     --(no-)st-inline-types         Inline pretty typescript types aside validator code (default: true)
     --(no-)st-export-type          Export the deduced types (or the pretty types,
                                    depending on --st-inline-types)
                                     (default: true)
     --(no-)st-export-schema        Export validator schemas (default: false)
     --(no-)st-export-validator     Export regular validators (default: true)
     --(no-)st-export-ensurer       Export 'ensurer' validators (default: true)
     --(no-)st-export-type-guard    Export type guards (is* validators) (default: true)
     --(no-)st-use-unknown          Use 'unknown' type instead of 'any' (default: true)
     --(no-)st-forward-schema       Forward the JSON Schema, and create an untyped validator schema
                                    with the raw JSON Schema under the hood
                                     (default: false)

As API

To convert from one type system to another, you create a reader for the type system to convert from and a writer for the type system to convert to. The readers and writers for the different type systems have their own set of options. Some have no options (like the JSON Schema reader), some require options (like the Open API writer).

makeConverter

Making a converter is done using makeConverter(reader, writer, options?), which takes a reader and a writer, and optionally options:

cwd (string)

The current working directory, only useful when working with files.

simplify (boolean) (default true)

When simplify is true, the converter will let core-types compress the types after having converted from {reader} format to core-types. This is usually recommended, but may cause some annotations (comments) to be dropped.

map (ConvertMapFunction)

Custom map function for transforming each type after it has been converted from the source type (and after it has been simplified), but before it's written to the target type system.

Type: (node: NamedType, index: number, array: ReadonlyArray<NamedType>) => NamedType (NamedType ref)

If filter is used as well, this runs before filter.

If transform is used as well, this runs before transform.

filter (ConvertFilterFunction)

Custom filter function for filtering types after they have been converted from the source type.

Type: (node: NamedType, index: number, array: ReadonlyArray<NamedType>) => boolean (NamedType ref)

If map is used as well, this runs after map.

If transform is used as well, this runs before transform.

transform (ConvertTransformFunction)

Custom filter function for filtering types after they have been converted from the source type.

Type: ( doc: NodeDocument ) => NodeDocument (NodeDocument ref)

If map is used as well, this runs after map.

If filter is used as well, this runs after filter.

shortcut (boolean) (default true)

Shortcut reader and writer if possible (bypassing core-types).

Basic example conversion

import {
  getTypeScriptReader,
  getOpenApiWriter,
  makeConverter,
} from 'typeconv'

const reader = getTypeScriptReader( );
const writer = getOpenApiWriter( { format: 'yaml', title: 'My API', version: 'v1' } );
const { convert } = makeConverter( reader, writer );
const { data } = await convert( { data: "export type Foo = string | number;" } );
data; // This is the Open API yaml as a string

JSON Schema

There are two exported functions for JSON Schema:

import { getJsonSchemaReader, getJsonSchemaWriter } from 'typeconv'

const reader = getJsonSchemaReader( );
const writer = getJsonSchemaWriter( );

They don't have any options.

typeconv expects the JSON Schema to contain definitions, i.e. to be in the form:

JSON Schema

{
	"definitions": {
		"User": {
			"type": "object",
			"properties": { "name": { "type": "string" } },
			"required": [ "name" ]
		},
		"ChatLine": {
			"type": "object",
			"properties": {
				"user": { "$ref": "#/definitions/User" },
				"line": { "type": "string" }
			},
			"required": [ "user", "line" ]
		}
	}
}

typeconv doesn't support external references (to other files). If you have that, you need to use a reference parser and merge it into one inline-referenced file before using typeconv.

Open API

Converting to or from Open API can be done with both JSON and YAML. The default is JSON.

When reading, if the filename ends with .yml or .yaml, typeconv will interpret the input as YAML.

Writing however, is decided in the writer factory and provided to getOpenApiWriter.

import { getOpenApiReader, getOpenApiWriter } from 'typeconv'

const reader = getOpenApiReader( );
const writer = getOpenApiWriter( {
  format: 'yaml',
  title: 'My API',
  version: 'v1',
  schemaVersion: '3.0.0',
} );

The options to getOpenApiWriter is:

interface {
  format?: string;
  title: string;
  version: string;
  schemaVersion?: string;
}

TypeScript

TypeScript conversion is done using:

import { getTypeScriptReader, getTypeScriptWriter } from 'typeconv'

const reader = getTypeScriptReader( );
const writer = getTypeScriptWriter( );

Both these take an optional argument.

The getTypeScriptReader takes an optional FromTsOptions object from core-types-ts, although warn isn't necessary since it's set by typeconv internally.

The getTypeScriptWriter takes an optional ToTsOptions object from core-types-ts, although warn, filename, sourceFilename, userPackage and userPackageUrl aren't necessary since they're set by typeconv internally.

GraphQL

GraphQL conversion is done using;

import { getGraphQLReader, getGraphQLWriter } from 'typeconv'

const reader = getGraphQLReader( );
const writer = getGraphQLWriter( );

Both these take an optional argument.

The getGraphQLReader takes an optional GraphqlToCoreTypesOptions object from core-types-graphql, although warn isn't necessary since it's set by typeconv internally.

The getGraphQLWriter takes an optional CoreTypesToGraphqlOptions object from core-types-graphql, although warn, filename, sourceFilename, userPackage and userPackageUrl aren't necessary since they're set by typeconv internally.

SureType

SureType conversion is done using;

import { getSureTypeReader, getSureTypeWriter } from 'typeconv'

const reader = getSureTypeReader( );
const writer = getSureTypeWriter( );

Both these take an optional argument from the core-types-suretype package.

The getSureTypeReader takes an optional SuretypeToJsonSchemaOptions.

The getSureTypeWriter takes an optional JsonSchemaToSuretypeOptions.

typeconv's People

Contributors

calvinl avatar grantila avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

typeconv's Issues

allOf and additionalProperties

Given the following typescript file:

interface A {
    a: string;
}

interface B {
    b: string;
}

export type C = A & B;

typeconv produces the following json schema:

{
  "definitions": {
    "C": {
      "allOf": [
        {
          "$ref": "#/definitions/A"
        },
        {
          "$ref": "#/definitions/B"
        }
      ],
      "title": "C"
    },
    "A": {
      "type": "object",
      "properties": {
        "a": {
          "type": "string",
          "title": "A.a"
        }
      },
      "required": [
        "a"
      ],
      "additionalProperties": false,
      "title": "A"
    },
    "B": {
      "type": "object",
      "properties": {
        "b": {
          "type": "string",
          "title": "B.b"
        }
      },
      "required": [
        "b"
      ],
      "additionalProperties": false,
      "title": "B"
    }
  },
  "$id": "dummy.json",
  "$comment": "Generated from src/api/dummy.ts by core-types-json-schema (https://github.com/grantila/core-types-json-schema) on behalf of typeconv (https://github.com/grantila/typeconv)"
}

However, the following json will not validate against type C in the schema:

{
  "a": "hello",
  "b": "world"
}

You can check it only at https://www.jsonschemavalidator.net/. You should add the following lines to the beginning of the json schema:

  "type": "object",
  "$ref": "#/definitions/C",

Overlapping attributes in inherited types fails to convert

Hi! Thanks for creating this tool, it's been a life saviour for us for generating OpenAPI definitions. We want to have a single source of truth for our type definitions, so a tool like this comes pretty handy.

However, I found an issue when type converting interfaces that inherit from other interfaces that share common attributes.

Let's imagine we have the following declarations:

interface Base {
  $type: string;
  comment: string;
}

interface A {
  $type: 'a';
  a: string;
}

export interface Foo extends Base, A {
  $type: 'a';
}

The conversion works as expected. However, if interface A has declared an attribute that matches one in the Base interface, the CLI gives an error Cannot read properties of undefined (reading 'length'). With a bit of testing I was able to narrow the issue down to the changes version 2.3.0. Previous versions have no issues with converting this, though, looking at the release notes it's supposedly because they weren't being converted at all ๐Ÿ˜„

Here's a modified example of the one above that reproduces the error:

interface Base {
  $type: string;
  comment: string;
}

interface A {
  $type: 'a';
  a: string;
  comment: string;
}

export interface Foo extends Base, A {
  $type: 'a';
}

Consideration for debugging: it would be nice to be able to see where the errors are generated from. The error didn't output any information regarding file or line number in regards to what was producing it. My project has quite extensive types that are converted using typeconv, so it took a while to find what was causing the error.

Cyclic -> Circular Dependencies?

The following is a valid schema, but typeconv fails with a cyclic dependency.

export interface D {}
export interface C extends D {}
export interface B {
  fieldOne?: D;
}

export interface A extends B {
  fieldOne?: C;
}

[ts-to-oapi] Enums are not generated during conversion.

Hi. I have a number of TypeScript files which I am trying to generate OpenAPI documentation for using this tool. In one of the typescript files, I have an enum which looks like the following:

export enum SpeciesKind {
    Human,
    Bird,
    Fish
}

I am using the following command to generate OpenAPI documentation from my typescript files:

npx typeconv -f ts -t oapi -o spec ./src/*.ts

When running the above command, everything is generated as expected except for any enums I have in my code, no OpenAPI schema is generated for them.

Incorrect openapi spec being generated from typescript types.

I have a project where I want to convert my typescript types into an openapi spec. When I run the typeconv command from the cli, the openapi spec that is generated includes various unsupported key words which don't comply.

I made a sample repo to highlight the problem.

https://github.com/avenmia/test-typeconv-error-repo

When running the following command:

typeconv -f ts -t oapi --oapi-version 3 -o openapitypes './test-func/types.ts'

for my types file, I get the following yaml:

openapi: 3.0.0
info:
  title: Converted from types.yaml with typeconv
  version: '3'
paths: {}
$id: types.yaml
$comment: >-
  Generated from test-func\types.ts by core-types-json-schema
  (https://github.com/grantila/core-types-json-schema) on behalf of typeconv
  (https://github.com/grantila/typeconv)
components:
  schemas:
    Book:
      properties:
        title:
          type: string
        author:
          type: string
        genre:
          anyOf:
            - const: Comedy
              type: string
            - const: Horror
              type: string
            - const: Romance
              type: string
      required:
        - title
        - author
        - genre
      additionalProperties: false
      description: "@swagger components:\r\n  schemas:\r\n    Book:\r\n      type: object\r\n      description: A book.\r\n      properties:\r\n        title:\r\n          type: string\r\n        author:\r\n          type: string\r\n        genre:\r\n          type: string"
      type: object

The yaml is invalid according to:
https://apitools.dev/swagger-parser/online/

but if you remove the $id and $comments fields then convert it from v3 to v2 using https://lucybot-inc.github.io/api-spec-converter/ then it does validate.

Another thing to note is that const is an unsupported keyword in version 3. I believe these are getting generated when an interface defines a type using the "or" operator. An example can be found in the repo when the Book genre property has type equal to "Comedy" | "Horror" | "Romance".

Ideally, the output of specifying version 3 for the openapi spec should output valid openapi version 3 yaml.

TS to OAPI

Schema ref are missing "s"

- $ref: '#/components/schema/TJunctionOperator'

components:  
  schemas:

Its a minor thing with a big impact.

json-schema type alias translates to union in GraphQL

Hi, one additional issue... when you have a type definition in json-schema like this:

"DateTimeIso8601": {
  "type": "string",
  "description": "A datetime in ISO-8601 format (YYYY-MM-DDTHH:MM:SS.MMMZ)",
  "format": "date-time"
}

It results in a union of String in graphql, like this: union DateTimeIso8601 = String
This is invalid graphql and results in an error:

Union type DateTimeIso8601 can only include Object types, it cannot include String.

Thanks

json-schema enums should translate to GraphQL enums

Hi, this is a great library... thanks for creating it!
We are running into an issue where we have types in json-schema defined as

"Color": {
  "type": "string",
  "enum": [
    "yellow",
    "blue",
    "red"
  ]
},

Those should convert to an enum in GraphQL. However, it is converting into a union of a String.

Expected:

enum Color {
  yellow
  blue
  red
}

Received:

union Color = String

Thanks

json-schema to suretype: import aliases are empty

Running a simple conversion from json-schema to suretype results in imports from suretype that are unusable. See below:

/* tslint:disable */
/* eslint-disable */
/**
 * This file is generated by core-types-suretype on behalf of typeconv, DO NOT EDIT.
 * For more information, see:
 *  - {@link https://github.com/grantila/core-types-suretype}
 *  - {@link https://github.com/grantila/typeconv}
 */

import { suretype as , v as , compile as , annotate as  } from 'suretype';

// ... rest of the schemas, interfaces and validators

Generation was done in the most basic way possible I believe:

const fs = require('fs');
const path = require('path');
const typeconv = require('typeconv');

const { readdirSync, readFileSync, writeFileSync } = fs;
const { resolve, extname, basename } = path;
const { getJsonSchemaReader, getSureTypeWriter, makeConverter } = typeconv;

const schemasDirectory = resolve(__dirname, 'schemas');
const { convert } = makeConverter(getJsonSchemaReader(), getSureTypeWriter())

readdirSync(schemasDirectory).forEach(file => {
    if (extname(file).includes('json')) {
        const fileName = basename(file, extname(file));
        const filePath = resolve(__dirname, 'schemas', file);
        const fileContent = readFileSync(filePath).toString();
        const targetFile = resolve(__dirname, 'schemas', `${fileName}.ts`);

        convert({ data: fileContent }).then((converted) => {
            writeFileSync(targetFile, converted.data)
        })
    }
});

Executing typeconv from nmp-scripts or within bash script does not work

$ npm run convert-types

> @***/***@*** convert-types
> npx typeconv -f ts -t oapi -o docs './src/**/*.ts

๐Ÿ’ก Converted 0 types in 0 files, in 0.0s
$ npm run convert-types

> @***/***@*** convert-types
> typeconv -f ts -t oapi -o docs './src/**/*.ts

๐Ÿ’ก Converted 0 types in 0 files, in 0.0s

JsonSchema to SureType conversion loses validation information

Hi! ๐Ÿ‘‹ Thanks again for typeconv!

I was trying to convert a json schema to suretype and noticed that the "minimum" and "maximum" properties for numbers are not honored in the generated schema.

Digging deeper it seems that code for this is in place, but typeconv chooses to convert jsc to ct to st, even though a shortcut from jsc to st is available (defined in the st writer). In this process, the minimum and maximum information gets lost. On a sidenote, the ct to st conversion actually generates a json schema based on the ct representation, and converts that to suretype. I confirmed that this intermediate json schema does not contain the minimum and maximum information.

One could argue that this validation information should also be present in the core-types representation, so that the conversion from jsc to ct should not be lossy. However, I did not look down that path and focused on the following:

The logic for finding the best conversion path in format-graph.ts, while considering shortcuts, does not work optimally if a format can be directly connected to the writer.

I was able to solve this problem by postulating that every reader has a trivial shortcut to itself (so in my case, "jsc to jsc"), which can then be connected with the "jsc to st" shortcut on the st writer side.

Here is the diff that solved my problem:

diff --git a/node_modules/typeconv/dist/converter.js b/node_modules/typeconv/dist/converter.js
index 0c6e981..21c7964 100644
--- a/node_modules/typeconv/dist/converter.js
+++ b/node_modules/typeconv/dist/converter.js
@@ -27,7 +27,9 @@ async function convertAny(data, reader, writer, format, readOpts, writeOpts) {
         };
     }
     else {
-        const read = await reader.shortcut[format](data, readOpts);
+        const read = reader.kind === format
+          ? { data: data, convertedTypes: [], notConvertedTypes: [] }
+          : await reader.shortcut[format](data, readOpts);
         const written = await writer.shortcut[format](read.data, writeOpts, reader);
         return {
             output: written.data,
diff --git a/node_modules/typeconv/dist/format-graph.js b/node_modules/typeconv/dist/format-graph.js
index 12669ba..85a00d2 100644
--- a/node_modules/typeconv/dist/format-graph.js
+++ b/node_modules/typeconv/dist/format-graph.js
@@ -51,7 +51,7 @@ class FormatGraph {
                 paths.set(pathKey, newPath);
             };
             const formats = [
-                ...shortcuts ? [] : ['ct'],
+                ...shortcuts ? [reader.kind] : ['ct'],
                 ...shortcuts !== false
                     ? Object.keys((_a = reader.shortcut) !== null && _a !== void 0 ? _a : {})
                     : []

This issue body was partially generated by patch-package.

[jsc-to-ts] enum with null value throws

Using a enum with a null value as shown here throws.

TypeError: Cannot destructure property 'properties' of 'node' as it is null.
    at tsObjectType (file:///home/ava/peach-front/node_modules/core-types-ts/dist/lib/core-types-to-ts.js:205:13)
    at tsConstType (file:///home/ava/peach-front/node_modules/core-types-ts/dist/lib/core-types-to-ts.js:185:31)
    at file:///home/ava/peach-front/node_modules/core-types-ts/dist/lib/core-types-to-ts.js:139:30
    at Array.map (<anonymous>)
    at tsType (file:///home/ava/peach-front/node_modules/core-types-ts/dist/lib/core-types-to-ts.js:139:18)
    at tsTypeAndOrSchema (file:///home/ava/peach-front/node_modules/core-types-ts/dist/lib/core-types-to-ts.js:109:16)
    at file:///home/ava/peach-front/node_modules/core-types-ts/dist/lib/core-types-to-ts.js:100:76
    at Array.map (<anonymous>)
    at tsTypeUnion (file:///home/ava/peach-front/node_modules/core-types-ts/dist/lib/core-types-to-ts.js:100:48)
    at tsTypeAndOr (file:///home/ava/peach-front/node_modules/core-types-ts/dist/lib/core-types-to-ts.js:115:16)

{
  "enum": ["red", "amber", "green", null, 42]
}

TS namespace

Hi,

It seems there is no namespace support for typeconv
Example, this file sample.ts output nothing
export namespace ModelVersion { export interface Version { version: string; codename: string; id: string; } }
Best regards

Typescript type "Date" is misrecognized as user-defined type

I have a script running from CLI which transforms typescript definitions to openapi. When having a model like this

export interface MyObject {
  startDate: Date,
  otherProp: string
}

the output is this

{
   "MyObject": {
      "type": "object",
      "properties": {
        "startDate": {
          "$ref": "#/definitions/Date",
          "title": "myObject.startDate"
        },
        "otherProp": {
          "type": "string",
          "title": "myObject.otherProp"
        }
      },
      "required": [
        "startDate",
        "otherProp"
      ],
      "additionalProperties": false,
      "title": "MyObject"
    }
}

The Date type is being interpreted as a user defined type, but it is not. It's a native type

Expected output is

{
   "MyObject": {
      "type": "object",
      "properties": {
        "startDate": {
          "type": "string",
          "format": "date-time",
          "title": "myObject.startDate"
        },
        "otherProp": {
          "type": "string",
          "title": "myObject.otherProp"
        }
      },
      "required": [
        "startDate",
        "otherProp"
      ],
      "additionalProperties": false,
      "title": "MyObject"
    }
}

'Required' not respected for JSON schema references

Hi, I am using typeconv to convert a JSON schema to suretype. I noticed that for required properties whose type is a referenced type, the 'required()' function call does not appear in the generated suretype declaration.

Repro:
test.ts:

export interface A {}

export interface B {
  a: A;
}

Run:

npx [email protected] -f ts -t jsc -o . test.ts
npx [email protected] -f jsc -t st -o ./out test.json

output:

import { suretype, v, compile } from 'suretype';

const schemaA = suretype({
    name: "A",
    title: "A"
}, v.object({}));

export interface A {
}

// ...
const schemaB = suretype({
    name: "B",
    title: "B"
}, v.object({
    a: schemaA
}));

export interface B {
    a: A;
}

should be

v.object({
    a: schemaA.required()
})

The inlined type is created correctly, which also means that, for example, the ensureB function is of type never, so cannot be called.

I think that in this line, it should be wrap instead of wrapAnnotations:
https://github.com/grantila/core-types-suretype/blob/1ae1e9fa802054e7de7a5c89226aa074cc642b6d/lib/json-schema-to-suretype.ts#L666

Thanks for building this :)

Invalid TS generated from ST

Using:

typeconv 1.7.0
node v17.4.0

input.ts

export type T = number | string;

And on the command line:

npx typeconv -f ts -t st -o out input.ts

Gives a file out/input.ts that contains this invalid import declaration:

import { suretype as , v as , compile as  } from 'suretype';

The generated import declaration should be:

import { suretype, v, compile} from 'suretype';

[ts-to-oapi] Imported types are transformed

Whenever you are transforming a TypeScript file to an OpenApi specification file, if you declare a type that reuses some other type that you import from a different file, the imported types are not included in the OpenApi specification file.

As an example this file:

import type { MyTypeB } from "./some-file";

export type A = MyTypeB;

generates:

$ref: '#/components/schemas/MyTypeB'

however no MyTypeB component is generated inside the file.

Convert interfaces/types that implements generic types

Hello!
I expect this to work:

export type FinalType = GenericType<{ foo: number; bar: string }>
export type GenericType<T> = T

but it isn't recognizing type params, all my types with generic type implementation are not constructed on my .swagger.yaml oapi output file. What can I do or it's not supported?

[jsc-to-ts] Discards descriptions on enums

Consider this schema:

{
  "title": "RDAP schema",
  "definitions": {
    "RdapEvent": {
      "title": "RdapEvent",
      "description": "This data structure represents events that have occurred on an instance of\nan object class.",
      "type": "object",
      "properties": {
        "eventAction": {
          "description": "the reason for the event",
          "type": "string"
        }
      },
      "required": ["eventAction"],
      "additionalProperties": false
    }
  }
}

typeconv translates this to the following TypeScript definition:

/**
 * This data structure represents events that have occurred on an instance of
 * an object class.
 */
export interface RdapEvent {
    /** the reason for the event */
    eventAction: string;
}

However if you update eventAction's definition to

{
  "description": "the reason for the event",
  "enum": ["registration", "reregistration", "last changed"]
}

The property's TSDoc comment is gone:

/**
 * This data structure represents events that have occurred on an instance of
 * an object class.
 */
export interface RdapEvent {
    eventAction: "registration" | "reregistration" | "last changed";
}

Parse inferred typescript types

It would be nice if the plugin would parse Typescript built in types such as: Partial, Pick, Omit etc.
It would make it possible to parse inferred types for example:

Interface Comment {
  description: string
  deletedAt: Date
}

Type CommentDTO = Omit<Comment, 'deletedAt'>;

Right now this is not possible and I would have to refactor almost all of my types, or duplicate them to have them available in Swagger.

May be inspiring: https://github.com/nestjs/swagger/tree/master/lib/type-helpers

JSON schema keywords getting lost

I'm trying to convert JSON schema to Open Api. During the conversion keywords like minLenght, maxLength and format are getting lost and are not present in my final Open Api conversion.
Here is my testcode:

const test = {
    "type": "object",
    "properties": {
        "name": { "minLength": 5, "maxLength": 10, "type": "string" },
        "creationDate": { "format": "date-time", "type": "string" }
    },
    "required": ["name", "creationDate"]
}

const schemas = {
    "definitions": {
        "testType": test
    }
};


const converter = async () => {
    const reader = getJsonSchemaReader();
    const writer = getOpenApiWriter({ format: 'yaml', title: 'Testconverter', version: 'v1', schemaVersion: '3.0.0' });
    const { convert } = makeConverter(reader, writer);
    await convert({ 'data': JSON.stringify(schemas) }, { filename: 'test.yaml' })
}

converter()

which produces this open api yaml:

openapi: 3.0.0
info:
  title: Testconverter
  version: v1
paths: {}
$id: test.yaml
$comment: >-
  Generated by core-types-json-schema
  (https://github.com/grantila/core-types-json-schema) on behalf of typeconv
  (https://github.com/grantila/typeconv)
components:
  schemas:
    testType:
      properties:
        name:
          type: string
        creationDate:
          type: string
      required:
        - name
        - creationDate
      type: object

which is missing the previous mentioned keyword. The correct (shortend) schme should look like this:

testType:
      properties:
        name:
          type: string
          minLength: 5
          maxLength: 10
        creationDate:
          type: string
          format: date-time
      required:
        - name
        - creationDate
      type: object

TypeScript to OpenApi

I would like to serve multiple versions of an api from a single web service. I also don't want to write OpenApi schemas. I want to write TypeScript, then I want to convert that to OpenApi. I am able to convert from TS to OpenApi (thanks!), however, I need to support multiple schema versions. If my project dirs look something like this...

.
`-- src/
    |-- business/
    |   `-- dtos/
    |       |-- v1/
    |       |   `-- index.ts
    |       `-- v2/
    |           `-- index.ts
    `-- customer/
        `-- dtos/
            |-- v1/
            |   `-- index.ts
            `-- v2/
                `-- index.ts

then i want the schema to look something like

{
    ...
    components:{
        schemas: {
            v1: {
                ...
            },
            v2:{
                ...
            }
        }
    }
}

JsonSchema => GraphQL: only "AllOf" schema is used

Hi there,

I'm trying to convert some Json schema to GraphQL & got some issue when using allOf in schema.

Here is a minimal reproduction :

const baseSchema = {
  $id: 'base',
  type: 'object',
  required: ['id'],
  properties: {
    id: {
      description: 'Content uniq ID.',
      type: 'string',
    },
  },
};

const schema = {
  allOf: [baseSchema],
  $id: 'something',
  type: 'object',
  title: 'CMS Product Documentation',
  required: ['title', 'excerpt'],
  properties: {
    title: {
      type: 'string',
      description: 'Content title',
      maxLength: 30,
    },
    excerpt: {
      type: 'string',
      description: 'Short description of post.',
      minLength: 15,
      maxLength: 300,
    }
  },
};

const contentSchema = {
  definitions: {
    'Something': schema,
  },
};

import { getGraphQLWriter, getJsonSchemaReader, makeConverter } from 'typeconv';

async function main() {
  const reader = getJsonSchemaReader();
  const gqlWriter = getGraphQLWriter();
  const { convert: gQlConvert } = makeConverter(reader, gqlWriter);

  let { data } = await gQlConvert({ data: JSON.stringify(contentSchema) });
  console.log(data)
}

main()

This ouput :

type Something {
  "Content uniq ID."
  id: String!
}

title& excerpt properties of the schema are ignored/override by the base schema.

Am I wrong to think output should include those 2 properties ?

TS -> OAPI - ignores interfaces inheritance

Given the following typescript file:

interface A {
    a: string;
}


interface B extends A {
    b: string;
}

OpenAPI will show only b property on type B. The below example does not work as well:

type B = A & {
    b: string;
};

Can be related to #15

Add option to read stdin

There's already -O -. typeconv could take - as input, too. (It would probably imply writing to stdout as well, since filename can't be determined automatically)

Use case

We already can do this:

npx typeconv -f ts -t jsc -O - models.ts | datamodel-codegen > models.py

Why not the other way around?

# generate_jsonschema.py

import json
from pydantic.schema import schema
from models import *

print(json.dumps(schema([MyModel, ...]), indent=2))
python generate_jsonschema.py | npx typeconv -f jsc -t ts - > models.ts

Unable to convert `keyof typeof something`

When converting to try something like this

export type DemoType = {
  name: keyof typeof something;
  class: string;
  Pure?: boolean;
}

it's converting this type to JSON but doesn't give a type field for the name.
image

TS to OpenAPI does not produce descriptions from the comments

If I have a type like this:

type Point = {
  /** The distance from the left in mm */
  x: number;
  /** The distance from the top in mm */
  y: number;
};

I would hope for an OpenAPI spec like this:

components:
  schemas:
    Point:
      type: object
      properties:
        x:
          type: number
          description: The distance from the left in mm
        y:
          type: number
          description: The distance from the top in mm

The primary reason I would want to convert my TS types to OpenAPI specs is so people can look at documentation for the API param/response types in a web browser.

Can this be done?

Cannot read undefined

The following results in an undefined error when a child type makes a field required that is not required in the parent.

export interface Parent {
    fieldOne?: string
}

export interface Child extends Parent {
    fieldOne: string
}

OpenAPI version 2

AFAICS OpenAPI version 3 is the only supported version. Are there any plans to support version 2?

[gql] `input` type is not getting converted

input types in GraphQL are not getting converted.

Example:

##### type.graphql #####

type Foo {
  bar: String!
}


##### input.graphql #####

input FooInput {
    bar: String!
}
$ typeconv -f gql -t ts ./type.graphql

๐Ÿ’ก Converted 1 types in 1 files, in 0.0s

$ typeconv -f gql -t ts ./input.graphql

๐Ÿ’ก Converted 0 types in 1 files, in 0.0s

# Note that I wrote this output myself and didn't actually test the two files above ;-)
# I did test the behavior with actual development/production use GraphQL schmas however

Type 'any' not supported

i have a schema defined in operation-types.ts
export type Scalars = {
ID: { input: string; output: string; }
String: { input: string; output: string; }
Boolean: { input: boolean; output: boolean; }
Int: { input: number; output: number; }
Float: { input: number; output: number; }
bigint: { input: any; output: any; }
numeric: { input: any; output: any; }
timestamptz: { input: any; output: any; }
};

when i run typeconv -f ts -t gql -o gql-schemas 'src/gql/*.ts',there is error:
Type 'any' not supported
Type 'or' not supported

how to fix it?

Nested interfaces ignored when declared in other files (Typescript -> OpenAPI)

Hey,

When using NodeJS/ES6 to convert existing Typescript interfaces to OpenAPI it ignores nested interfaces that are declared in other files.

For example, the following interface:

// main.ts
export interface MyResponse {
  id: string;
  status: StatusResponse;
}

Uses the StatusResponse that is defined in another file as simply:

//helper.ts
export interface StatusResponse {
  status: string;
  errorMessages?: string[];
}

Yet the final MyResponse schema ignores the status field entirely and just shows the id field.

Has anyone encountered this before or can suggest a solultion?

Thanks

TS -> OAPI single example

Hello,

Firstly, thank you for this fantastic project.

I have noticed a small bug when converting from TS to OAPI and using the @example annotation.

If I have the following TS:

type MyType = {
  /**
   * My description
   * @example: test1
   * @example: test2
   */
  myProp: string
}

Then the examples are correctly converted to:

"examples": [
  "test1",
  "test2"
]

However, if there is only 1 example annotation e.g.

type MyType = {
  /**
   * My description
   * @example: test1
   */
  myProp: string
}

Then it is incorrectly converted to:

"examples": "test1"

It should either still be an array with 1 item, or:

"example": "test1"

Thanks very much!

TS enum to graphql enum

Thrift IDL enum to TS enum has no problem, such as:
image

typeconv now:
image

I understand not all TS enum has good correspondence in graphql, bu will typeconv behave better in such case in the future? maybe some options?

OpenAPI -> TypeScript adds wildcard prop to each type

I'm using typeconv to convert some OpenAPI schemas into TypeScript interfaces. Generally working great, but I noticed one thing.

When I start with the below OpenAPI spec:

{
    components: {
      schemas: {
        Person: {
          type: "object",
          properties: {
            first_name: {
              type: "string",
              example: "Pam",
            },
            last_name: {
              type: "string",
              example: "Halpert",
            },
          },
          required: [],
          title: "Person",
        },
      },
    },
  };

It produces the following type:

export interface Person {
    first_name?: string;
    last_name?: string;
    [key: string]: any;
}

Almost perfect, except for that last line:

    [key: string]: any;

It's appending a wildcard accessor to my type, for some reason, essentially asserting that on Person, any string can access any value, which makes the type not particularly helpful.

Any ideas what this is happening? I could get rid of this line through string manipulation, but I wonder why it's happening, and if there's some option I'm missing.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.