Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions internal/printer/printer.go
Original file line number Diff line number Diff line change
Expand Up @@ -5762,6 +5762,14 @@ func (p *Printer) emitPos(pos int) {
return
}

// During declaration emit, nodes reused from other files may have positions
// beyond the current source file's text length. Skip source map emission
// for such positions, matching TypeScript's implicit behavior where
// out-of-bounds string access returns NaN/undefined without crashing.
if pos > len(p.sourceMapSource.Text()) {
return
}

sourceLine, sourceCharacter := p.sourceMapLineCharCache.getLineAndCharacter(pos)
if err := p.sourceMapGenerator.AddSourceMapping(
p.writer.GetLine(),
Expand Down
8 changes: 6 additions & 2 deletions internal/scanner/scanner.go
Original file line number Diff line number Diff line change
Expand Up @@ -2270,11 +2270,15 @@ func SkipTriviaEx(text string, pos int, options *SkipTriviaOptions) int {
if ast.PositionIsSynthesized(pos) {
return pos
}

textLen := len(text)
if pos >= textLen {
return pos
}

if options == nil {
options = &SkipTriviaOptions{}
}

textLen := len(text)
canConsumeStar := false
// Keep in sync with couldStartTrivia
for {
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,234 @@
===================================================================
JsFile: types.d.ts
mapUrl: types.d.ts.map
sourceRoot:
sources: types.ts
===================================================================
-------------------------------------------------------------------
emittedFile:types.d.ts
sourceFile:types.ts
-------------------------------------------------------------------
>>>export interface Widget {
1 >
2 >^^^^^^
3 > ^^^^^^^^^^^
4 > ^^^^^^
1 >
2 >export
3 > interface
4 > Widget
1 >Emitted(1, 1) Source(1, 1) + SourceIndex(0)
2 >Emitted(1, 7) Source(1, 7) + SourceIndex(0)
3 >Emitted(1, 18) Source(1, 18) + SourceIndex(0)
4 >Emitted(1, 24) Source(1, 24) + SourceIndex(0)
---
>>> id: string;
1 >^^^^
2 > ^^
3 > ^^
4 > ^^^^^^
5 > ^
6 > ^^^->
1 > {
>
2 > id
3 > :
4 > string
5 > ;
1 >Emitted(2, 5) Source(2, 5) + SourceIndex(0)
2 >Emitted(2, 7) Source(2, 7) + SourceIndex(0)
3 >Emitted(2, 9) Source(2, 9) + SourceIndex(0)
4 >Emitted(2, 15) Source(2, 15) + SourceIndex(0)
5 >Emitted(2, 16) Source(2, 16) + SourceIndex(0)
---
>>> name: string;
1->^^^^
2 > ^^^^
3 > ^^
4 > ^^^^^^
5 > ^
1->
>
2 > name
3 > :
4 > string
5 > ;
1->Emitted(3, 5) Source(3, 5) + SourceIndex(0)
2 >Emitted(3, 9) Source(3, 9) + SourceIndex(0)
3 >Emitted(3, 11) Source(3, 11) + SourceIndex(0)
4 >Emitted(3, 17) Source(3, 17) + SourceIndex(0)
5 >Emitted(3, 18) Source(3, 18) + SourceIndex(0)
---
>>>}
1 >^
2 > ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^->
1 >
>}
1 >Emitted(4, 2) Source(4, 2) + SourceIndex(0)
---
>>>//# sourceMappingURL=types.d.ts.map===================================================================
JsFile: helper.d.ts
mapUrl: helper.d.ts.map
sourceRoot:
sources: helper.ts
===================================================================
-------------------------------------------------------------------
emittedFile:helper.d.ts
sourceFile:helper.ts
-------------------------------------------------------------------
>>>import { Widget } from "./types";
1 >
2 >^^^^^^^
3 > ^^
4 > ^^^^^^
5 > ^^
6 > ^^^^^^
7 > ^^^^^^^^^
8 > ^
9 > ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^->
1 >
2 >import
3 > {
4 > Widget
5 > }
6 > from
7 > "./types"
8 > ;
1 >Emitted(1, 1) Source(1, 1) + SourceIndex(0)
2 >Emitted(1, 8) Source(1, 8) + SourceIndex(0)
3 >Emitted(1, 10) Source(1, 10) + SourceIndex(0)
4 >Emitted(1, 16) Source(1, 16) + SourceIndex(0)
5 >Emitted(1, 18) Source(1, 18) + SourceIndex(0)
6 >Emitted(1, 24) Source(1, 24) + SourceIndex(0)
7 >Emitted(1, 33) Source(1, 33) + SourceIndex(0)
8 >Emitted(1, 34) Source(1, 34) + SourceIndex(0)
---
>>>export declare function getWidget(): (w: Widget) => keyof Widget;
1->
2 >^^^^^^^^^^^^^^^^^^^^^^^^
3 > ^^^^^^^^^
4 > ^^^^
5 > ^
6 > ^
7 > ^^
8 > ^^^^^^
9 > ^^^^^
10> ^^^^^^
11> ^^^^^^
12> ^
1->
>
>// Here is a bunch of text in comments to pad the file length so positions in the return type annotation below
>// are past the length of the short index.ts file. This is needed to trigger the slice bounds
>// out of range crash when node positions from this file are used with the text of index.ts.
>
2 >export function
3 > getWidget
4 > ():
5 > (
6 > w
7 > :
8 > Widget
9 > ) =>
10> keyof
11> Widget
12> {
> return (w) => "id";
> }
1->Emitted(2, 1) Source(6, 1) + SourceIndex(0)
2 >Emitted(2, 25) Source(6, 17) + SourceIndex(0)
3 >Emitted(2, 34) Source(6, 26) + SourceIndex(0)
4 >Emitted(2, 38) Source(6, 30) + SourceIndex(0)
5 >Emitted(2, 39) Source(6, 31) + SourceIndex(0)
6 >Emitted(2, 40) Source(6, 32) + SourceIndex(0)
7 >Emitted(2, 42) Source(6, 34) + SourceIndex(0)
8 >Emitted(2, 48) Source(6, 40) + SourceIndex(0)
9 >Emitted(2, 53) Source(6, 45) + SourceIndex(0)
10>Emitted(2, 59) Source(6, 51) + SourceIndex(0)
11>Emitted(2, 65) Source(6, 57) + SourceIndex(0)
12>Emitted(2, 66) Source(8, 2) + SourceIndex(0)
---
>>>//# sourceMappingURL=helper.d.ts.map===================================================================
JsFile: index.d.ts
mapUrl: index.d.ts.map
sourceRoot:
sources: index.ts
===================================================================
-------------------------------------------------------------------
emittedFile:index.d.ts
sourceFile:index.ts
-------------------------------------------------------------------
>>>import { Widget } from "./types";
1 >
2 >^^^^^^^
3 > ^^
4 > ^^^^^^
5 > ^^
6 > ^^^^^^
7 > ^^^^^^^^^
8 > ^
1 >
2 >import
3 > {
4 > Widget
5 > }
6 > from
7 > "./types"
8 > ;
1 >Emitted(1, 1) Source(1, 1) + SourceIndex(0)
2 >Emitted(1, 8) Source(1, 8) + SourceIndex(0)
3 >Emitted(1, 10) Source(1, 10) + SourceIndex(0)
4 >Emitted(1, 16) Source(1, 16) + SourceIndex(0)
5 >Emitted(1, 18) Source(1, 18) + SourceIndex(0)
6 >Emitted(1, 24) Source(1, 24) + SourceIndex(0)
7 >Emitted(1, 33) Source(1, 33) + SourceIndex(0)
8 >Emitted(1, 34) Source(1, 34) + SourceIndex(0)
---
>>>export type MyWidget = Widget;
1 >
2 >^^^^^^
3 > ^^^^^^
4 > ^^^^^^^^
5 > ^^^
6 > ^^^^^^
7 > ^
8 > ^^^^^^^^^^^^^^^^^^^^^^^^->
1 >
>import { getWidget } from "./helper";
>
2 >export
3 > type
4 > MyWidget
5 > =
6 > Widget
7 > ;
1 >Emitted(2, 1) Source(3, 1) + SourceIndex(0)
2 >Emitted(2, 7) Source(3, 7) + SourceIndex(0)
3 >Emitted(2, 13) Source(3, 13) + SourceIndex(0)
4 >Emitted(2, 21) Source(3, 21) + SourceIndex(0)
5 >Emitted(2, 24) Source(3, 24) + SourceIndex(0)
6 >Emitted(2, 30) Source(3, 30) + SourceIndex(0)
7 >Emitted(2, 31) Source(3, 31) + SourceIndex(0)
---
>>>export declare const fn: (w: Widget) => keyof Widget;
1->
2 >^^^^^^^^^^^^^^^
3 > ^^^^^^
4 > ^^
5 > ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
6 > ^
1->
>
2 >export
3 > const
4 > fn
5 > = getWidget()
6 > ;
1->Emitted(3, 1) Source(4, 1) + SourceIndex(0)
2 >Emitted(3, 16) Source(4, 8) + SourceIndex(0)
3 >Emitted(3, 22) Source(4, 14) + SourceIndex(0)
4 >Emitted(3, 24) Source(4, 16) + SourceIndex(0)
5 >Emitted(3, 53) Source(4, 30) + SourceIndex(0)
6 >Emitted(3, 54) Source(4, 31) + SourceIndex(0)
---
>>>//# sourceMappingURL=index.d.ts.map
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
//// [tests/cases/compiler/declarationMapReusedNodeFromDifferentFile.ts] ////

=== types.ts ===
export interface Widget {
>Widget : Symbol(Widget, Decl(types.ts, 0, 0))

id: string;
>id : Symbol(Widget.id, Decl(types.ts, 0, 25))

name: string;
>name : Symbol(Widget.name, Decl(types.ts, 1, 15))
}

=== helper.ts ===
import { Widget } from "./types";
>Widget : Symbol(Widget, Decl(helper.ts, 0, 8))

// Here is a bunch of text in comments to pad the file length so positions in the return type annotation below
// are past the length of the short index.ts file. This is needed to trigger the slice bounds
// out of range crash when node positions from this file are used with the text of index.ts.
export function getWidget(): (w: Widget) => keyof Widget {
>getWidget : Symbol(getWidget, Decl(helper.ts, 0, 33))
>w : Symbol(w, Decl(helper.ts, 5, 30))
>Widget : Symbol(Widget, Decl(helper.ts, 0, 8))
>Widget : Symbol(Widget, Decl(helper.ts, 0, 8))

return (w) => "id";
>w : Symbol(w, Decl(helper.ts, 6, 12))
}

=== index.ts ===
import { Widget } from "./types";
>Widget : Symbol(Widget, Decl(index.ts, 0, 8))

import { getWidget } from "./helper";
>getWidget : Symbol(getWidget, Decl(index.ts, 1, 8))

export type MyWidget = Widget;
>MyWidget : Symbol(MyWidget, Decl(index.ts, 1, 37))
>Widget : Symbol(Widget, Decl(index.ts, 0, 8))

export const fn = getWidget();
>fn : Symbol(fn, Decl(index.ts, 3, 12))
>getWidget : Symbol(getWidget, Decl(index.ts, 1, 8))

Loading