Skip to content

Commit fc641b9

Browse files
committed
Merge branch 'slawomir-10758-always-strict'
2 parents 80ef348 + 2920f82 commit fc641b9

28 files changed

+303
-2
lines changed

src/compiler/binder.ts

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,8 @@ namespace ts {
122122

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

128129
let symbolCount = 0;
@@ -140,7 +141,7 @@ namespace ts {
140141
file = f;
141142
options = opts;
142143
languageVersion = getEmitScriptTarget(options);
143-
inStrictMode = !!file.externalModuleIndicator;
144+
inStrictMode = bindInStrictMode(file, opts);
144145
classifiableNames = createMap<string>();
145146
symbolCount = 0;
146147
skipTransformFlagAggregation = isDeclarationFile(file);
@@ -175,6 +176,16 @@ namespace ts {
175176

176177
return bindSourceFile;
177178

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

src/compiler/commandLineParser.ts

Lines changed: 5 additions & 0 deletions
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

src/compiler/diagnosticMessages.json

Lines changed: 4 additions & 0 deletions
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

src/compiler/factory.ts

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2235,6 +2235,33 @@ namespace ts {
22352235
return statementOffset;
22362236
}
22372237

2238+
/**
2239+
* Ensures "use strict" directive is added
2240+
*
2241+
* @param node source file
2242+
*/
2243+
export function ensureUseStrict(node: SourceFile): SourceFile {
2244+
let foundUseStrict = false;
2245+
for (const statement of node.statements) {
2246+
if (isPrologueDirective(statement)) {
2247+
if (isUseStrictPrologue(statement as ExpressionStatement)) {
2248+
foundUseStrict = true;
2249+
break;
2250+
}
2251+
}
2252+
else {
2253+
break;
2254+
}
2255+
}
2256+
if (!foundUseStrict) {
2257+
const statements: Statement[] = [];
2258+
statements.push(startOnNewLine(createStatement(createLiteral("use strict"))));
2259+
// add "use strict" as the first statement
2260+
return updateSourceFileNode(node, statements.concat(node.statements));
2261+
}
2262+
return node;
2263+
}
2264+
22382265
/**
22392266
* Wraps the operand to a BinaryExpression in parentheses if they are needed to preserve the intended
22402267
* order of operations.

src/compiler/program.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1473,6 +1473,10 @@ namespace ts {
14731473
programDiagnostics.add(createCompilerDiagnostic(Diagnostics.Option_0_cannot_be_specified_with_option_1, "lib", "noLib"));
14741474
}
14751475

1476+
if (options.noImplicitUseStrict && options.alwaysStrict) {
1477+
programDiagnostics.add(createCompilerDiagnostic(Diagnostics.Option_0_cannot_be_specified_with_option_1, "noImplicitUseStrict", "alwaysStrict"));
1478+
}
1479+
14761480
const languageVersion = options.target || ScriptTarget.ES3;
14771481
const outFile = options.outFile || options.out;
14781482

src/compiler/transformers/ts.ts

Lines changed: 5 additions & 0 deletions
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 = ensureUseStrict(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.

src/compiler/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2925,6 +2925,7 @@ namespace ts {
29252925
allowSyntheticDefaultImports?: boolean;
29262926
allowUnreachableCode?: boolean;
29272927
allowUnusedLabels?: boolean;
2928+
alwaysStrict?: boolean;
29282929
baseUrl?: string;
29292930
charset?: string;
29302931
/* @internal */ configFilePath?: string;

src/harness/unittests/transpile.ts

Lines changed: 4 additions & 0 deletions
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
});
Lines changed: 10 additions & 0 deletions
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+
}
Lines changed: 11 additions & 0 deletions
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+
}

0 commit comments

Comments
 (0)