Skip to content

RTK generateEndpoints throws typescript error: Trace: TypeError: Cannot read property 'pos' of undefined #2425

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

Open
isidornygren opened this issue Jun 20, 2022 · 13 comments

Comments

@isidornygren
Copy link

isidornygren commented Jun 20, 2022

Running the RTK code generation as described in the docs by running npx @rtk-query/codegen-openapi openapi-config.ts works fine without any issues.

However, running exactly the same config using the generateEndpoints function produces what looks like a typescript error. I've tried running it both using Node and esbuild-runner but it still errors. I've tried using different openapi endpoints but I still receive the same error when trying to run the function programmatically.

Setup

// src/store/emptyApi.ts
import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react';

export const emptySplitApi = createApi({
  baseQuery: fetchBaseQuery({ baseUrl: '/' }),
  endpoints: () => ({}),
});
// apiConfig.ts
import type { ConfigFile } from '@rtk-query/codegen-openapi';

const apiConfig: ConfigFile = {
  // Using an example openapi endpoint found online
  schemaFile: 'https://petstore.swagger.io/v2/swagger.json',
  apiFile: './src/store/emptyApi.ts',
  apiImport: 'emptySplitApi',
  outputFile: './src/model/generated/api.ts',
  exportName: 'api',
  hooks: true,
};

export default apiConfig;
// generateApi.ts (run through node or esbuild-runner)
const config = {
  schemaFile: 'https://petstore.swagger.io/v2/swagger.json',
  apiFile: './src/store/emptyApi.ts',
  apiImport: 'emptySplitApi',
  outputFile: './src/model/generated/api.ts',
  exportName: 'api',
  hooks: true,
};

generateEndpoints(config).catch(console.trace);

Output

Trace: TypeError: Cannot read property 'pos' of undefined
    at emitNodeList (/Users/***/***/node_modules/@rtk-query/codegen-openapi/node_modules/typescript/lib/typescript.js:111266:48)
    at emitList (/Users/***/***/node_modules/@rtk-query/codegen-openapi/node_modules/typescript/lib/typescript.js:111158:13)
    at emitObjectLiteralExpression (/Users/***/***/node_modules/@rtk-query/codegen-openapi/node_modules/typescript/lib/typescript.js:109538:13)
    at pipelineEmitWithHintWorker (/Users/***/***/node_modules/@rtk-query/codegen-openapi/node_modules/typescript/lib/typescript.js:108863:32)
    at pipelineEmitWithHint (/Users/***/***/node_modules/@rtk-query/codegen-openapi/node_modules/typescript/lib/typescript.js:108479:17)
    at pipelineEmitWithComments (/Users/***/***/node_modules/@rtk-query/codegen-openapi/node_modules/typescript/lib/typescript.js:112033:13)
    at pipelineEmit (/Users/***/***/node_modules/@rtk-query/codegen-openapi/node_modules/typescript/lib/typescript.js:108419:13)
    at emitExpression (/Users/***/***/node_modules/@rtk-query/codegen-openapi/node_modules/typescript/lib/typescript.js:108403:13)
    at emitNodeList (/Users/***/***/node_modules/@rtk-query/codegen-openapi/node_modules/typescript/lib/typescript.js:111271:25)
    at emitExpressionList (/Users/***/***/node_modules/@rtk-query/codegen-openapi/node_modules/typescript/lib/typescript.js:111161:13)
    at processTicksAndRejections (internal/process/task_queues.js:95:5)
@phryneas
Copy link
Member

Have you tried calling parseConfig before?

See

async function run(configFile: string) {
process.chdir(dirname(configFile));
const unparsedConfig = require(configFile);
for (const config of parseConfig(unparsedConfig.default ?? unparsedConfig)) {
try {
console.log(`Generating ${config.outputFile}`);
await generateEndpoints(config);
console.log(`Done`);
} catch (err) {
console.error(err);
process.exit(1);
}
}
}

@isidornygren
Copy link
Author

Have you tried calling parseConfig before?

See

async function run(configFile: string) {
process.chdir(dirname(configFile));
const unparsedConfig = require(configFile);
for (const config of parseConfig(unparsedConfig.default ?? unparsedConfig)) {
try {
console.log(`Generating ${config.outputFile}`);
await generateEndpoints(config);
console.log(`Done`);
} catch (err) {
console.error(err);
process.exit(1);
}
}
}

