Skip to content

Jsdoc values as namespaces#20198

Merged
sandersn merged 26 commits into
masterfrom
jsdoc-values-as-namespaces
Nov 30, 2017
Merged

Jsdoc values as namespaces#20198
sandersn merged 26 commits into
masterfrom
jsdoc-values-as-namespaces

Conversation

@sandersn
Copy link
Copy Markdown
Member

Fixes one blocking issue for compiling the chrome devtools.

  1. In Javascript, support type references to class expressions whose
    name is obtained via "static property assignment" to another class like
    so:
function Outer() {
  this.y = 2
}
Outer.Inner = class { }

/** @type {Outer.Inner} */
var inner;
  1. In Javascript, support type references to properties of function and
    class expressions that are assigned to a variable, like so:
var Outer = function {
  this.y = 2
}
Outer.Inner = class { }

/** @type {Outer.Inner} */
var inner;

1. In Javascript, support type references to class expressions whose
name is obtained via "static property assignment" to another class like
so:

```ts
function Outer() {
  this.y = 2
}
Outer.Inner = class { }

/** @type {Outer.Inner} */
var inner;
```

2. In Javascript, support type references to properties of function and
class expressions that are assigned to a variable, like so:

```ts
var Outer = function {
  this.y = 2
}
Outer.Inner = class { }

/** @type {Outer.Inner} */
var inner;
```
Now it turns out that we don't support Closure's property declaration
style, which doesn't require assignment in the constructor:

```js
class C {
  constructor() {
    /** @type {number} */
    this.n
  }
}
```

This means that we still miss basically all the properties of class.

Also the 'conflicting declarations' message still mentions absolute
paths :(
@sandersn
Copy link
Copy Markdown
Member Author

Note that chrome devtools doesn't improve that much because now we don't recognise devtools' way of declaring properties. We expect assignments, but it uses just a type annotation:

class C {
  constructor() {
    /** @type {number} x */
    this.x;
  }
}

@sandersn
Copy link
Copy Markdown
Member Author

After discussion with @weswigham and @mhegazy, I moved the bulk of the solution to the binder, which results in a more general solution. I still have some cleanup to do, and the current PR won't cover IIFEs or certain other patterns, but it's better than before.

I also added recognition of type-annotation-as-declaration:

/** @type {number} */
p.x;

class C {
  constructor() {
    /** @type {string} */
    this.x
  }
}

This, too, needs some cleanup, since I originally only intended it to work for the latter case.

This means that Javascript property assignments always create a
namespace, never statics on a class. The ES5->ES6 class refactoring
still needs to be updated.
Declaring values didn't work before.
export default fails right now; I haven't got it to work and it's not in
dev tools, so I don't know if it's worth the effort.
Like: `var SDK = {}`.

These are normally generated by the Chrome dev tools build; adding them
gets rid of more than 10,000 errors
This removes tons of errors.
Don't issue a "multiple declarations must have the same type" error for
JS static property assignments, because these don't appear to have a
type in this case.
@sandersn
Copy link
Copy Markdown
Member Author

OK, I think this is in a good state now. Thanks @weswigham and @mhegazy for your help. Mind taking a look?

Copy link
Copy Markdown
Member

@weswigham weswigham left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some small comments, but it looks like a pretty good change!

Comment thread src/compiler/binder.ts Outdated

// Look up the function in the local scope, since prototype assignments should
/**
* For nodes like `x.y = z`, declare a member 'y' on 'x' if x was a function.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the if x was a function qualifier in this comment still true?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated: It's now function, class or not declared. I have a change that will make it also {}, but that's in a branch that I'll make a PR for after this PR is in.

Comment thread src/compiler/checker.ts Outdated
function mergeSymbol(target: Symbol, source: Symbol) {
if (!(target.flags & getExcludedSymbolFlags(source.flags))) {
if (!(target.flags & getExcludedSymbolFlags(source.flags)) ||
source.valueDeclaration && source.valueDeclaration.kind === SyntaxKind.Identifier ||
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd say that there should probably be an extra symbol flag you set on these symbols to imply this, rather than relying on the value declaration being an identifier implying this.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good idea, for now at least. There are still symbol flags to burn.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

Comment thread src/compiler/checker.ts Outdated
}

function errorNextVariableOrPropertyDeclarationMustHaveSameType(firstDeclaration: Declaration, firstType: Type, nextDeclaration: Declaration, nextType: Type): void {
if (isIdentifier(firstDeclaration) || isIdentifier(nextDeclaration)) {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again, I really feel like this should be a flag on the symbol and not be information implicitly derived from the declaration being an identifier.

Comment thread src/compiler/binder.ts
else {
isLegalPosition = propertyAccess.parent.parent.kind === SyntaxKind.SourceFile;
}
if (!isPrototypeProperty && (!targetSymbol || !(targetSymbol.flags & SymbolFlags.Namespace)) && isLegalPosition) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we need to handle these recursivelly as well.. i.e. today we handel:

var outer;
outer = function() {};
outer.inner = function () {};

but we should also handle:

var outer;
outer = function() {};
outer.inner = function () {};
outer.inner.another = function () {};

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good idea. I will do that in a follow-up PR. It will require touching even more of the existing code.

@sandersn sandersn merged commit 2ec2238 into master Nov 30, 2017
@sandersn sandersn deleted the jsdoc-values-as-namespaces branch November 30, 2017 20:56
@microsoft microsoft locked and limited conversation to collaborators Jun 14, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants