Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Invalid index in type #1974

Open
navalex opened this issue May 27, 2024 · 11 comments
Open

Invalid index in type #1974

navalex opened this issue May 27, 2024 · 11 comments
Labels

Comments

@navalex
Copy link

navalex commented May 27, 2024

Hello,

I'm trying to use your module to progamaticly generate JSON Schema from my defined types. Most of my custom types extends from packages types, such as Prisma. I don't have a lot of types, for here there are:

import { Prisma, Challenge } from "@prisma/client"
import { SessionRequest } from "supertokens-node/framework/fastify"
import { Certificate } from "tls"

export interface ChallengeWithStats extends Challenge {
	currentValue: number
}

export interface ExoCertificate extends Certificate {
	DC: string
}

interface RouteInterface {
	Params?: unknown
	Body?: unknown
}

export interface FastifyRequestSession<T extends RouteInterface> extends SessionRequest {
	body: T["Body"]
	params: T["Params"]
}

export interface UserWithRoles extends Prisma.UserGetPayload<{ include: { preferences: true } }>{
	roles: string[]
}

export interface SessionJsonData {
	sessionId: string
	start_date: Date
	end_date: Date
	steps: number
	distance: number
	verticalDuration: number
	walkDuration: number
	totalDuration: number
}

export interface SessionStatistics {
	total: {
		steps: number
		distance: number
		verticalDuration: number
		walkDuration: number
		totalDuration: number
	}
}