Yes, I've tried it and it gave me what looked like the same error. However, when double checking i saw that it was slightly different (Albeit still seems to be a typescript parsing error, and I still have no idea why it's happening):

Trace: TypeError: Cannot read property 'end' of undefined
    at emitTupleType (/Users/***/***/node_modules/@rtk-query/codegen-openapi/node_modules/typescript/lib/typescript.js:109373:76)
    at pipelineEmitWithHintWorker (/Users/***/***/node_modules/@rtk-query/codegen-openapi/node_modules/typescript/lib/typescript.js:108569:32)
    at pipelineEmitWithHint (/Users/***/***/node_modules/@rtk-query/codegen-openapi/node_modules/typescript/lib/typescript.js:108479:17)
    at pipelineEmitWithComments (/Users/***/***/node_modules/@rtk-query/codegen-openapi/node_modules/typescript/lib/typescript.js:112033:13)
    at pipelineEmit (/Users/***/***/node_modules/@rtk-query/codegen-openapi/node_modules/typescript/lib/typescript.js:108419:13)
    at emit (/Users/***/***/node_modules/@rtk-query/codegen-openapi/node_modules/typescript/lib/typescript.js:108392:13)
    at emitNodeList (/Users/***/***/node_modules/@rtk-query/codegen-openapi/node_modules/typescript/lib/typescript.js:111271:25)
    at emitList (/Users/***/***/node_modules/@rtk-query/codegen-openapi/node_modules/typescript/lib/typescript.js:111158:13)
    at emitUnionType (/Users/***/***/node_modules/@rtk-query/codegen-openapi/node_modules/typescript/lib/typescript.js:109388:13)
    at pipelineEmitWithHintWorker (/Users/***/***/node_modules/@rtk-query/codegen-openapi/node_modules/typescript/lib/typescript.js:108574:32)
    at processTicksAndRejections (internal/process/task_queues.js:95:5)

Using this code:

const config = parseConfig({
  schemaFile: 'https://petstore.swagger.io/v2/swagger.json',
  apiFile: './src/store/emptyApi.ts',
  apiImport: 'emptySplitApi',
  outputFile: './src/model/generated/api.ts',
  exportName: 'api',
  hooks: true
});

config.forEach((c) => generateEndpoints(c).catch(console.trace));

@kdevan
Copy link

kdevan commented Jun 24, 2022

I'm running into the same issue:

TypeError: Cannot read properties of undefined (reading 'end')
    at emitTupleType (/app/node_modules/@rtk-query/codegen-openapi/node_modules/typescript/lib/typescript.js:109480:76)
    at pipelineEmitWithHintWorker (/app/node_modules/@rtk-query/codegen-openapi/node_modules/typescript/lib/typescript.js:108676:32)
    at pipelineEmitWithHint (/app/node_modules/@rtk-query/codegen-openapi/node_modules/typescript/lib/typescript.js:108586:17)
    at pipelineEmitWithComments (/app/node_modules/@rtk-query/codegen-openapi/node_modules/typescript/lib/typescript.js:112140:13)
    at pipelineEmit (/app/node_modules/@rtk-query/codegen-openapi/node_modules/typescript/lib/typescript.js:108526:13)
    at emit (/app/node_modules/@rtk-query/codegen-openapi/node_modules/typescript/lib/typescript.js:108499:13)
    at emitNodeList (/app/node_modules/@rtk-query/codegen-openapi/node_modules/typescript/lib/typescript.js:111378:25)
    at emitList (/app/node_modules/@rtk-query/codegen-openapi/node_modules/typescript/lib/typescript.js:111265:13)
    at emitUnionType (/app/node_modules/@rtk-query/codegen-openapi/node_modules/typescript/lib/typescript.js:109495:13)
    at pipelineEmitWithHintWorker (/app/node_modules/@rtk-query/codegen-openapi/node_modules/typescript/lib/typescript.js:108681:32)

Also tried adding parseConfig but still getting the same error. I did have this working in a previous version, running into this after updating react, @reduxjs/toolkit, react-redux, and @rtk-query/codegen-openapi to latest versions.

Edit: I wouldn't mind digging into this. Is there some way to get a trace that leads me in the right direction? I'm really just not sure where I would start since the trace is all typescript library file.

@phryneas
Copy link
Member

I just tried this and for me it is working. Maybe it is your TypeScript version? I just tried with 4.5.2.

