Skip to content

Commit c493d07

Browse files
authored
copy prologue directives to new file (#40306)
1 parent 94123d5 commit c493d07

9 files changed

+187
-5
lines changed

src/compiler/core.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2272,4 +2272,14 @@ namespace ts {
22722272
export function padRight(s: string, length: number, padString: " " = " ") {
22732273
return length <= s.length ? s : s + padString.repeat(length - s.length);
22742274
}
2275+
2276+
export function takeWhile<T, U extends T>(array: readonly T[], predicate: (element: T) => element is U): U[];
2277+
export function takeWhile<T>(array: readonly T[], predicate: (element: T) => boolean): T[] {
2278+
const len = array.length;
2279+
let index = 0;
2280+
while (index < len && predicate(array[index])) {
2281+
index++;
2282+
}
2283+
return array.slice(0, index);
2284+
}
22752285
}

src/services/refactors/moveToNewFile.ts

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -65,20 +65,26 @@ namespace ts.refactor {
6565
readonly ranges: readonly StatementRange[];
6666
}
6767

68-
// Filters imports out of the range of statements to move. Imports will be copied to the new file anyway, and may still be needed in the old file.
6968
function getStatementsToMove(context: RefactorContext): ToMove | undefined {
7069
const rangeToMove = getRangeToMove(context);
7170
if (rangeToMove === undefined) return undefined;
7271
const all: Statement[] = [];
7372
const ranges: StatementRange[] = [];
7473
const { toMove, afterLast } = rangeToMove;
75-
getRangesWhere(toMove, s => !isPureImport(s), (start, afterEndIndex) => {
74+
getRangesWhere(toMove, isAllowedStatementToMove, (start, afterEndIndex) => {
7675
for (let i = start; i < afterEndIndex; i++) all.push(toMove[i]);
7776
ranges.push({ first: toMove[start], afterLast });
7877
});
7978
return all.length === 0 ? undefined : { all, ranges };
8079
}
8180

81+
function isAllowedStatementToMove(statement: Statement): boolean {
82+
// Filters imports and prologue directives out of the range of statements to move.
83+
// Imports will be copied to the new file anyway, and may still be needed in the old file.
84+
// Prologue directives will be copied to the new file and should be left in the old file.
85+
return !isPureImport(statement) && !isPrologueDirective(statement);;
86+
}
87+
8288
function isPureImport(node: Node): boolean {
8389
switch (node.kind) {
8490
case SyntaxKind.ImportDeclaration:
@@ -111,10 +117,10 @@ namespace ts.refactor {
111117
oldFile: SourceFile, usage: UsageInfo, changes: textChanges.ChangeTracker, toMove: ToMove, program: Program, newModuleName: string, preferences: UserPreferences,
112118
) {
113119
const checker = program.getTypeChecker();
114-
120+
const prologueDirectives = takeWhile(oldFile.statements, isPrologueDirective);
115121
if (!oldFile.externalModuleIndicator && !oldFile.commonJsModuleIndicator) {
116122
deleteMovedStatements(oldFile, toMove.ranges, changes);
117-
return toMove.all;
123+
return [...prologueDirectives, ...toMove.all];
118124
}
119125

120126
const useEs6ModuleSyntax = !!oldFile.externalModuleIndicator;
@@ -126,20 +132,21 @@ namespace ts.refactor {
126132

127133
deleteUnusedOldImports(oldFile, toMove.all, changes, usage.unusedImportsFromOldFile, checker);
128134
deleteMovedStatements(oldFile, toMove.ranges, changes);
129-
130135
updateImportsInOtherFiles(changes, program, oldFile, usage.movedSymbols, newModuleName);
131136

132137
const imports = getNewFileImportsAndAddExportInOldFile(oldFile, usage.oldImportsNeededByNewFile, usage.newFileImportsFromOldFile, changes, checker, useEs6ModuleSyntax, quotePreference);
133138
const body = addExports(oldFile, toMove.all, usage.oldFileImportsFromNewFile, useEs6ModuleSyntax);
134139
if (imports.length && body.length) {
135140
return [
141+
...prologueDirectives,
136142
...imports,
137143
SyntaxKind.NewLineTrivia as const,
138144
...body
139145
];
140146
}
141147

142148
return [
149+
...prologueDirectives,
143150
...imports,
144151
...body,
145152
];
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
/// <reference path='fourslash.ts' />
2+
3+
// @Filename: /a.ts
4+
////"use strict";
5+
////[|function b() {
6+
//// return this;
7+
////}|]
8+
////b();
9+
10+
verify.moveToNewFile({
11+
newFileContents: {
12+
"/a.ts":
13+
`"use strict";
14+
b();`,
15+
16+
"/b.ts":
17+
`"use strict";
18+
function b() {
19+
return this;
20+
}
21+
`,
22+
},
23+
});
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
/// <reference path='fourslash.ts' />
2+
3+
// @module: commonjs
4+
// @allowJs: true
5+
6+
// @Filename: /foo.js
7+
////exports.foo = function () {};
8+
9+
// @Filename: /a.js
10+
////"use strict";
11+
////const foo = require("./foo");
12+
////[|function b() {
13+
//// return this;
14+
////}|]
15+
////b();
16+
17+
verify.moveToNewFile({
18+
newFileContents: {
19+
"/a.js":
20+
`"use strict";
21+
const { b } = require("./b");
22+
const foo = require("./foo");
23+
b();`,
24+
25+
"/b.js":
26+
`"use strict";
27+
function b() {
28+
return this;
29+
}
30+
exports.b = b;
31+
`,
32+
},
33+
});
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
/// <reference path='fourslash.ts' />
2+
3+
// @Filename: /a.ts
4+
////[|"use strict";|]
5+
6+
verify.noMoveToNewFile();
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
/// <reference path='fourslash.ts' />
2+
3+
// @Filename: /a.ts
4+
////function foo() {
5+
//// [|"use strict";|]
6+
////}
7+
8+
verify.noMoveToNewFile();
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/// <reference path='fourslash.ts' />
2+
3+
// @module: esnext
4+
5+
// @Filename: /foo.ts
6+
////export default function () {}
7+
8+
// @Filename: /a.ts
9+
////"use strict";
10+
////import foo from "./foo";
11+
////[|function b() {
12+
//// return foo;
13+
////}|]
14+
////b();
15+
16+
verify.moveToNewFile({
17+
newFileContents: {
18+
"/a.ts":
19+
`"use strict";
20+
import { b } from "./b";
21+
b();`,
22+
23+
"/b.ts":
24+
`"use strict";
25+
import foo from "./foo";
26+
27+
export function b() {
28+
return foo;
29+
}
30+
`,
31+
},
32+
});
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
/// <reference path='fourslash.ts' />
2+
3+
// @module: esnext
4+
5+
// @Filename: /foo.ts
6+
////export default function () {}
7+
8+
// @Filename: /a.ts
9+
////"use strict";
10+
////"use foo";
11+
////"use bar";
12+
////import foo from "./foo";
13+
////[|function b() {
14+
//// return foo;
15+
////}|]
16+
////b();
17+
18+
verify.moveToNewFile({
19+
newFileContents: {
20+
"/a.ts":
21+
`"use strict";
22+
"use foo";
23+
"use bar";
24+
import { b } from "./b";
25+
b();`,
26+
27+
"/b.ts":
28+
`"use strict";
29+
"use foo";
30+
"use bar";
31+
import foo from "./foo";
32+
33+
export function b() {
34+
return foo;
35+
}
36+
`,
37+
},
38+
});
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
/// <reference path='fourslash.ts' />
2+
3+
// @Filename: /a.ts
4+
////"use strict";
5+
////[|function b() {
6+
//// return this;
7+
////}|]
8+
////"prologue directive like statement";
9+
////b();
10+
11+
verify.moveToNewFile({
12+
newFileContents: {
13+
"/a.ts":
14+
`"use strict";
15+
"prologue directive like statement";
16+
b();`,
17+
18+
"/b.ts":
19+
`"use strict";
20+
function b() {
21+
return this;
22+
}
23+
`,
24+
},
25+
});

0 commit comments

Comments
 (0)