diff --git a/README.md b/README.md
index af9ea5e..4460bb3 100644
--- a/README.md
+++ b/README.md
@@ -78,6 +78,7 @@ This guarantees 100% compatibility between the plugin and the parser.
| [`typescript/no-non-null-assertion`](./docs/rules/no-non-null-assertion.md) | Disallows non-null assertions using the `!` postfix operator (`no-non-null-assertion` from TSLint) | | |
| [`typescript/no-object-literal-type-assertion`](./docs/rules/no-object-literal-type-assertion.md) | Forbids an object literal to appear in a type assertion expression (`no-object-literal-type-assertion` from TSLint) | | |
| [`typescript/no-parameter-properties`](./docs/rules/no-parameter-properties.md) | Disallow the use of parameter properties in class constructors. (`no-parameter-properties` from TSLint) | | |
+| [`typescript/no-semantic-errors`](./docs/rules/no-semantic-errors.md) | Enforces that there is no semantic and syntactic errors | | |
| [`typescript/no-this-alias`](./docs/rules/no-this-alias.md) | Disallow aliasing `this` (`no-this-assignment` from TSLint) | | |
| [`typescript/no-triple-slash-reference`](./docs/rules/no-triple-slash-reference.md) | Disallow `/// ` comments (`no-reference` from TSLint) | | |
| [`typescript/no-type-alias`](./docs/rules/no-type-alias.md) | Disallow the use of type aliases (`interface-over-type-literal` from TSLint) | | |
diff --git a/docs/rules/no-semantic-errors.md b/docs/rules/no-semantic-errors.md
new file mode 100644
index 0000000..b531683
--- /dev/null
+++ b/docs/rules/no-semantic-errors.md
@@ -0,0 +1,31 @@
+# Enforces that there is no semantic and syntactic errors (no-semantic-errors)
+
+This rule reports all semantic and type errors provided by diagnostics from typescript.
+
+## Rule Details
+
+Examples of **incorrect** code for this rule:
+
+```ts
+interface Foo {
+ hello: string;
+}
+const foo: string = ({ hello: 2 } as Foo)!.foo;
+```
+
+Examples of **correct** code for this rule:
+
+```ts
+interface Foo {
+ hello: string;
+}
+const foo: string = ({ hello: "Bar" } as Foo).hello;
+```
+
+### Options
+
+```json
+{
+ "typescript/no-this-alias": "no-semantic-errors"
+}
+```
diff --git a/lib/rules/no-semantic-errors.js b/lib/rules/no-semantic-errors.js
new file mode 100644
index 0000000..d77f22a
--- /dev/null
+++ b/lib/rules/no-semantic-errors.js
@@ -0,0 +1,56 @@
+/**
+ * @fileoverview Enforces that there is no semantic and syntactic errors
+ * @author Armano
+ */
+"use strict";
+
+const util = require("../util");
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
+module.exports = {
+ meta: {
+ type: "problem",
+ docs: {
+ description:
+ "Enforces that there is no semantic and syntactic errors",
+ category: "TypeScript",
+ url: util.metaDocsUrl("no-semantic-errors"),
+ },
+ schema: [],
+ },
+
+ create(context) {
+ const sourceCode = context.getSourceCode();
+
+ const program = util.getParserServices(context).program;
+
+ return {
+ Program(node) {
+ const semantic = program.getSemanticDiagnostics() || [];
+ const syntactic = program.getSyntacticDiagnostics() || [];
+
+ const errors = semantic
+ .concat(syntactic)
+ // DiagnosticCategory.Error = 1,
+ .filter(error => error.category === 1);
+
+ for (const error of errors) {
+ const errorNode = error.start
+ ? sourceCode.getNodeByRangeIndex(error.start)
+ : node;
+
+ context.report({
+ node: errorNode,
+ message:
+ typeof error.messageText === "object"
+ ? error.messageText.messageText
+ : error.messageText,
+ });
+ }
+ },
+ };
+ },
+};
diff --git a/lib/util.js b/lib/util.js
index a44369a..d895f4f 100644
--- a/lib/util.js
+++ b/lib/util.js
@@ -15,6 +15,24 @@ exports.metaDocsUrl = name =>
*/
exports.isTypescript = fileName => /\.tsx?$/.test(fileName);
+/**
+ * Try to retrieve typescript parser service from context
+ * @param {RuleContext} context Rule context
+ * @returns {{esTreeNodeToTSNodeMap}|{program}|Object|*} parserServices
+ */
+exports.getParserServices = context => {
+ if (
+ !context.parserServices ||
+ !context.parserServices.program ||
+ !context.parserServices.esTreeNodeToTSNodeMap
+ ) {
+ throw new Error(
+ "This rule requires you to use `typescript-eslint-parser`."
+ );
+ }
+ return context.parserServices;
+};
+
/**
* Pure function - doesn't mutate either parameter!
* Merges two objects together deeply, overwriting the properties in first with the properties in second
diff --git a/package.json b/package.json
index 0370308..2e4673f 100644
--- a/package.json
+++ b/package.json
@@ -24,7 +24,7 @@
},
"dependencies": {
"requireindex": "^1.2.0",
- "typescript-eslint-parser": "21.0.2"
+ "typescript-eslint-parser": "git+https://github.com/uniqueiniquity/typescript-eslint-parser.git#0625f29a9721c6f10a7522de6c9d236a671bd1ac"
},
"devDependencies": {
"eslint": "^5.9.0",
diff --git a/tests/lib/fixtures/empty/empty.ts b/tests/lib/fixtures/empty/empty.ts
new file mode 100644
index 0000000..e69de29
diff --git a/tests/lib/fixtures/empty/import.ts b/tests/lib/fixtures/empty/import.ts
new file mode 100644
index 0000000..115a937
--- /dev/null
+++ b/tests/lib/fixtures/empty/import.ts
@@ -0,0 +1,3 @@
+export default interface Foo {
+ name: string
+}
diff --git a/tests/lib/fixtures/empty/tsconfig.json b/tests/lib/fixtures/empty/tsconfig.json
new file mode 100644
index 0000000..2dd72f8
--- /dev/null
+++ b/tests/lib/fixtures/empty/tsconfig.json
@@ -0,0 +1,9 @@
+{
+ "compilerOptions": {
+ "target": "es5",
+ "module": "commonjs",
+ "strict": true,
+ "esModuleInterop": true,
+ "lib": ["es2015", "es2017"]
+ }
+}
diff --git a/tests/lib/rules/no-semantic-errors.js b/tests/lib/rules/no-semantic-errors.js
new file mode 100644
index 0000000..e49942d
--- /dev/null
+++ b/tests/lib/rules/no-semantic-errors.js
@@ -0,0 +1,132 @@
+/**
+ * @fileoverview Enforces that there is no semantic and syntactic errors
+ * @author Armano
+ */
+"use strict";
+
+//------------------------------------------------------------------------------
+// Requirements
+//------------------------------------------------------------------------------
+const path = require("path");
+
+const rule = require("../../../lib/rules/no-semantic-errors"),
+ RuleTester = require("eslint").RuleTester;
+
+//------------------------------------------------------------------------------
+// Tests
+//------------------------------------------------------------------------------
+
+const rootPath = path.join(process.cwd(), "tests/lib/fixtures/empty");
+// valid filePath is required to get access to lib
+// @see https://github.com/JamesHenry/typescript-estree/issues/50
+const filePath = path.join(rootPath, "empty.ts");
+
+const ruleTester = new RuleTester({
+ parser: "typescript-eslint-parser",
+ parserOptions: {
+ generateServices: true,
+ tsconfigRootDir: rootPath,
+ project: "./tsconfig.json",
+ },
+});
+
+ruleTester.run("no-errors", rule, {
+ valid: [
+ {
+ filename: filePath,
+ code: `
+import Foo from './import';
+var foo: Foo = {
+ name: 'test'
+};
+ `,
+ },
+ {
+ filename: filePath,
+ code: `
+interface Foo {
+ hello: string;
+}
+const foo: string = ({ hello: 'Bar' } as Foo).hello
+ `,
+ },
+ {
+ filename: filePath,
+ code: `var foo: number = parseInt("5.5", 10) + 10;`,
+ },
+ ],
+ invalid: [
+ {
+ filename: filePath,
+ code: `var foo: string = parseInt("5.5", 10) + 10;`,
+ errors: [
+ {
+ message:
+ "Type 'number' is not assignable to type 'string'.",
+ line: 1,
+ column: 5,
+ type: "Identifier",
+ },
+ ],
+ },
+ {
+ filename: filePath,
+ code: `
+import Foo from './import';
+var foo: Foo = {
+ name: 2
+};
+ `,
+ errors: [
+ {
+ message:
+ "Type 'number' is not assignable to type 'string'.",
+ line: 4,
+ column: 5,
+ type: "Identifier",
+ },
+ ],
+ },
+ {
+ filename: filePath,
+ code: `
+import Foo from './not-found';
+var foo: Foo = {
+ name: 2
+};
+ `,
+ errors: [
+ {
+ message: "Cannot find module './not-found'.",
+ line: 2,
+ column: 17,
+ type: "Literal",
+ },
+ ],
+ },
+ {
+ filename: filePath,
+ code: `
+interface Foo {
+ hello: string;
+}
+const foo: string = ({ hello: 2 } as Foo)!.foo
+ `,
+ errors: [
+ {
+ message:
+ "Conversion of type '{ hello: number; }' to type 'Foo' may be a mistake because neither type sufficiently overlaps with the other. If this was intentional, convert the expression to 'unknown' first.",
+ line: 5,
+ column: 22,
+ type: "ObjectExpression",
+ },
+ {
+ message: "Property 'foo' does not exist on type 'Foo'.",
+ line: 5,
+ column: 44,
+ type: "Identifier",
+ },
+ ],
+ },
+ ],
+});
diff --git a/yarn.lock b/yarn.lock
index c9dd2af..94955ee 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -2996,15 +2996,6 @@ typedarray@^0.0.6:
resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"
integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=
-typescript-eslint-parser@21.0.2:
- version "21.0.2"
- resolved "https://registry.yarnpkg.com/typescript-eslint-parser/-/typescript-eslint-parser-21.0.2.tgz#270af10e4724528677fbcf34ea495284bec3a894"
- integrity sha512-u+pj4RVJBr4eTzj0n5npoXD/oRthvfUCjSKndhNI714MG0mQq2DJw5WP7qmonRNIFgmZuvdDOH3BHm9iOjIAfg==
- dependencies:
- eslint-scope "^4.0.0"
- eslint-visitor-keys "^1.0.0"
- typescript-estree "5.3.0"
-
typescript-eslint-parser@^16.0.0:
version "16.0.1"
resolved "https://registry.yarnpkg.com/typescript-eslint-parser/-/typescript-eslint-parser-16.0.1.tgz#b40681c7043b222b9772748b700a000b241c031b"
@@ -3013,6 +3004,14 @@ typescript-eslint-parser@^16.0.0:
lodash.unescape "4.0.1"
semver "5.5.0"
+"typescript-eslint-parser@git+https://github.com/uniqueiniquity/typescript-eslint-parser.git#0625f29a9721c6f10a7522de6c9d236a671bd1ac":
+ version "21.0.2"
+ resolved "git+https://github.com/uniqueiniquity/typescript-eslint-parser.git#0625f29a9721c6f10a7522de6c9d236a671bd1ac"
+ dependencies:
+ eslint-scope "^4.0.0"
+ eslint-visitor-keys "^1.0.0"
+ typescript-estree "5.3.0"
+
typescript-estree@5.3.0:
version "5.3.0"
resolved "https://registry.yarnpkg.com/typescript-estree/-/typescript-estree-5.3.0.tgz#fb6c977b5e21073eb16cbdc0338a7f752da99ff5"