ToddThomson / tsproject

Typescript minifier and modular typescript bundle optimizer for gulp (Ts Vinyl Adapter).

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

TypeError: Cannot read property 'flags' of undefined

frankebersoll opened this issue · comments

When building our project with minification enabled, we get this:

[18:40:31] TypeError: Cannot read property 'flags' of undefined
    at IdentifierInfo.isPrivateProperty (/Users/Frank/Entwicklung/node/Exceptionless.JavaScript/node_modules/tsproject/tsproject.min.js:1284:53)
    at BundleMinifier.canShortenIdentifier (/Users/Frank/Entwicklung/node/Exceptionless.JavaScript/node_modules/tsproject/tsproject.min.js:1781:28)
    at BundleMinifier.processIdentifierInfo (/Users/Frank/Entwicklung/node/Exceptionless.JavaScript/node_modules/tsproject/tsproject.min.js:1760:18)
    at BundleMinifier.shortenContainerIdentifiers (/Users/Frank/Entwicklung/node/Exceptionless.JavaScript/node_modules/tsproject/tsproject.min.js:1742:18)
    at BundleMinifier.shortenIdentifiers (/Users/Frank/Entwicklung/node/Exceptionless.JavaScript/node_modules/tsproject/tsproject.min.js:1712:14)
    at BundleMinifier.minify (/Users/Frank/Entwicklung/node/Exceptionless.JavaScript/node_modules/tsproject/tsproject.min.js:1685:14)
    at BundleMinifier.transform (/Users/Frank/Entwicklung/node/Exceptionless.JavaScript/node_modules/tsproject/tsproject.min.js:1504:21)
    at BundleCompiler.compile (/Users/Frank/Entwicklung/node/Exceptionless.JavaScript/node_modules/tsproject/tsproject.min.js:2457:41)
    at Project.buildWorker (/Users/Frank/Entwicklung/node/Exceptionless.JavaScript/node_modules/tsproject/tsproject.min.js:2659:44)
    at Project.build (/Users/Frank/Entwicklung/node/Exceptionless.JavaScript/node_modules/tsproject/tsproject.min.js:2576:32)
franks-macbook:Exceptionless.JavaScript Frank$ gulp typescript.node

Looks like "A property has a value declaration" isn't true in every case, but I don't know enough about the AST to understand what's going on here.

The current symbol looks like this:

SymbolObject {
  flags: 134217732,
  name: 'prototype',
  parent: 
   SymbolObject {
     flags: 32,
     name: 'Configuration',
     declarations: [ [Object] ],
     exports: 
      { prototype: [Circular],
        _defaultSettings: [Object],
        defaults: [Object] },
     members: 
      { defaultTags: [Object],
        defaultData: [Object],
        enabled: [Object],
        environmentInfoCollector: [Object],
        errorParser: [Object],
        lastReferenceIdManager: [Object],
        log: [Object],
        moduleCollector: [Object],
        requestInfoCollector: [Object],
        submissionBatchSize: [Object],
        submissionAdapter: [Object],
        submissionClient: [Object],
        settings: [Object],
        storage: [Object],
        queue: [Object],
        _plugins: [Object],
        __constructor: [Object],
        _apiKey: [Object],
        apiKey: [Object],
        isValid: [Object],
        _serverUrl: [Object],
        serverUrl: [Object],
        _dataExclusions: [Object],
        _userAgentBotPatterns: [Object],
        dataExclusions: [Object],
        addDataExclusions: [Object],
        userAgentBotPatterns: [Object],
        addUserAgentBotPatterns: [Object],
        plugins: [Object],
        addPlugin: [Object],
        removePlugin: [Object],
        setVersion: [Object],
        setUserIdentity: [Object],
        userAgent: [Object],
        useSessions: [Object],
        useReferenceIds: [Object],
        useLocalStorage: [Object],
        useDebugLogger: [Object] },
     valueDeclaration: 
      NodeObject {
        kind: 217,
        pos: 29933,
        end: 42727,
        flags: 2,
        parent: [Object],
        decorators: undefined,
        modifiers: [Object],
        name: [Object],
        typeParameters: undefined,
        heritageClauses: [Object],
        members: [Object],
        symbol: [Circular],
        localSymbol: [Object],
        nextContainer: [Object],
        id: 90264 },
     parent: 
      SymbolObject {
        flags: 512,
        name: '"exceptionless.node.min"',
        declarations: [Object],
        exports: [Object],
        valueDeclaration: [Object],
        id: 56518 },
     id: 55548 },
  id: 56470 }

@frankebersoll The current symbol flag value is 134217732. This is a combination of SymbolFlags.Prototype + SymbolFlags.Property. The symbol dump indicates that you have something like

Configuration.prototype.someProperty = somePropertyValue;

I realize that "prototype" is a reserved word and thus cannot be shortened. I will review how reserved words are treated in TsProject.

I will need to add a test for this usage and investigate. Perhaps you can provide a code snippet from your project for this purpose.

I will resolve this issue early next week.

Hey Todd,

you can use this commit to reproduce the issue:

exceptionless/Exceptionless.JavaScript@113155c

Cheers and have a nice weekend!

