Serialize (noncontextual) keyword named namespace members with export declarations in both declaration emitters#38982
Conversation
… declarations in both declaration emitters
| * @param {T} a | ||
| */ | ||
| export function self<T>(a: T): T; | ||
| function self<T>(a: T): T; |
There was a problem hiding this comment.
While working on this, I found a need for the js declaration emitter to automatically add/strip export modifiers from nested namespace members as needed; so the result of this can be seen in some baseline updates like this - since every member of the containing namespace was exported, there was no need to explicitly have the export modifiers. Now they get stripped, consistent with our transform-based declaration emitter.
| declare namespace Ns { | ||
| export { C1 }; | ||
| const C5: { | ||
| export const C5: { |
There was a problem hiding this comment.
Yes, this was mistakenly missing an export modifier before. (The export statement above made it required, but the emitter never added it).
| "./obj.json": { | ||
| "version": "2151907832-{\n \"val\": 42\n}", | ||
| "signature": "-6323167306-export declare const val: number;\r\n", | ||
| "signature": "-5546159834-export const val: number;\r\n", |
There was a problem hiding this comment.
So! Fun fact: We parse json documents essentially as export = { val: 42 }. Previous to this change, we'd serialize it to
declare namespace export_ {
export declare const val: number;
}
export = _export;then inline it to
export declare const val: number;Now, we first make
declare namespace export_ {
const val: number;
}
export = _export;since we can omit the export and declare modifiers, and inline to
const val: number;which we then patch an export modifier back onto (since we're inlining a namespace where everything was implicitly exported):
export const val: number;so our frugality with the export modifier has, in this case, also caused us to be more frugal with the declare modifier, too. This should be fine, since everything in a .d.ts file is already implicitly declare'd anyway.
sandersn
left a comment
There was a problem hiding this comment.
The fix looks right. I have a few suggestions and one small question before you merge.
| @@ -0,0 +1,84 @@ | |||
| // @declaration: true | |||
There was a problem hiding this comment.
nitpick: shouldn't this test be named tsDeclarationsFunctionKeywordPropExhaustive to match the js test?
There was a problem hiding this comment.
I pulled this in from @a-tarasyuk 's PR and wanted to preserve his history.
| declare namespace foo { | ||
| export var x: number; | ||
| export var y: number; | ||
| var _a: number; |
There was a problem hiding this comment.
wwhy doesn't the ts version generate good names like _break? I guess it's because the JS declaration emit is purpose-built for this, but the TS code is pre-existing.
There was a problem hiding this comment.
Pretty much that. The TS code is just using getGeneratedNameForNode (which is simple and uses these alphanumeric names), while the JS code has a lot of scope tracking machinery in getInternalSymbolName to generate better names where possible.
| /*modifiers*/ undefined, | ||
| createNamedExports([createExportSpecifier(d.expression, createIdentifier(InternalSymbolName.Default))]) | ||
| ) : d); | ||
| const exportModifierStripped = every(defaultReplaced, d => hasSyntacticModifier(d, ModifierFlags.Export)) ? map(defaultReplaced, removeExportModifier) : defaultReplaced; |
There was a problem hiding this comment.
Don't we have a mapSame that would make this more succnctly expressed as
| const exportModifierStripped = every(defaultReplaced, d => hasSyntacticModifier(d, ModifierFlags.Export)) ? map(defaultReplaced, removeExportModifier) : defaultReplaced; | |
| const exportModifierStripped = mapSame(defaultReplaced, d => hasSyntacticModifier(d, ModifierFlags.Export) ? removeExportModifier(d) : d); | |
There was a problem hiding this comment.
Nope, that's not the same at all 😄
If and only if every export has an export modifier, then we can strip the export modifier from every export and retain the same meaning. With your suggestion, we'd remove export modifiers from everything, even if some things didn't have export modifiers, which is very wrong and would make privates public.
| statement.modifierFlagsCache = 0; | ||
| } | ||
|
|
||
| function removeExportModifier(statement: Statement) { |
There was a problem hiding this comment.
could this be defined closer to its usage?
There was a problem hiding this comment.
I prefer it to be here, next to it's cousin, addExportModifier, whose implementation is nearly identical.
* upstream/master: (22 commits) Small fix in `getIsContextSensitiveAssignmentOrContextType` Simplify `visitObjectLiteralExpression` Fix handling of `aruments` in the emitter Fix declaration emit for property references of imported object literal types (microsoft#39055) Fix casing for wild card keys for implicit globs to get wild card directories to watch (microsoft#39049) DOM update 2020-06-12 fix(a11y): make ISSUE_TEMPLATE/Bug_report.md more accessible for folks with screen readers (microsoft#39013) Update request-pr-review script to latest version of octokit (microsoft#39031) pin version of octokit skip implements types with no symbols isDynamicName skips parentheses for element access Allow `e: unknown` in `catch` arguments Serialize (noncontextual) keyword named namespace members with export declarations in both declaration emitters (microsoft#38982) Patch to use this.timeout() > 0 rather than this.enableTimeout() to work with mocha 8+ Handle missing return type nodes and nested type references missing type arguments in existing jsdoc node serialization (microsoft#39011) Add containerName to CallHierarchyItem (microsoft#38997) Fix isSameEntityName (microsoft#38999) Fix typo for 'blocklist' (microsoft#39001) remove errant tab Switch to isSymbolAccessible for both. ...
Fixes #38750
cc @a-tarasyuk I pulled in your test from #38874; I went with a slightly different style of emit for the normal declaration emitter, and, well, the js declaration emitter was just another beast entirely (note for reviewers: I inlined one of the helper functions in the js declaration emitter, so the change isn't actually that large; I just had to inline the helper to set a condition in a branch of it).
Note that the OP in #38750 was hoping to also have non-identifier strings like
"foo bar"also roundtrip; unfortunately, with this emit scheme (as @DanielRosenwasser proposed), such a thing is not possible (without amending syntax somewhere anyway).