Note that all those types are located in ./src/types/**.ts, and all exported in ./src/types/index.ts.

Here is my script I'm trying to run to make my schema:

const fs = require("fs")

import("ts-json-schema-generator").then(async tsj => {
	const config = {
		path: "./src/types/index.ts",
		tsconfig: "./tsconfig.json",
		type: "*",
	}

	const outputPath = "./testSchema.json"

	const schema = tsj.createGenerator(config).createSchema(config.type)
	const schemaString = JSON.stringify(schema, null, 2)
	fs.writeFile(outputPath, schemaString, err => {
		if (err) throw err
	})
})

This file is located in ./src/generateSchema.js and i'm running the script like node ./src/schemaGenerator.js

And the output throw me this error:

file:///src/api/node_modules/ts-json-schema-generator/dist/src/NodeParser/IndexedAccessTypeNodeParser.js:60
                    throw new LogicError(`Invalid index "${type.getValue()}" in type "${objectType.getId()}"`);
                          ^

LogicError: Invalid index "exoskeleton" in type "indexed-type-1777104669-59854-59949-1777104669-59841-59950-1777104669-59839-60229-1777104669-59543-60230-1777104669-0-108983<structure-1777104669-16731-16733-1777104669-16717-16746-1777104669-16680-16747-1777104669-0-108983,structure-1777104669-16734-16737-1777104669-16717-16746-1777104669-16680-16747-1777104669-0-108983,structure-1777104669-16738-16741-1777104669-16717-16746-1777104669-16680-16747-1777104669-0-108983,structure-1777104669-16742-16745-1777104669-16717-16746-1777104669-16680-16747-1777104669-0-108983>"
    at file:///src/api/node_modules/ts-json-schema-generator/dist/src/NodeParser/IndexedAccessTypeNodeParser.js:60:27
    at Array.map (<anonymous>)
    at IndexedAccessTypeNodeParser.createType (file:///src/api/node_modules/ts-json-schema-generator/dist/src/NodeParser/IndexedAccessTypeNodeParser.js:47:42)
    at ChainNodeParser.createType (file:///src/api/node_modules/ts-json-schema-generator/dist/src/ChainNodeParser.js:27:54)
    at TypeReferenceNodeParser.createSubContext (file:///src/api/node_modules/ts-json-schema-generator/dist/src/NodeParser/TypeReferenceNodeParser.js:60:62)
    at TypeReferenceNodeParser.createType (file:///src/api/node_modules/ts-json-schema-generator/dist/src/NodeParser/TypeReferenceNodeParser.js:30:70)
    at ChainNodeParser.createType (file:///src/api/node_modules/ts-json-schema-generator/dist/src/ChainNodeParser.js:27:54)
    at AnnotatedNodeParser.createType (file:///src/api/node_modules/ts-json-schema-generator/dist/src/NodeParser/AnnotatedNodeParser.js:25:47)
    at file:///src/api/node_modules/ts-json-schema-generator/dist/src/NodeParser/TypeLiteralNodeParser.js:35:117
    at Array.map (<anonymous>) {
  msg: 'Invalid index "exoskeleton" in type "indexed-type-1777104669-59854-59949-1777104669-59841-59950-1777104669-59839-60229-1777104669-59543-60230-1777104669-0-108983<structure-1777104669-16731-16733-1777104669-16717-16746-1777104669-16680-16747-1777104669-0-108983,structure-1777104669-16734-16737-1777104669-16717-16746-1777104669-16680-16747-1777104669-0-108983,structure-1777104669-16738-16741-1777104669-16717-16746-1777104669-16680-16747-1777104669-0-108983,structure-1777104669-16742-16745-1777104669-16717-16746-1777104669-16680-16747-1777104669-0-108983>"'
}

Node.js v20.13.1

And to be honest, I have no clue about how to read and correct this at this point!

Do you guys have any clue on how to fix this ?

Thanks

@domoritz
Copy link
Member

Thanks for the report. Can you provide a minimal reproducible example that demonstrates the issue?

@navalex
Copy link
Author

navalex commented May 27, 2024

Yeah sorry, here is a little project I made up to reproduce this:

package.json

{
  "name": "test",
  "version": "1.0.0",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC",
  "description": "",
  "devDependencies": {
    "@types/node": "^20.12.12",
    "prisma": "^5.14.0",
    "ts-json-schema-generator": "^2.2.0",
    "ts-node": "^10.9.2",
    "typescript": "^5.4.5"
  },
  "dependencies": {
    "@prisma/client": "^5.14.0"
  }
}

prisma/schema.prisma

generator client {
    provider = "prisma-client-js"
}

datasource db {
    provider = "sqlite"
    url      = env("DATABASE_URL")
}

model User {
    id    Int     @id @default(autoincrement())
    email String  @unique
    name  String?
    posts Post[]
}

model Post {
    id        Int     @id @default(autoincrement())
    title     String
    content   String?
    published Boolean @default(false)
    author    User    @relation(fields: [authorId], references: [id])
    authorId  Int
}

types/index.ts

import { User } from '@prisma/client';

export interface UserTest extends User {
    newField: string;
}

schemaGenerator.js

const fs = require("fs")

import("ts-json-schema-generator").then(async tsj => {
	const config = {
		path: "./types/user.ts",
		tsconfig: "./tsconfig.json",
		type: "*",
		schemaId: "WdcTypes",
	}

	const outputPath = "./schemas"

	const schema = tsj.createGenerator(config).createSchema(config.type)
	const schemaString = JSON.stringify(schema, null, 2)
	fs.writeFile(outputPath, schemaString, err => {
		if (err) throw err
	})
})

This example + my personnal tests seems to show that any import from the @prisma/client seems to make the generator crash.

@domoritz
Copy link
Member

That's not yet minimal if you can remove anything and the error state does not change. Oncer you identify the offending change, you can see how it's causing the issues you see.

@navalex
Copy link
Author

navalex commented May 27, 2024

Okay,

I edited my schema:

generator client {
    provider = "prisma-client-js"
}

datasource db {
    provider = "sqlite"
    url      = env("DATABASE_URL")
}

model User {
    name String @unique
}

That make all my files as minimal as possible (not that the error also trigger with the CLI, without using my .js file).
The error occur when I extends any Prisma type. The moment I remove Prisma imports, everything works, if I add a Prisma type, it triggers this error

@arthurfiorette
Copy link
Collaborator

This might be fixed by #1924

@arthurfiorette
Copy link
Collaborator

arthurfiorette commented May 27, 2024

#343 could also help here

@arthurfiorette
Copy link
Collaborator

@navalex can you try with v2.3.0-next.2?

After #1963 added diagnostics, the error thrown will have more info about it.

@arthurfiorette
Copy link
Collaborator

Probably duplicate of #542

@navalex
Copy link
Author

navalex commented May 29, 2024

@navalex can you try with v2.3.0-next.2?

After #1963 added diagnostics, the error thrown will have more info about it.

Okay so, after testing, it does fix the issue on my basic exemple, but does not on my main project. I tried both 2.2.0-next.0 and 2.3.0-next.2, the last one give an enormous output that seems to dump both a ts-json-schema-generator file and probably my file that throw the error (the Prisma generated client, so a big one).

I don't know if I'll have enough time to do more tests this week, so here is at least the output error, may give you more infos:
Here is the full log: https://logpaste.com/OQTlH3wj

I'll also let my package.json and prisma.schema

package.json:

{
	"name": "eveapp-api-core",
	"version": "1.0.1",
	"description": "",
	"scripts": {
		"start:dev": "nodemon --exec 'ts-node -r tsconfig-paths/register' src/server.ts",
		"start:prod": "node -r tsconfig-paths/register dist/server.js",
		"build": "tsc && tsc-alias",
		"test:watch": "jest --watchAll --collectCoverage",
		"test:ci": "jest --collectCoverage",
		"test:manual": "jest",
		"format:check": "prettier --check \"src/**/*.ts\"",
		"format:write": "prettier --write \"src/**/*.ts\"",
		"lint:check": "eslint \"src/**/*.ts\"",
		"lint:fix": "eslint --fix \"src/**/*.ts\"",
		"schema:generate": "node bin/schemaGenerator.js"
	},
	"nodemonConfig": {
		"watch": [
			"src"
		],
		"ext": "ts",
		"exec": "ts-node -r tsconfig-paths/register"
	},
	"author": "",
	"license": "ISC",
	"dependencies": {
		"@fastify/cors": "^9.0.1",
		"@fastify/formbody": "^7.4.0",
		"@fastify/multipart": "^8.2.0",
		"@fastify/sensible": "^5.6.0",
		"@fastify/swagger": "^8.14.0",
		"@fastify/swagger-ui": "^3.0.0",
		"@prisma/client": "^5.14.0",
		"fastify": "^4.27.0",
		"pino-loki": "^2.3.0",
		"pino-pretty": "^11.0.0",
		"prom-client": "^15.1.2",
		"socket.io": "^4.7.5",
		"supertokens-node": "^17.1.2"
	},
	"devDependencies": {
		"@types/jest": "^29.5.12",
		"@types/node": "^20.12.12",
		"eslint": "^9.3.0",
		"eslint-config-prettier": "^9.1.0",
		"jest": "^29.7.0",
		"jest-mock-extended": "^3.0.7",
		"nodemon": "^3.1.0",
		"prettier": "^3.2.5",
		"prisma": "^5.14.0",
		"prisma-json-schema-generator": "5.1.1",
		"prisma-json-types-generator": "^3.0.4",
		"ts-jest": "^29.1.3",
		"ts-json-schema-generator": "^2.3.0-next.2",
		"ts-node": "^10.9.2",
		"tsc-alias": "^1.8.10",
		"tsconfig-paths": "^4.2.0",
		"typescript": "^5.4.5"
	}
}