@frankebersoll I don't use git command line, so I am not sure how to download the source you are referring to above. I tried downloading the features/build branch, but I cannot get it to compile without error. Please let me know what to download to reproduce this issue. Thanks.

@frankebersoll I've been able to recreate this issue by downloading exceptionless.javascript release 1.3.2 and modifying it slightly.
While is is obvious that the 'prototype' property cannot be shortened, I want to make sure that TsProject handles assignment to the 'prototype' properly.
It may be the case that your PR fixes this issue, but I have a feeling that the general fix will take a bit more - I just can't be sure until I write a test scenario.

@frankebersoll This is an interesting issue. It is not straight forward!

@frankebersoll I've opened an issue with the TypeScript project microsoft/TypeScript#8024

I need to resolve the TypeScript issue before I can complete fixing your issue.

@frankebersoll @niemyjski I believe the solution to this issue can be handled by simply checking for a null valueDeclaration. However, as I thought, there are issue(s) that (may) result from this. TypeScript 1.8.9 does not resolve the Type for this in functions that are assigned to object.prototype (well, they are resolved to any). This leads to property identifiers not having associated symbols. TsProject uses these unique identifier symbols to shorten all occurrences of a given identifier.
Since you make an assignment to the Configuration.prototype.UseLocalStorage in your initialization code, which references the this.storage property in Configuration, the identifier storage in this case would not have a symbol and would not be shortened (iff the Configuration.storage identifier was private and was shortened ).
Now, I know that Configuration.storage in your specific case is public, so the identifier would not be shortened and thus no runtime error would be caused by minification. However, in general object properties can be marked as private and are thus candidates for shortening which would then result in runtime errors if they are accessed through the object prototype functions.
So, in the short term, I can patch TsProject to check for a null valueDeclaration in the appropriate places. However if you access object properties or methods in functions that are assigned to the object prototype you must mark them as public.
Please let me know what you think.

@frankebersoll @niemyjski I've written some experimental code to resolve the Type for this when it is contained in a function that has been assigned to a class object prototype. I am not sure why TypeScript does not do this ( there prob. is a reason which will become apparent when they answer my issue ).
Are you in a rush to have this issue resolved?

@ToddThomson I don't think we are in any big hurry but we are looking to switch from uglify to the new stuff soon.

I don't say this enough but I really appreciate all the work you do!

@niemyjski Thanks!
I am ready to release TsProject version 1.2.1. It will contain the fix for this issue. It will also include type resolution for this within functions that are assigned to the object prototype property.

This issue has been addressed in release 1.2.1. Thank-you for your input!

Awesome!!

Great stuff, thank you so much!

@frankebersoll @niemyjski You're welcome.
The minification feature is pretty new. It is used to build TsProject itself, so it does work quite well (better than all the current javascript minifiers). If you do run into any issues I should be able to address them quickly. Good luck and happy coding!

It looks like we are still hitting this issue. I'll work on getting more information.

@ToddThomson do you know if any progress has been made on this, it looks like it's the same exact issue that we ran into before (Just working on upgrading us to latest typescript https://github.com/exceptionless/Exceptionless.JavaScript/tree/feature/latest-ts)


[TsProject] Building bundle:  src/exceptionless-nodespec
[22:44:46] 'typescript.test' errored after 2.55 s
[22:44:46] TypeError: Cannot read property 'flags' of undefined
    at Object.getBaseTypes (/Users/blake/Code/Exceptionless.JavaScript/node_modules/typescript/lib/typescript.js:28239:37)
    at R.U (/Users/blake/Code/Exceptionless.JavaScript/node_modules/tsproject/tsproject.min.js:1:34088)
    at R.Q (/Users/blake/Code/Exceptionless.JavaScript/node_modules/tsproject/tsproject.min.js:1:33804)
    at /Users/blake/Code/Exceptionless.JavaScript/node_modules/tsproject/tsproject.min.js:1:32840
    at Array.forEach (native)
    at _loop_1 (/Users/blake/Code/Exceptionless.JavaScript/node_modules/tsproject/tsproject.min.js:1:32685)
    at R.O (/Users/blake/Code/Exceptionless.JavaScript/node_modules/tsproject/tsproject.min.js:1:33198)
    at V.bb (/Users/blake/Code/Exceptionless.JavaScript/node_modules/tsproject/tsproject.min.js:1:42564)
    at V.Y (/Users/blake/Code/Exceptionless.JavaScript/node_modules/tsproject/tsproject.min.js:1:41067)
    at Object.src (/Users/blake/Code/Exceptionless.JavaScript/node_modules/tsproject/tsproject.min.js:1:45967)

Seems to only happen when were running gulp typescript.test

I think this has something to do with how we export functions in our tests:

export function describeStorage(name: string,
                                storageFactory: (maxItems?: number) => IStorage,
                                beforeEachCallback?: () => void,
                                recreateStorage: boolean = false) {

The passed in type to typescript.getBaseTypes(type) has an intrinsicName of unknown. and the symbol object is just the function name we export in the previous stack frame

Kinda getting the feeling that it's expecting my functions to be exported from a class, and they are not (they are just test scripts)