tst-reflect icon indicating copy to clipboard operation
tst-reflect copied to clipboard

TypeError: Cannot read properties of undefined (reading 'declarations') (monorepo Nx)

Open CristianPi opened this issue 3 years ago • 8 comments

The project is a monorepo created with Nx. I'm using ts-patch (ttypescript) to allow transformers globally on the project Is this error related to the local private pkg?

Stack

ERROR in ./apps/api/src/app.module.ts
Module build failed (from ./node_modules/ts-loader/index.js):
TypeError: Cannot read properties of undefined (reading 'declarations')
    at processGenericCallExpression (/home/zzzzz/IdeaProjects/xxxx/node_modules/tst-reflect-transformer/dist/processGenericCallExpression.js:12:25)
    at mainVisitor (/home/zzzzz/IdeaProjects/xxxx/node_modules/tst-reflect-transformer/dist/visitors/mainVisitor.js:43:97)
    at Context._visitor (/home/zzzzz/IdeaProjects/xxxx/node_modules/tst-reflect-transformer/dist/contexts/Context.js:9:35)
    at visitNodes (/home/zzzzz/IdeaProjects/xxxx/node_modules/typescript/lib/typescript.js:87060:48)
    at Object.visitEachChild (/home/zzzzz/IdeaProjects/xxxx/node_modules/typescript/lib/typescript.js:87363:67)
    at mainVisitor (/home/zzzzz/IdeaProjects/xxxx/node_modules/tst-reflect-transformer/dist/visitors/mainVisitor.js:85:15)
    at Context._visitor (/home/zzzzz/IdeaProjects/xxxx/node_modules/tst-reflect-transformer/dist/contexts/Context.js:9:35)
    at visitNode (/home/zzzzz/IdeaProjects/xxxx/node_modules/typescript/lib/typescript.js:87007:23)
    at Object.visitEachChild (/home/zzzzz/IdeaProjects/xxxx/node_modules/typescript/lib/typescript.js:87634:115)
    at mainVisitor (/home/zzzzz/IdeaProjects/xxxx/node_modules/tst-reflect-transformer/dist/visitors/mainVisitor.js:85:15)

Affected line

processGenericCallExpression.js

    if (!fncType.symbol.declarations) {
        throw new Error("Unable to resolve declarations of symbol.");
    }

Affected file

import {Module} from '@nestjs/common';
import {AppController} from './app.controller';
import {AppService} from './app.service';
import {GraphQLModule} from '@nestjs/graphql';
import {ApolloDriver, ApolloDriverConfig} from '@nestjs/apollo';
import {join} from 'path'
import {TasksModule} from './task/task.module';
import {MongooseModule} from '@nestjs/mongoose';
import {RequestContextCreatorInterceptor, RequestContextModule} from "@privatepkt/nestjs-request-context";
import {APP_INTERCEPTOR} from "@nestjs/core";

@Module({
  imports: [
    RequestContextModule, // thread-local / asyncLocalStorage for the nest request
    TasksModule,
    GraphQLModule.forRoot<ApolloDriverConfig>({
      driver: ApolloDriver,
      autoSchemaFile: join(process.cwd(), 'apps/api/schema.gql'),
      sortSchema: true,
      definitions: {
        path: join(process.cwd(), 'apps/api/schema.ts'),
        outputAs: 'interface',
      },
      // TODO disable for prod
      introspection: true,
      debug: true,
      playground: true,
    }),
    // TODO use env var
    MongooseModule.forRoot('mongodb://localhost/db', {
      user: "xxx",
      pass: "xxx"
    })
  ],
  controllers: [AppController],
  providers: [AppService,
    {
      provide: APP_INTERCEPTOR,
      useClass: RequestContextCreatorInterceptor, // thread-local / asyncLocalStorage for the nest request, analyze request and fill data (graphql, http ect)
    }],
})
export class AppModule {
}

tsconfig.base,json

    "paths": {
      "@privatepkt/graphql-utils": [
        "libs/graphql-utils/src/index.ts"
      ],
      "@privatepkt/nestjs-request-context": [
        "libs/nestjs-request-context/src/index.ts"
      ]
    },
    ,
    "plugins": [
      {
        "transform": "tst-reflect-transformer"
      }
    ]

If you have suggestion on how to fix this let me know :).

CristianPi avatar May 03 '22 17:05 CristianPi

Hello @CristianPi ,

There must be some call of generic function/method/decorator which has no declararation (no .ts file nor .d.ts file). I made some changes, I hope it will help. Try to install the new version [email protected] and let me know. I did some quick test with Angular in the past, but I never test it with complex project. There can be some other issues.

PS: I work on a new major version, containing big changes... Angular support should be included. I prepared docs for Angular https://github.com/Hookyns/tst-reflect/blob/v0.10/docs/usage/angular.md There is a DEMO at the end of the guide. But you've already made it run, so nothing interesting for you.

