Skip to content

Conversation

Copy link
Contributor

Copilot AI commented Oct 22, 2025

Fixes the issue where copyright comments and file headers were emitted in the wrong position relative to prologue directives and module helpers.

Problem

When compiling TypeScript files with copyright headers or JSDoc comments at the top, tsgo was placing them after the generated module code instead of after prologue directives, which didn't match TypeScript's behavior.

Solution

Modified internal/printer/printer.go in the emitSourceFile function to reorder the emit calls to match TypeScript's order:

  1. emitShebangIfNeeded
  2. emitPrologueDirectives
  3. emitDetachedCommentsAndUpdateCommentsInfo (for copyright headers and JSDoc blocks)
  4. emitHelpers (e.g., Object.defineProperty)
  5. emitTripleSlashDirectives
  6. Emit remaining statements

This matches TypeScript's behavior where writeFile calls emitPrologueDirectivesIfNeeded first, then emitSourceFile handles detached comments. The fix simply corrects the order of these emit calls without adding unnecessary complexity.

Results

✅ Copyright comments now correctly appear after "use strict" but before Object.defineProperty
✅ Output matches TypeScript exactly
✅ Simple, clean implementation with no code duplication

Fixes #1526

Original prompt

This section details on the original issue you should resolve

<issue_title>Emit adds generated code before file header/copyright comment</issue_title>
<issue_description>## Steps to reproduce

Compile a ts file with a copyright comment:

/*---------------------------------------------------------------------------------------------
 *  Copyright
 *--------------------------------------------------------------------------------------------*/

export const a = 1;

Behavior with typescript@5.8

The generated helpers and module code is added after the comment:

"use strict";
/*---------------------------------------------------------------------------------------------
 *  Copyright
 *--------------------------------------------------------------------------------------------*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.a = void 0;
exports.a = 1;

Behavior with tsgo

The copyright comment after the added code:

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.a = void 0;
/*---------------------------------------------------------------------------------------------
 *  Copyright
 *--------------------------------------------------------------------------------------------*/
exports.a = 1;

</issue_description>

Comments on the Issue (you are @copilot in this section)

@DanielRosenwasser I don't know how we are doomed in every version of TypeScript ever to have issues with the ordering of prologue directives and copyright headers.

Fixes #1526


💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.

Copilot AI and others added 2 commits October 22, 2025 23:39
When a source file has synthesized prologue directives (e.g., "use strict"
added by module transformation), copyright headers should appear after the
prologue but before emitted helpers like Object.defineProperty.

This matches TypeScript's behavior by emulating its two-phase approach:
1. Emit synthesized prologue directives first
2. Emit detached comments (copyright headers)
3. Emit helpers
4. Emit remaining statements

Co-authored-by: jakebailey <5341706+jakebailey@users.noreply.github.com>
Accept baseline changes for tests affected by the emit order fix.
All changes correctly place detached comments (copyright headers,
JSDoc blocks, etc.) after prologue directives but before helpers.

Co-authored-by: jakebailey <5341706+jakebailey@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix generated code placement in TypeScript files Fix emit order to place copyright comments after prologue directives but before helpers Oct 22, 2025
Copilot AI requested a review from jakebailey October 22, 2025 23:51
Copilot finished work on behalf of jakebailey October 22, 2025 23:51
@jakebailey jakebailey marked this pull request as ready for review October 22, 2025 23:54
Copilot AI review requested due to automatic review settings October 22, 2025 23:54
@jakebailey
Copy link
Member

Wow, I think it got it?

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

This PR fixes the emit order of copyright headers and file-level comments in generated JavaScript output. Previously, tsgo was placing copyright headers after generated module code instead of after prologue directives, which didn't match TypeScript's behavior.

Key changes:

  • Modified emitSourceFile in internal/printer/printer.go to implement a two-phase approach when synthesized prologue directives are present
  • Copyright headers and JSDoc blocks now appear after prologue directives (like "use strict") but before module helpers and other generated code
  • Updated 252 test baselines to reflect the corrected emit order

Reviewed Changes

Copilot reviewed 251 out of 251 changed files in this pull request and generated 2 comments.

