Skip to content
Merged
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
15 changes: 13 additions & 2 deletions src/compiler/binder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,8 @@ namespace ts {

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

let symbolCount = 0;
Expand All @@ -139,7 +140,7 @@ namespace ts {
file = f;
options = opts;
languageVersion = getEmitScriptTarget(options);
inStrictMode = !!file.externalModuleIndicator;
inStrictMode = bindInStrictMode(file, opts);
classifiableNames = createMap<string>();
symbolCount = 0;
skipTransformFlagAggregation = isDeclarationFile(file);
Expand Down Expand Up @@ -174,6 +175,16 @@ namespace ts {

return bindSourceFile;

function bindInStrictMode(file: SourceFile, opts: CompilerOptions): boolean {
if (opts.alwaysStrict && !isDeclarationFile(file)) {
// bind in strict mode source files with alwaysStrict option
return true;
}
else {
return !!file.externalModuleIndicator;
}
}

function createSymbol(flags: SymbolFlags, name: string): Symbol {
symbolCount++;
return new Symbol(flags, name);
Expand Down
5 changes: 5 additions & 0 deletions src/compiler/commandLineParser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -444,6 +444,11 @@ namespace ts {
name: "importHelpers",
type: "boolean",
description: Diagnostics.Import_emit_helpers_from_tslib
},
{
name: "alwaysStrict",
type: "boolean",
description: Diagnostics.Parse_in_strict_mode_and_emit_use_strict_for_each_source_file
}
];

Expand Down
4 changes: 4 additions & 0 deletions src/compiler/diagnosticMessages.json
Original file line number Diff line number Diff line change
Expand Up @@ -2861,6 +2861,10 @@
"category": "Error",
"code": 6140
},
"Parse in strict mode and emit \"use strict\" for each source file": {
"category": "Message",
"code": 6141
},
"Variable '{0}' implicitly has an '{1}' type.": {
"category": "Error",
"code": 7005
Expand Down
27 changes: 27 additions & 0 deletions src/compiler/factory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2235,6 +2235,33 @@ namespace ts {
return statementOffset;
}

/**
* Ensures "use strict" directive is added
*
* @param node source file
*/
export function ensureUseStrict(node: SourceFile): SourceFile {
let foundUseStrict = false;
for (const statement of node.statements) {
if (isPrologueDirective(statement)) {
if (isUseStrictPrologue(statement as ExpressionStatement)) {
foundUseStrict = true;
break;
}
}
else {
break;
}
}
if (!foundUseStrict) {
const statements: Statement[] = [];
statements.push(startOnNewLine(createStatement(createLiteral("use strict"))));
// add "use strict" as the first statement
return updateSourceFileNode(node, statements.concat(node.statements));
}
return node;
}

/**
* Wraps the operand to a BinaryExpression in parentheses if they are needed to preserve the intended
* order of operations.
Expand Down
5 changes: 5 additions & 0 deletions src/compiler/transformers/ts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -436,6 +436,11 @@ namespace ts {
function visitSourceFile(node: SourceFile) {
currentSourceFile = node;

// ensure "use strict" is emitted in all scenarios in alwaysStrict mode
if (compilerOptions.alwaysStrict) {
node = ensureUseStrict(node);
}

// If the source file requires any helpers and is an external module, and
// the importHelpers compiler option is enabled, emit a synthesized import
// statement for the helpers library.
Expand Down
1 change: 1 addition & 0 deletions src/compiler/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2929,6 +2929,7 @@ namespace ts {
allowSyntheticDefaultImports?: boolean;
allowUnreachableCode?: boolean;
allowUnusedLabels?: boolean;
alwaysStrict?: boolean;
baseUrl?: string;
charset?: string;
/* @internal */ configFilePath?: string;
Expand Down
4 changes: 4 additions & 0 deletions src/harness/unittests/transpile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,10 @@ var x = 0;`, {
options: { compilerOptions: { allowUnusedLabels: true }, fileName: "input.js", reportDiagnostics: true }
});

transpilesCorrectly("Supports setting 'alwaysStrict'", "x;", {
options: { compilerOptions: { alwaysStrict: true }, fileName: "input.js", reportDiagnostics: true }
});

transpilesCorrectly("Supports setting 'baseUrl'", "x;", {
options: { compilerOptions: { baseUrl: "./folder/baseUrl" }, fileName: "input.js", reportDiagnostics: true }
});
Expand Down
10 changes: 10 additions & 0 deletions tests/baselines/reference/alwaysStrict.errors.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
tests/cases/compiler/alwaysStrict.ts(3,9): error TS1100: Invalid use of 'arguments' in strict mode.


==== tests/cases/compiler/alwaysStrict.ts (1 errors) ====

function f() {
var arguments = [];
~~~~~~~~~
!!! error TS1100: Invalid use of 'arguments' in strict mode.
}
11 changes: 11 additions & 0 deletions tests/baselines/reference/alwaysStrict.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
//// [alwaysStrict.ts]

function f() {
var arguments = [];
}

//// [alwaysStrict.js]
"use strict";
function f() {
var arguments = [];
}
11 changes: 11 additions & 0 deletions tests/baselines/reference/alwaysStrictAlreadyUseStrict.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
//// [alwaysStrictAlreadyUseStrict.ts]
"use strict"
function f() {
var a = [];
}

//// [alwaysStrictAlreadyUseStrict.js]
"use strict";
function f() {
var a = [];
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
=== tests/cases/compiler/alwaysStrictAlreadyUseStrict.ts ===
"use strict"
function f() {
>f : Symbol(f, Decl(alwaysStrictAlreadyUseStrict.ts, 0, 12))

var a = [];
>a : Symbol(a, Decl(alwaysStrictAlreadyUseStrict.ts, 2, 7))
}
11 changes: 11 additions & 0 deletions tests/baselines/reference/alwaysStrictAlreadyUseStrict.types
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
=== tests/cases/compiler/alwaysStrictAlreadyUseStrict.ts ===
"use strict"
>"use strict" : "use strict"

function f() {
>f : () => void

var a = [];
>a : any[]
>[] : undefined[]
}
10 changes: 10 additions & 0 deletions tests/baselines/reference/alwaysStrictES6.errors.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
tests/cases/compiler/alwaysStrictES6.ts(3,9): error TS1100: Invalid use of 'arguments' in strict mode.


==== tests/cases/compiler/alwaysStrictES6.ts (1 errors) ====

function f() {
var arguments = [];
~~~~~~~~~
!!! error TS1100: Invalid use of 'arguments' in strict mode.
}
11 changes: 11 additions & 0 deletions tests/baselines/reference/alwaysStrictES6.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
//// [alwaysStrictES6.ts]

function f() {
var arguments = [];
}

//// [alwaysStrictES6.js]
"use strict";
function f() {
var arguments = [];
}
12 changes: 12 additions & 0 deletions tests/baselines/reference/alwaysStrictModule.errors.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
tests/cases/compiler/alwaysStrictModule.ts(4,13): error TS1100: Invalid use of 'arguments' in strict mode.


==== tests/cases/compiler/alwaysStrictModule.ts (1 errors) ====

module M {
export function f() {
var arguments = [];
~~~~~~~~~
!!! error TS1100: Invalid use of 'arguments' in strict mode.
}
}
17 changes: 17 additions & 0 deletions tests/baselines/reference/alwaysStrictModule.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
//// [alwaysStrictModule.ts]

module M {
export function f() {
var arguments = [];
}
}

//// [alwaysStrictModule.js]
"use strict";
var M;
(function (M) {
function f() {
var arguments = [];
}
M.f = f;
})(M || (M = {}));
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
tests/cases/compiler/alwaysStrictNoImplicitUseStrict.ts(4,13): error TS1100: Invalid use of 'arguments' in strict mode.


==== tests/cases/compiler/alwaysStrictNoImplicitUseStrict.ts (1 errors) ====

module M {
export function f() {
var arguments = [];
~~~~~~~~~
!!! error TS1100: Invalid use of 'arguments' in strict mode.
}
}
17 changes: 17 additions & 0 deletions tests/baselines/reference/alwaysStrictNoImplicitUseStrict.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
//// [alwaysStrictNoImplicitUseStrict.ts]

module M {
export function f() {
var arguments = [];
}
}

//// [alwaysStrictNoImplicitUseStrict.js]
"use strict";

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

alwaysStrict overrides noImplicitUseStrict

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Can you add a check in program.ts::verifyCompilerOptions to flag teh use of --noImplicitUseStrict and --alwaysStrict as invalid combination.. so somthing like

if (options.noImplicitUseStrict && options.alwaysStrict) {
    programDiagnostics.add(createCompilerDiagnostic(Diagnostics.Option_0_cannot_be_specified_with_option_1, "noImplicitUseStrict ", "alwaysStrict"));
}

var M;
(function (M) {
function f() {
var arguments = [];
}
M.f = f;
})(M || (M = {}));

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

5 changes: 5 additions & 0 deletions tests/cases/compiler/alwaysStrict.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
// @alwaysStrict: true

function f() {
var arguments = [];
}
5 changes: 5 additions & 0 deletions tests/cases/compiler/alwaysStrictAlreadyUseStrict.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
// @alwaysStrict: true
"use strict"
function f() {
var a = [];
}
6 changes: 6 additions & 0 deletions tests/cases/compiler/alwaysStrictES6.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// @target: ES6
// @alwaysStrict: true

function f() {
var arguments = [];
}
8 changes: 8 additions & 0 deletions tests/cases/compiler/alwaysStrictModule.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// @module: commonjs
// @alwaysStrict: true

module M {
export function f() {
var arguments = [];
}
}
9 changes: 9 additions & 0 deletions tests/cases/compiler/alwaysStrictNoImplicitUseStrict.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// @module: commonjs
// @alwaysStrict: true
// @noImplicitUseStrict: true

module M {
export function f() {
var arguments = [];
}
}