Hookyns avatar May 03 '22 21:05 Hookyns

Hi @Hookyns Currently i'm using Nestjs (node framework) and React as fronted, i know, Nest looks like angular but fortunately is not :)

I checked the change but the problem persist as symbol is missing on the fncType

fncType.symbol -> undefined

I patched the lib locally with

    if (fncType.symbol == null || !fncType.symbol.declarations) {
        if (context.config.debugMode) {
            context.log.debug("Unable to resolve declaration of the generic type's symbol signature.\r\n" + (0, getNodeLocationText_1.getNodeLocationText)(node));
        }
        return undefined;
    }

Also i don't see the emitted metadata :eyes: only

const _ßr = __webpack_require__("tst-reflect");

without any

_ßr.Type.store.set(...)

Don't know if the problem is related as this is a little bit tricky for me to know/check.

CristianPi avatar May 03 '22 21:05 CristianPi

Probably the transformer is not working on the project, it could explain the fncType.symbol -> undefined

Example code

console.log("TasksService",getType<TasksService>())
[ERR] tst-reflect: You call getType() method directly. You have probably wrong configuration, because tst-reflect-transformer package should replace this call by the Type instance.
If you have right configuration it may be BUG so try to create an issue.
If it is not an issue and you don't want to see this debug message, create field 'tst-reflect-disable' in global object (window | global | globalThis) eg. `window['tst-reflect-disable'] = true;`
TasksService TypeActivator {
  _name: 'unknown',
  _fullName: 'unknown',
  _kind: 2,
  _constructors: [],
  _properties: [],
  _methods: [],
  _decorators: [],
  _typeParameters: [],
  _ctor: [Function: ctor],
  _ctorDesc: ConstructorImportActivator {},
  _interface: undefined,
  _isUnion: false,
  _isIntersection: false,
  _types: [],
  _literalValue: undefined,
  _typeArgs: [],
  _conditionalType: undefined,
  _indexedAccessType: undefined,
  _genericTypeConstraint: undefined,
  _genericTypeDefault: undefined,
  _baseType: undefined
}

CristianPi avatar May 03 '22 21:05 CristianPi

🤦 fixing from the bed... I missed Nest imports and the fact that the symbol is undefined not declaration... the error message is super clear. 🤦 I'll fix that tomorrow.


Do you have some kind of hot reloads? I think there is a bug with generated identifiers, webpack (or some loader) find identifiers unrelated while reloading and omit the metadata. Does full build work? Does just tsc work?

Do you use typelib or inline mode? https://github.com/Hookyns/tst-reflect/wiki/Configuration

Hookyns avatar May 03 '22 21:05 Hookyns

Similar project: https://github.com/knowankit/fullstack-monorepo-boilerplate

Yes, it's using a hot reload but i have the same problem building for production/dev.

I tried changing the config (typelib and/or inline) inside the tsconfig.base.json but it's ignored. (a problem with reading the configs?) For testing i edited

function transform(program) {
    TransformerContext_1.default.instance.init(program);
    return (context) => {
        return (node) => ts.visitNode(node, getVisitor(context, program));
    };
}

and i enabled debug/changed flags but nothing.

testing with tsc:

tsc -p tsconfig.app.json (run inside apps/api)

and i get a crash


[WRN] tst-reflect-transformer Unexpected decorator argument. Only constant values are allowed.
        At () => ID (/home/cristian/IdeaProjects/xxx/apps/api/src/task/task.schema.ts:16:9)  
[WRN] tst-reflect-transformer Unexpected decorator argument. Only constant values are allowed.
        At {required: true} (/home/cristian/IdeaProjects/xxx/apps/api/src/task/task.schema.ts:19:8)  
[WRN] tst-reflect-transformer Unexpected decorator argument. Only constant values are allowed.
        At {type:Date} (/home/cristian/IdeaProjects/xxx/apps/api/src/task/task.schema.ts:31:8)  
[WRN] tst-reflect-transformer Unexpected decorator argument. Only constant values are allowed.
        At {type:Date} (/home/cristian/IdeaProjects/xxx/apps/api/src/task/task.schema.ts:35:8)  
[WRN] tst-reflect-transformer Unexpected decorator argument. Only constant values are allowed.
        At {nullable: true} (/home/cristian/IdeaProjects/xxx/apps/api/src/task/task.schema.ts:36:9)  
/home/cristian/IdeaProjects/xxx/node_modules/typescript/lib/tsc.js:115715
                throw e;
                ^