@kdevan
Copy link

kdevan commented Jun 24, 2022

Ah yeah, didn't think of that. Currently, Typescript 4.7.4. I'll test with 4.5.2 and update here.

@jkirkpatrick24
Copy link

I bumped up against this too. Using typescript 4.7.4 throws the error described above, but reverting to typescript v4.5.2 fixes it.

@phryneas
Copy link
Member

Could you take a look what changed between those versions and if you could come up with a fix?

@kdevan
Copy link

kdevan commented Jun 24, 2022

The function that throws the error seems mostly the same between these versions:

https://raw.githubusercontent.com/microsoft/TypeScript/v4.5.2/lib/typescript.js

function emitTupleType(node) {
    emitTokenWithComment(22 /* OpenBracketToken */, node.pos, writePunctuation, node);
    var flags = ts.getEmitFlags(node) & 1 /* SingleLine */ ? 528 /* SingleLineTupleTypeElements */ : 657 /* MultiLineTupleTypeElements */;
    emitList(node, node.elements, flags | 524288 /* NoSpaceIfEmpty */);
    emitTokenWithComment(23 /* CloseBracketToken */, node.elements.end, writePunctuation, node);
}

https://raw.githubusercontent.com/microsoft/TypeScript/v4.7.4/lib/typescript.js

function emitTupleType(node) {
    emitTokenWithComment(22 /* SyntaxKind.OpenBracketToken */, node.pos, writePunctuation, node);
    var flags = ts.getEmitFlags(node) & 1 /* EmitFlags.SingleLine */ ? 528 /* ListFormat.SingleLineTupleTypeElements */ : 657 /* ListFormat.MultiLineTupleTypeElements */;
    emitList(node, node.elements, flags | 524288 /* ListFormat.NoSpaceIfEmpty */, parenthesizer.parenthesizeElementTypeOfTupleType);
    emitTokenWithComment(23 /* SyntaxKind.CloseBracketToken */, node.elements.end, writePunctuation, node);
}

Can see that node.elements.end is the offending object/array. I'll keep digging and update if I find anything.

Edit: Looks to me like filterEndpoints and endpointOverrides are the two possible properties that can be undefined and also use a possible List/NodeList and Tuple type? The stack trace mentions a UnionType -> List -> NodeList -> Tuple. I need to fix some stuff in my project and then I can test this theory out, I'll update as soon as I can.

@kdevan
Copy link

kdevan commented Jun 26, 2022

filterEndpoints and endpointOverrides ended up being the culprits. If you add them to the configuration with an empty array as the value then it works. Both parameters trigger the error.

{
    ...
    filterEndpoints: [],
    endpointOverrides: [],
}

Edit: False positive because I was just filtering every endpoint. I added regex to include everything so that I could pass a value to filterEndpoints without it being undefined but I still get the error. Still looking.

@isidornygren
Copy link
Author

Reverting to typescript version 4.5.2 unfortunately does not seem to change anything for me, I've tried forcing the rtk-query codegen typescript version by adding:

{
  "devDependencies": {
     ...
     "typescript": "=4.5.2"
  },
  "resolutions": {
    "@rtk-query/codegen-openapi/typescript": "=4.5.2"
  },
}

But still getting the same issue:

Trace: TypeError: Cannot read property 'end' of undefined
    at emitTupleType (/Users/***/***/node_modules/typescript/lib/typescript.js:109342:76)
    at pipelineEmitWithHintWorker (/Users/***/***/node_modules/typescript/lib/typescript.js:108538:32)
    at pipelineEmitWithHint (/Users/***/***/node_modules/typescript/lib/typescript.js:108448:17)
    at pipelineEmitWithComments (/Users/***/***/node_modules/typescript/lib/typescript.js:112002:13)
    at pipelineEmit (/Users/***/***/node_modules/typescript/lib/typescript.js:108388:13)
    at emit (/Users/***/***/node_modules/typescript/lib/typescript.js:108361:13)
    at emitNodeList (/Users/***/***/node_modules/typescript/lib/typescript.js:111240:25)
    at emitList (/Users/***/***/node_modules/typescript/lib/typescript.js:111127:13)
    at emitUnionType (/Users/***/***/node_modules/typescript/lib/typescript.js:109357:13)
    at pipelineEmitWithHintWorker (/Users/***/***/node_modules/typescript/lib/typescript.js:108543:32)
    at processTicksAndRejections (internal/process/task_queues.js:95:5)