prisma.schema:

// ############################################
// #
// #           DATABASE DEFINITION
// #
// ############################################

datasource db {
    provider = "postgresql"
    url      = env("API_POSTGRES_URL")
}

generator client {
    provider        = "prisma-client-js"
    previewFeatures = ["fullTextSearch"]
}

generator jsonTypes {
    provider = "prisma-json-types-generator"
}

generator jsonSchema {
    provider   = "prisma-json-schema-generator"
    schemaId   = "PrismaSchema"
    forceAnyOf = true
}

// ############################################
// #
// #                MODELS
// #
// ############################################

model User {
    id                 String                   @id @default(uuid())
    auth_id            String                   @unique
    firstname          String
    lastname           String
    data               Json
    activationToken    String?                  @default(uuid())
    createdAt          DateTime                 @default(now())
    updatedAt          DateTime                 @updatedAt
    following          User[]                   @relation("Follow")
    followers          User[]                   @relation("Follow")
    exoskeletons       ExoskeletonAttribution[]
    challenges         Challenge[]
    authoredChallenges Challenge[]              @relation(name: "challengeAuthor")
    surveys            Survey[]
    preferences        Preferences?
}

model Preferences {
    id        String       @id @default(uuid())
    userId    String       @unique
    user      User         @relation(fields: [userId], references: [id])
    weekStart WeekStartDay @default(MONDAY)
    darkMode  Boolean      @default(false)
    unitType  UnitType     @default(METRIC)
    createdAt DateTime     @default(now())
    updatedAt DateTime     @updatedAt
}