Error: Debug Failure. False expression: Expected fileName to be present in command line
    at Object.getOutputFileNames (/home/cristian/IdeaProjects/xxx/node_modules/typescript/lib/typescript.js:108442:18)
    at getOutPathForSourceFile (/home/cristian/IdeaProjects/xxx/node_modules/tst-reflect-transformer/dist/helpers.js:266:19)
    at getExportOfConstructor (/home/cristian/IdeaProjects/xxx/node_modules/tst-reflect-transformer/dist/getExports.js:28:56)
    at getTypeDescription (/home/cristian/IdeaProjects/xxx/node_modules/tst-reflect-transformer/dist/getTypeDescription.js:242:79)
    at getTypeCall (/home/cristian/IdeaProjects/xxx/node_modules/tst-reflect-transformer/dist/getTypeCall.js:21:71)
    at /home/cristian/IdeaProjects/xxx/node_modules/tst-reflect-transformer/dist/getProperties.js:19:50
    at Array.map (<anonymous>)
    at getProperties (/home/cristian/IdeaProjects/xxx/node_modules/tst-reflect-transformer/dist/getProperties.js:14:14)
    at getTypeDescription (/home/cristian/IdeaProjects/xxx/node_modules/tst-reflect-transformer/dist/getTypeDescription.js:235:50)
    at getTypeCall (/home/cristian/IdeaProjects/xxx/node_modules/tst-reflect-transformer/dist/getTypeCall.js:21:71)

but looking at the .js files i see the metadatas

_ßr.Type.store.set(1308, { k: 4, n: "Date", args: [] });
_ßr.Type.store.set(92, { k: 1, n: "Task", fn: "xxx/apps/api/src/task/task.schema.ts:Task#92", props: [{ n: "_id", t: _ßr.Type.store.wrap({ n: "number", k: 2, ctor: function () {
                    return Promise.resolve(Number);
                } }), d: [{ n: "Prop", fn: "@nestjs/mongoose/dist/decorators/prop.decorator.d.ts:Prop#98" }, { n: "Field", fn: "@nestjs/graphql/dist/decorators/field.decorator.d.ts:Field#99", args: [null] }], am: 2, acs: 0, ro: false, o: false }, { n: "title", t: _ßr.Type.store.wrap({ n: "string", k: 2, ctor: function () {
                    return Promise.resolve(String);
                } }), d: [{ n: "Prop", fn: "@nestjs/mongoose/dist/decorators/prop.decorator.d.ts:Prop#98", args: [null] }, { n: "Field", fn: "@nestjs/graphql/dist/decorators/field.decorator.d.ts:Field#99" }], am: 2, acs: 0, ro: false, o: false }, { n: "description", t: _ßr.Type.store.wrap({ n: "string", k: 2, ctor: function () {
                    return Promise.resolve(String);
                } }), d: [{ n: "Prop", fn: "@nestjs/mongoose/dist/decorators/prop.decorator.d.ts:Prop#98" }, { n: "Field", fn: "@nestjs/graphql/dist/decorators/field.decorator.d.ts:Field#99" }], am: 2, acs: 0, ro: false, o: false }, { n: "status", t: _ßr.Type.store.wrap({ n: "string", k: 2, ctor: function () {
                    return Promise.resolve(String);
                } }), d: [{ n: "Prop", fn: "@nestjs/mongoose/dist/decorators/prop.decorator.d.ts:Prop#98" }, { n: "Field", fn: "@nestjs/graphql/dist/decorators/field.decorator.d.ts:Field#99" }], am: 2, acs: 0, ro: false, o: false }, { n: "startDate", t: _ßr.Type.store.get(1308), d: [{ n: "Prop", fn: "@nestjs/mongoose/dist/decorators/prop.decorator.d.ts:Prop#98", args: [null] }, { n: "Field", fn: "@nestjs/graphql/dist/decorators/field.decorator.d.ts:Field#99" }], am: 2, acs: 0, ro: false, o: false }, { n: "endDate", t: _ßr.Type.store.get(1308), d: [{ n: "Prop", fn: "@nestjs/mongoose/dist/decorators/prop.decorator.d.ts:Prop#98", args: [null] }, { n: "Field", fn: "@nestjs/graphql/dist/decorators/field.decorator.d.ts:Field#99", args: [null] }], am: 2, acs: 0, ro: false, o: false }], decs: [{ n: "reflect", fn: "tst-reflect/dist/reflect.d.ts:reflect#94" }, { n: "Schema", fn: "@nestjs/mongoose/dist/decorators/schema.decorator.d.ts:Schema#95" }, { n: "ObjectType", fn: "@nestjs/graphql/dist/decorators/object-type.decorator.d.ts:ObjectType#96" }], ctors: [{ params: [] }], ctor: function () {
        return Promise.resolve(require("./task.schema").Task);
    } });

my package.json

    "ts-patch": "2.0.1",
    "tst-reflect-transformer": "0.9.6",
    "typescript": "4.6.4",

(tspach needs ts-patch install -s)

Just for reference I tried typescript-rtti and it's working (but breaks nestjs lol).

