Skip to content

Commit 29a85e0

Browse files
committed
Fix microsoft#10758 Add compiler option to parse in strict mode
* add compiler option alwaysStrict * compile in strict mode when option is set * emit "use strict"
1 parent d34916a commit 29a85e0

19 files changed

+170
-2
lines changed

Diff for: src/compiler/binder.ts

+13-2
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,8 @@ namespace ts {
121121

122122
// If this file is an external module, then it is automatically in strict-mode according to
123123
// ES6. If it is not an external module, then we'll determine if it is in strict mode or
124-
// not depending on if we see "use strict" in certain places (or if we hit a class/namespace).
124+
// not depending on if we see "use strict" in certain places or if we hit a class/namespace
125+
// or if compiler options contain alwaysStrict.
125126
let inStrictMode: boolean;
126127

127128
let symbolCount = 0;
@@ -139,7 +140,7 @@ namespace ts {
139140
file = f;
140141
options = opts;
141142
languageVersion = getEmitScriptTarget(options);
142-
inStrictMode = !!file.externalModuleIndicator;
143+
inStrictMode = bindInStrictMode(file, opts);
143144
classifiableNames = createMap<string>();
144145
symbolCount = 0;
145146
skipTransformFlagAggregation = isDeclarationFile(file);
@@ -174,6 +175,16 @@ namespace ts {
174175

175176
return bindSourceFile;
176177

178+
function bindInStrictMode(file: SourceFile, opts: CompilerOptions): boolean {
179+
if (opts.alwaysStrict && !isDeclarationFile(file)) {
180+
// bind in strict mode source files with alwaysStrict option
181+
return true;
182+
}
183+
else {
184+
return !!file.externalModuleIndicator;
185+
}
186+
}
187+
177188
function createSymbol(flags: SymbolFlags, name: string): Symbol {
178189
symbolCount++;
179190
return new Symbol(flags, name);

Diff for: src/compiler/commandLineParser.ts

+5
Original file line numberDiff line numberDiff line change
@@ -444,6 +444,11 @@ namespace ts {
444444
name: "importHelpers",
445445
type: "boolean",
446446
description: Diagnostics.Import_emit_helpers_from_tslib
447+
},
448+
{
449+
name: "alwaysStrict",
450+
type: "boolean",
451+
description: Diagnostics.Parse_in_strict_mode_and_emit_use_strict_for_each_source_file
447452
}
448453
];
449454

Diff for: src/compiler/diagnosticMessages.json

+4
Original file line numberDiff line numberDiff line change
@@ -2861,6 +2861,10 @@
28612861
"category": "Error",
28622862
"code": 6140
28632863
},
2864+
"Parse in strict mode and emit \"use strict\" for each source file": {
2865+
"category": "Message",
2866+
"code": 6141
2867+
},
28642868
"Variable '{0}' implicitly has an '{1}' type.": {
28652869
"category": "Error",
28662870
"code": 7005

Diff for: src/compiler/transformers/ts.ts

+12
Original file line numberDiff line numberDiff line change
@@ -436,6 +436,11 @@ namespace ts {
436436
function visitSourceFile(node: SourceFile) {
437437
currentSourceFile = node;
438438

439+
// ensure "use strict"" is emitted in all scenarios in alwaysStrict mode
440+
if (compilerOptions.alwaysStrict) {
441+
node = emitUseStrict(node);
442+
}
443+
439444
// If the source file requires any helpers and is an external module, and
440445
// the importHelpers compiler option is enabled, emit a synthesized import
441446
// statement for the helpers library.
@@ -472,6 +477,13 @@ namespace ts {
472477
return node;
473478
}
474479

480+
function emitUseStrict(node: SourceFile): SourceFile {
481+
const statements: Statement[] = [];
482+
statements.push(startOnNewLine(createStatement(createLiteral("use strict"))));
483+
// add "use strict" as the first statement
484+
return updateSourceFileNode(node, statements.concat(node.statements));
485+
}
486+
475487
/**
476488
* Tests whether we should emit a __decorate call for a class declaration.
477489
*/

Diff for: src/compiler/types.ts

+1
Original file line numberDiff line numberDiff line change
@@ -2929,6 +2929,7 @@ namespace ts {
29292929
allowSyntheticDefaultImports?: boolean;
29302930
allowUnreachableCode?: boolean;
29312931
allowUnusedLabels?: boolean;
2932+
alwaysStrict?: boolean;
29322933
baseUrl?: string;
29332934
charset?: string;
29342935
/* @internal */ configFilePath?: string;

Diff for: src/harness/unittests/transpile.ts

+4
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,10 @@ var x = 0;`, {
253253
options: { compilerOptions: { allowUnusedLabels: true }, fileName: "input.js", reportDiagnostics: true }
254254
});
255255

256+
transpilesCorrectly("Supports setting 'alwaysStrict'", "x;", {
257+
options: { compilerOptions: { alwaysStrict: true }, fileName: "input.js", reportDiagnostics: true }
258+
});
259+
256260
transpilesCorrectly("Supports setting 'baseUrl'", "x;", {
257261
options: { compilerOptions: { baseUrl: "./folder/baseUrl" }, fileName: "input.js", reportDiagnostics: true }
258262
});

Diff for: tests/baselines/reference/alwaysStrict.errors.txt

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
tests/cases/compiler/alwaysStrict.ts(3,9): error TS1100: Invalid use of 'arguments' in strict mode.
2+
3+
4+
==== tests/cases/compiler/alwaysStrict.ts (1 errors) ====
5+
6+
function f() {
7+
var arguments = [];
8+
~~~~~~~~~
9+
!!! error TS1100: Invalid use of 'arguments' in strict mode.
10+
}

Diff for: tests/baselines/reference/alwaysStrict.js

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
//// [alwaysStrict.ts]
2+
3+
function f() {
4+
var arguments = [];
5+
}
6+
7+
//// [alwaysStrict.js]
8+
"use strict";
9+
function f() {
10+
var arguments = [];
11+
}

Diff for: tests/baselines/reference/alwaysStrictES6.errors.txt

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
tests/cases/compiler/alwaysStrictES6.ts(3,9): error TS1100: Invalid use of 'arguments' in strict mode.
2+
3+
4+
==== tests/cases/compiler/alwaysStrictES6.ts (1 errors) ====
5+
6+
function f() {
7+
var arguments = [];
8+
~~~~~~~~~
9+
!!! error TS1100: Invalid use of 'arguments' in strict mode.
10+
}

Diff for: tests/baselines/reference/alwaysStrictES6.js

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
//// [alwaysStrictES6.ts]
2+
3+
function f() {
4+
var arguments = [];
5+
}
6+
7+
//// [alwaysStrictES6.js]
8+
"use strict";
9+
function f() {
10+
var arguments = [];
11+
}
+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
tests/cases/compiler/alwaysStrictModule.ts(4,13): error TS1100: Invalid use of 'arguments' in strict mode.
2+
3+
4+
==== tests/cases/compiler/alwaysStrictModule.ts (1 errors) ====
5+
6+
module M {
7+
export function f() {
8+
var arguments = [];
9+
~~~~~~~~~
10+
!!! error TS1100: Invalid use of 'arguments' in strict mode.
11+
}
12+
}

Diff for: tests/baselines/reference/alwaysStrictModule.js

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
//// [alwaysStrictModule.ts]
2+
3+
module M {
4+
export function f() {
5+
var arguments = [];
6+
}
7+
}
8+
9+
//// [alwaysStrictModule.js]
10+
"use strict";
11+
var M;
12+
(function (M) {
13+
function f() {
14+
var arguments = [];
15+
}
16+
M.f = f;
17+
})(M || (M = {}));
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
tests/cases/compiler/alwaysStrictNoImplicitUseStrict.ts(4,13): error TS1100: Invalid use of 'arguments' in strict mode.
2+
3+
4+
==== tests/cases/compiler/alwaysStrictNoImplicitUseStrict.ts (1 errors) ====
5+
6+
module M {
7+
export function f() {
8+
var arguments = [];
9+
~~~~~~~~~
10+
!!! error TS1100: Invalid use of 'arguments' in strict mode.
11+
}
12+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
//// [alwaysStrictNoImplicitUseStrict.ts]
2+
3+
module M {
4+
export function f() {
5+
var arguments = [];
6+
}
7+
}
8+
9+
//// [alwaysStrictNoImplicitUseStrict.js]
10+
"use strict";
11+
var M;
12+
(function (M) {
13+
function f() {
14+
var arguments = [];
15+
}
16+
M.f = f;
17+
})(M || (M = {}));

Diff for: tests/baselines/reference/transpile/Supports setting alwaysStrict.js

+3
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Diff for: tests/cases/compiler/alwaysStrict.ts

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
// @alwaysStrict: true
2+
3+
function f() {
4+
var arguments = [];
5+
}

Diff for: tests/cases/compiler/alwaysStrictES6.ts

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
// @target: ES6
2+
// @alwaysStrict: true
3+
4+
function f() {
5+
var arguments = [];
6+
}

Diff for: tests/cases/compiler/alwaysStrictModule.ts

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
// @module: commonjs
2+
// @alwaysStrict: true
3+
4+
module M {
5+
export function f() {
6+
var arguments = [];
7+
}
8+
}
+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
// @module: commonjs
2+
// @alwaysStrict: true
3+
// @noImplicitUseStrict: true
4+
5+
module M {
6+
export function f() {
7+
var arguments = [];
8+
}
9+
}

0 commit comments

Comments
 (0)