Running yarn list --pattern typescript

yarn list v1.22.15
*omitted*
└─ [email protected]
✨  Done in 0.78s.

@lindapaiste
Copy link
Contributor

lindapaiste commented Jun 29, 2022

I am able to reproduce this error in TS version 4.7.4 (but not on 4.3.5). I am running Node.js version 16.13.0 on Windows.

I'm hoping that I'll get a chance to dig into it and figure out how we can make the codegen compatible with the latest TS version.

I'm not sure at this point if the issue would occur if both the app and the codegen are using v4.7.4. When I saw the error it was with the app on the latest 4.7.4 but the codegen will load its own version fitting the specified range "typescript": ">=4.1 <=4.5".

This is the node which triggers the error when passed to emitTupleType. There is no elements property, so the node.elements.end gives that "TypeError: Cannot read property 'end' of undefined" error.

{
  "pos": -1,
  "end": -1,
  "flags": 8,
  "modifierFlagsCache": 0,
  "transformFlags": 1,
  "kind": 183,
  "elementType": {
    "pos": -1,
    "end": -1,
    "flags": 8,
    "modifierFlagsCache": 0,
    "transformFlags": 1,
    "kind": 178,
    "typeName": {
      "pos": -1,
      "end": -1,
      "flags": 8,
      "modifierFlagsCache": 0,
      "transformFlags": 0,
      "kind": 79,
      "escapedText": "Pet"
    }
  },
  "emitNode": {
    "leadingComments": [
      {
        "kind": 3,
        "pos": -1,
        "end": -1,
        "hasTrailingNewLine": false,
        "text": "* status 200 successful operation "
      }
    ]
  }
}

So we need to go up a few levels to figure out why emitTupleType is getting called with this type which is not a tuple.

The line that it is trying to write is:

export type FindPetsByStatusApiResponse = /** status 200 successful operation */ Pet[];

It should have an array of Pet, but somehow it winds up with type 183 (TupleType) instead. ArrayType is 182, so it's an off-by-one. I ask myself "would they ever change those numbers?"...and the answer is YES.

I am not yet fully understanding which parts of the code are executed with the app TS version and which use the codegen's version, but it seems like this is a version mismatch problem.

In my project's node_modules\typescript\lib\typescript.js, version 4.7.4, line 111166-111169:

case 183 /* SyntaxKind.ArrayType */:
  return emitArrayType(node);
case 184 /* SyntaxKind.TupleType */:
   return emitTupleType(node);

In the file where the error is triggered, node_modules\@rtk-query\codegen-openapi\node_modules\typescript\lib\typescript.js, version 4.5.5, line 108566-108569:

case 182 /* ArrayType */:
  return emitArrayType(node);
case 183 /* TupleType */:
  return emitTupleType(node);

@phryneas
Copy link
Member

Oh, good catch. TS versions make a lot of sense. oazapfts has to run with the exact same TS version as the module itself - we are trying to enforce that with enforceOazapftsTsVersion but it seems that does not work here. Are y'all using some kind of special bundler? I could imagine this happening with yarn-pnp.

function enforceOazapftsTsVersion<T>(cb: () => T): T {
const ozTsPath = require.resolve('typescript', { paths: [require.resolve('oazapfts')] });
const tsPath = require.resolve('typescript');
const originalEntry = require.cache[ozTsPath];
try {
require.cache[ozTsPath] = require.cache[tsPath];
return cb();
} finally {
if (originalEntry) {
require.cache[ozTsPath] = originalEntry;
} else {
delete require.cache[ozTsPath];
}
}

@kdevan
Copy link

kdevan commented Jul 3, 2022

Yeah, in my project oazapfts itself is using typescript 4.7.4 while rtk-query-codegen-openapi is using 4.5.5. Since oazapfts is used for typescript generation, nodes are being generated using 4.7.4 and then being processed by this library using 4.5.5.

In my case this is due to how I have yarn set up, using yarn 3.2.1 workspaces with nodeLinker: node-modules in .yarnrc.yml.

I tried adding a resolution to force everything to use 4.7.4 and everything is working so far:

"resolutions": {
  "typescript": "4.7.4"
}

Obviously this is risky to force libraries to use a version they don't expect but for now it's allowing development on this front to continue. :)

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

No branches or pull requests

6 participants