Tomorrow i'm going to create a fork of https://github.com/knowankit/fullstack-monorepo-boilerplate and configure tst-reflect for testing purpose

CristianPi avatar May 04 '22 01:05 CristianPi

Error with sourcefile when building using tsc fixed by PR #38 Merged in main, not published yet.

Hookyns avatar May 04 '22 11:05 Hookyns

Tomorrow i'm going to create a fork of https://github.com/knowankit/fullstack-monorepo-boilerplate and configure tst-reflect for testing purpose

It would be nice. I'll try it this weekend.

Hookyns avatar May 04 '22 22:05 Hookyns

@Hookyns Sorry, life got the best of me.

Here the full configured repo: (npm i && npm run dev) https://github.com/CristianPi/fullstack-monorepo-boilerplate

i changed the webpack config to disable transpileOnly (the root cause of all!)

there's just a little problem: ReferenceError: _ßr is not defined

culprit: Missing import const _ßr = require("tst-reflect"); on every file

/***/ "./apps/api/src/task/task.service.ts":
/***/ ((__unused_webpack_module, exports, __webpack_require__) => {


Object.defineProperty(exports, "__esModule", ({ value: true }));
exports.TasksService = void 0;
const tslib_1 = __webpack_require__("tslib");
const mongoose_1 = __webpack_require__("mongoose");
const common_1 = __webpack_require__("@nestjs/common");
const mongoose_2 = __webpack_require__("@nestjs/mongoose");
const task_schema_1 = __webpack_require__("./apps/api/src/task/task.schema.ts");
const tst_reflect_1 = __webpack_require__("tst-reflect");
//NOT DEFINED (_ßr) 
_ßr.Type.store.set(109, { k: 1, n: "TasksService", fn: "complicated-todo/apps/api/src/task/task.service.ts:TasksService#109", props: [{ n: "tasksModel", t: _ßr.Type.store.get(126), d: [{ n: "InjectModel", fn: "@nestjs/mongoose/dist/common/mongoose.decorators.d.ts:__type#4103", args: [null] }], am: 0, acs: 0, ro: false, o: false }], meths: [{ n: "getTasks", params: [], rt: _ßr.Type.store.get(26145), tp: [], o: false, am: 2 }, { n: "getTask", params: [{ n: "id", t: _ßr.Type.store.get(101), o: false }], rt: _ßr.Type.store.get(26626), tp: [], o: false, am: 2 }, { n: "createTask", params: [{ n: "task", t: _ßr.Type.store.get(98), o: false }], rt: _ßr.Type.store.get(26626), tp: [], o: false, am: 2 }, { n: "updateTask", params: [{ n: "id", t: _ßr.Type.store.get(101), o: false }, { n: "update", t: _ßr.Type.store.get(103), o: false }], rt: _ßr.Type.store.get(26626), tp: [], o: false, am: 2 }, { n: "deleteTask", params: [{ n: "taskId", t: _ßr.Type.store.get(101), o: false }], rt: _ßr.Type.store.get(26626), tp: [], o: false, am: 2 }], decs: [{ n: "reflect", fn: "tst-reflect/dist/reflect.d.ts:reflect#111" }, { n: "Injectable", fn: "@nestjs/common/decorators/core/injectable.decorator.d.ts:Injectable#85" }], ctors: [{ params: [{ n: "tasksModel", t: _ßr.Type.store.get(126), o: false }] }], ctor: function () {
        return Promise.resolve((__webpack_require__("./apps/api/src/task/task.service.ts").TasksService));
    } });
let TasksService = class TasksService {
    constructor(tasksModel) {
        this.tasksModel = tasksModel;
    }
    getTasks() {
        return (0, tslib_1.__awaiter)(this, void 0, void 0, function* () {
            return this.tasksModel.find();
        });
    }
    getTask(id) {
        return (0, tslib_1.__awaiter)(this, void 0, void 0, function* () {
            return this.tasksModel.findOne({ _id: id });
        });
    }
    createTask(task) {
        return (0, tslib_1.__awaiter)(this, void 0, void 0, function* () {
            return this.tasksModel.create(task);
        });
    }
    updateTask(id, update) {
        return (0, tslib_1.__awaiter)(this, void 0, void 0, function* () {
            return this.tasksModel.findOneAndUpdate({ _id: id }, update, {
                new: true
            });
        });
    }
    deleteTask(taskId) {
        return (0, tslib_1.__awaiter)(this, void 0, void 0, function* () {
            return this.tasksModel.findOneAndRemove({ _id: taskId });
        });
    }
};

On my local project i fixed this, temporarily, declaring global._ßr = require("tst-reflect");

CristianPi avatar May 13 '22 21:05 CristianPi

Fixed in v1. Not in the current version.

Hookyns avatar Sep 29 '22 06:09 Hookyns