File Description
internal/printer/printer.go Implements two-phase emission logic to place detached comments after prologue directives but before helpers
testdata/baselines/reference/submodule/conformance/*.js Updated baselines showing corrected comment positioning in conformance tests
testdata/baselines/reference/submodule/compiler/*.js Updated baselines showing corrected comment positioning in compiler tests
testdata/baselines/reference/compiler/*.js Updated baselines showing corrected comment positioning in local tests

@jakebailey
Copy link
Member

@copilot Address the review comments (from yourself)

…ication

- Updated misleading comment at line 4387 to better reflect the actual logic
- Extracted duplicated prologue emission logic into helper function
  emitPrologueDirectivesAndDetachedComments to improve code clarity

Co-authored-by: jakebailey <5341706+jakebailey@users.noreply.github.com>
Copy link
Contributor Author

Copilot AI commented Oct 23, 2025

@copilot Address the review comments (from yourself)

Addressed both review comments in commit 0ab9a4f:

  1. Updated the misleading comment to better reflect the actual logic
  2. Extracted duplicated prologue emission logic into a helper function

All tests still passing.

Copilot finished work on behalf of jakebailey October 23, 2025 00:10
Removed comments that simply described what the code does, making
the code cleaner and more maintainable.

Co-authored-by: jakebailey <5341706+jakebailey@users.noreply.github.com>
Copilot AI requested a review from jakebailey October 23, 2025 00:23
Copilot finished work on behalf of jakebailey October 23, 2025 00:23
@jakebailey
Copy link
Member

@copilot see my comment, and also make sure the code is formatted

Removed the comment at line 4417 that was just describing what the
code does. Also ran formatter to clean up whitespace issues.

Co-authored-by: jakebailey <5341706+jakebailey@users.noreply.github.com>
Copy link
Contributor Author

Copilot AI commented Oct 23, 2025

@copilot see my comment, and also make sure the code is formatted

Removed the remaining redundant comment and formatted the code. Fixed in 4fbefe6.

Copilot finished work on behalf of jakebailey October 23, 2025 02:23
@jakebailey jakebailey requested a review from weswigham October 23, 2025 16:23
@jakebailey
Copy link
Member

@weswigham Does this pass the smell test?

Copy link
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.

Oh, no, this is just wrong for sure - super duplicative at least. In corsa, emitDetachedCommentsBeforeStatementList (called via emitSourceFile) should already handle this and has conditions that only apply to source files (which is the call it removed and replaced and has only one other use!). It's probably just bugged (dunno how yet - it's not immediately obvious without debugging through the test and checking which conditional bail is wrong/missing).

It's also probably just called in the wrong place - corsa mushes together writeFile, emitSourceFile, and emitSourceFileWorker from strada into emitSourceFile (no need for bundle support allowed some inlining I think), so the effective order of calls is just wrong. It should be emitShebangIfNeeded, then emitPrologueDirectives, then emitDetachedCommentsBeforeStatementList, then emitTripleSlashDirectives, then the main statement list print and so on to match strada ordering of these things. The calls most likely just need to be reordered inside corsa's emitSourceFile to match strada.

@jakebailey
Copy link
Member

Ah well, I guessed as much.

One more shot out of interest.

@copilot Well, read the above, think real hard, and implement it the correct way this time. 🙂

Following @weswigham's feedback, removed the complex helper function
and instead simply reordered the emit calls to match TypeScript:
1. emitShebangIfNeeded
2. emitPrologueDirectives
3. emitDetachedComments (for copyright headers)
4. emitHelpers
5. emitTripleSlashDirectives

This is much simpler, less duplicative, and directly matches the
strada/TypeScript emit order.

Co-authored-by: jakebailey <5341706+jakebailey@users.noreply.github.com>
Copy link
Contributor Author

Copilot AI commented Oct 23, 2025

Ah well, I guessed as much.

One more shot out of interest.
...

Reimplemented with the correct approach. Simply reordered the emit calls to match TypeScript's order:

  1. emitShebangIfNeeded
  2. emitPrologueDirectives
  3. emitDetachedComments
  4. emitHelpers
  5. emitTripleSlashDirectives

Removed the complex helper function and duplication. Much simpler now! Fixed in 3a53c98.

Copilot finished work on behalf of jakebailey October 23, 2025 21:53
@jakebailey
Copy link
Member

Well, this certainly looks less weird

@jakebailey
Copy link
Member

I think I found the real problem / a better fix. Closing and will send a new PR.

@jakebailey jakebailey closed this Oct 23, 2025
@jakebailey jakebailey deleted the copilot/fix-code-generation-order branch October 30, 2025 23:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Emit adds generated code before file header/copyright comment

3 participants