model Exoskeleton {
    serial       String                   @id
    version      String?
    createdAt    DateTime                 @default(now())
    updatedAt    DateTime                 @updatedAt
    attributions ExoskeletonAttribution[]
}

model ExoskeletonAttribution {
    id            String      @id @default(uuid())
    createdAt     DateTime    @default(now())
    revokedAt     DateTime?
    exoskeletonId String
    userId        String
    exoskeleton   Exoskeleton @relation(fields: [exoskeletonId], references: [serial])
    user          User        @relation(fields: [userId], references: [id])
    sessions      Session[]
}

model Session {
    id            String                 @id @default(uuid())
    /// [SessionData]
    data          Json
    createdAt     DateTime               @default(now())
    updatedAt     DateTime               @updatedAt
    attributionId String
    attribution   ExoskeletonAttribution @relation(fields: [attributionId], references: [id])
}

model Challenge {
    id             String             @default(uuid())
    targetValue    Float
    metric         ChallengeMetric
    frequency      ChallengeFrequency
    repeate        Boolean            @default(false)
    weekRepetition Int?
    createdAt      DateTime           @default(now())
    archivedAt     DateTime?
    userId         String
    authorId       String
    user           User               @relation(fields: [userId], references: [id])
    author         User               @relation(name: "challengeAuthor", fields: [authorId], references: [id])

    @@id(name: "challengeId", [id, createdAt])
}

model ChallengeTemplate {
    id          String             @id @default(uuid())
    description String?
    targetValue Float
    metric      ChallengeMetric
    frequency   ChallengeFrequency
}

model Survey {
    id        String     @id @default(uuid())
    type      SurveyType
    data      Json
    createdAt DateTime   @default(now())
    userId    String
    user      User       @relation(fields: [userId], references: [id])
}

// ############################################
// #
// #                 ENUMS
// #
// ############################################

enum ChallengeMetric {
    STEP_COUNT
    DISTANCE
    VERTICAL_DURATION
    WALK_DURATION
}

enum ChallengeFrequency {
    DAILY
    WEEKLY
}

enum SurveyType {
    DAILY_MOOD
}

enum WeekStartDay {
    MONDAY
    SUNDAY
}

enum UnitType {
    METRIC
    IMPERIAL
}

@arthurfiorette
Copy link
Collaborator

Hey @navalex what about our latest release?

@imjuni
Copy link

imjuni commented Jul 19, 2024

@arthurfiorette hello, thank you for your effort.

I create reproducible repository: https://github.com/imjuni/reproducible-prisma

sadly, ts-json-schema-generator cannot generate schema from mapped access type using prisma generated, like: https://github.com/imjuni/reproducible-prisma/blob/e2590cf2dff10f0d1eb7ad887a82656be6489faf/src/dto/ITagDto.ts#L6

I was tested 2.3.0-next.5 and 2.4.0-next.1.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

4 participants