From 5198c95857998edda9051275ffb2eda91591b4af Mon Sep 17 00:00:00 2001 From: Rajiv Ram V Date: Wed, 19 Jun 2019 08:38:59 +0530 Subject: [PATCH] work in progress --- README.MD | 17 +- api-service/package.json | 4 +- .../cpp/binary-search.cpp | 0 .../{analyzers => linters}/cpp/cpplint/README | 0 .../cpp/cpplint/cpplint.py | 0 .../cpp/cpplint/cpplint_test_header.h | 0 .../cpp/cpplint/cpplint_unittest.py | 0 .../cpp/cpplint/nested/cpplint_test_header.h | 0 .../src/{analyzers => linters}/index.ts | 10 +- .../java/ComplexNumber.java | 0 .../java/checkstyle-8.21-all.jar | Bin .../java/google_checks.xml | 0 api-service/src/routes.ts | 8 +- app/.env | 2 + app/package-lock.json | 153 ++++++++++++++++-- app/package.json | 8 +- app/src/App.css | 42 ++--- app/src/App.tsx | 110 ++++++++++--- app/src/api.ts | 42 +++++ app/src/index.css | 1 + app/src/samples.ts | 72 +++++++++ app/tslint.json | 12 ++ 22 files changed, 401 insertions(+), 80 deletions(-) rename api-service/src/{analyzers => linters}/cpp/binary-search.cpp (100%) rename api-service/src/{analyzers => linters}/cpp/cpplint/README (100%) rename api-service/src/{analyzers => linters}/cpp/cpplint/cpplint.py (100%) rename api-service/src/{analyzers => linters}/cpp/cpplint/cpplint_test_header.h (100%) rename api-service/src/{analyzers => linters}/cpp/cpplint/cpplint_unittest.py (100%) rename api-service/src/{analyzers => linters}/cpp/cpplint/nested/cpplint_test_header.h (100%) rename api-service/src/{analyzers => linters}/index.ts (90%) rename api-service/src/{analyzers => linters}/java/ComplexNumber.java (100%) rename api-service/src/{analyzers => linters}/java/checkstyle-8.21-all.jar (100%) rename api-service/src/{analyzers => linters}/java/google_checks.xml (100%) create mode 100644 app/.env create mode 100644 app/src/api.ts create mode 100644 app/src/samples.ts create mode 100644 app/tslint.json diff --git a/README.MD b/README.MD index cb9fbf2..9a7750a 100644 --- a/README.MD +++ b/README.MD @@ -1,2 +1,17 @@ +# Simple Linter +This utility lints source code to verify if it conforms to [Google's Style Guide](https://github.com/google/styleguide). It uses [checkstyle](https://checkstyle.org/index.html) and [cpplint](https://github.com/google/styleguide/tree/gh-pages/cpplint) for the linting. Currently implemented languages: Java, C++. + +### Dependencies +1. Node.js >= v10.11.3 +2. Python >= v3.5 +3. Java & JRE + ### Installation -1. Install java and jre from deb package openjdk-9-jre-headless. Use command `sudo apt-get install openjdk-9-jre-headless` +1. Install Node.js >= v10.11.3 using [node version manager](https://github.com/nvm-sh/nvm#install--update-script). +2. Install java and jre from deb package openjdk-9-jre-headless or any other suitable version. Use command `sudo apt-get install openjdk-9-jre-headless`. +3. [Download](https://www.python.org/downloads/) and install Python >= v3.5. +4. Clone the repository and run `npm install` inside `api-service` and `app`. +5. Start the Api service by running `npm run dev` inside `api-service`. +6. Start the App by running `npm start` inside `app`. + + diff --git a/api-service/package.json b/api-service/package.json index 6e2b80e..6119bf9 100644 --- a/api-service/package.json +++ b/api-service/package.json @@ -1,7 +1,7 @@ { "name": "api-service", "version": "0.1.0", - "description": "Backend for code analyzer", + "description": "Backend for code linter", "main": "dist", "scripts": { "build": "tsc", @@ -11,7 +11,7 @@ }, "keywords": [ "Code", - "analyzer", + "linter", "backend" ], "author": "Rajiv Ram V ", diff --git a/api-service/src/analyzers/cpp/binary-search.cpp b/api-service/src/linters/cpp/binary-search.cpp similarity index 100% rename from api-service/src/analyzers/cpp/binary-search.cpp rename to api-service/src/linters/cpp/binary-search.cpp diff --git a/api-service/src/analyzers/cpp/cpplint/README b/api-service/src/linters/cpp/cpplint/README similarity index 100% rename from api-service/src/analyzers/cpp/cpplint/README rename to api-service/src/linters/cpp/cpplint/README diff --git a/api-service/src/analyzers/cpp/cpplint/cpplint.py b/api-service/src/linters/cpp/cpplint/cpplint.py similarity index 100% rename from api-service/src/analyzers/cpp/cpplint/cpplint.py rename to api-service/src/linters/cpp/cpplint/cpplint.py diff --git a/api-service/src/analyzers/cpp/cpplint/cpplint_test_header.h b/api-service/src/linters/cpp/cpplint/cpplint_test_header.h similarity index 100% rename from api-service/src/analyzers/cpp/cpplint/cpplint_test_header.h rename to api-service/src/linters/cpp/cpplint/cpplint_test_header.h diff --git a/api-service/src/analyzers/cpp/cpplint/cpplint_unittest.py b/api-service/src/linters/cpp/cpplint/cpplint_unittest.py similarity index 100% rename from api-service/src/analyzers/cpp/cpplint/cpplint_unittest.py rename to api-service/src/linters/cpp/cpplint/cpplint_unittest.py diff --git a/api-service/src/analyzers/cpp/cpplint/nested/cpplint_test_header.h b/api-service/src/linters/cpp/cpplint/nested/cpplint_test_header.h similarity index 100% rename from api-service/src/analyzers/cpp/cpplint/nested/cpplint_test_header.h rename to api-service/src/linters/cpp/cpplint/nested/cpplint_test_header.h diff --git a/api-service/src/analyzers/index.ts b/api-service/src/linters/index.ts similarity index 90% rename from api-service/src/analyzers/index.ts rename to api-service/src/linters/index.ts index 6b7bdb3..92c82ed 100644 --- a/api-service/src/analyzers/index.ts +++ b/api-service/src/linters/index.ts @@ -2,18 +2,18 @@ import { spawn } from "child_process"; import { writeFile } from "fs"; import tmp from "tmp"; -export interface IAnalyzeRequest { +export interface ILintRequest { code: string; lang: string; } -export interface IAnalyzeResult { +export interface ILintResult { lang: "cpp" | "java"; errors: string; completed: string; } -export const analyze = (job: IAnalyzeRequest): Promise => { +export const lint = (job: ILintRequest): Promise => { return new Promise((resolve, reject) => { switch (job.lang) { case "cpp": @@ -73,3 +73,7 @@ export const analyze = (job: IAnalyzeRequest): Promise => { } }); }; + +// const detectLanguage = (code: string): Promise => { + +// } \ No newline at end of file diff --git a/api-service/src/analyzers/java/ComplexNumber.java b/api-service/src/linters/java/ComplexNumber.java similarity index 100% rename from api-service/src/analyzers/java/ComplexNumber.java rename to api-service/src/linters/java/ComplexNumber.java diff --git a/api-service/src/analyzers/java/checkstyle-8.21-all.jar b/api-service/src/linters/java/checkstyle-8.21-all.jar similarity index 100% rename from api-service/src/analyzers/java/checkstyle-8.21-all.jar rename to api-service/src/linters/java/checkstyle-8.21-all.jar diff --git a/api-service/src/analyzers/java/google_checks.xml b/api-service/src/linters/java/google_checks.xml similarity index 100% rename from api-service/src/analyzers/java/google_checks.xml rename to api-service/src/linters/java/google_checks.xml diff --git a/api-service/src/routes.ts b/api-service/src/routes.ts index 0ea2fdb..3259e8a 100644 --- a/api-service/src/routes.ts +++ b/api-service/src/routes.ts @@ -1,16 +1,16 @@ import { Context } from "koa"; import Router from "koa-router"; -import { analyze, IAnalyzeRequest } from "./analyzers"; +import { ILintRequest, lint } from "./linters"; const router = new Router(); router.get("/test", async (ctx: Context) => { ctx.body = "Hello World!"; }); -router.post("/analyze", async (ctx: Context) => { - const job = ctx.request.body as IAnalyzeRequest; - const result = await analyze(job); +router.post("/lint", async (ctx: Context) => { + const job = ctx.request.body as ILintRequest; + const result = await lint(job); ctx.body = result; }); diff --git a/app/.env b/app/.env new file mode 100644 index 0000000..8074697 --- /dev/null +++ b/app/.env @@ -0,0 +1,2 @@ +PORT=4000 +REACT_APP_API_URI=http://localhost:3000 \ No newline at end of file diff --git a/app/package-lock.json b/app/package-lock.json index f0877aa..3400b23 100644 --- a/app/package-lock.json +++ b/app/package-lock.json @@ -765,6 +765,22 @@ "regexpu-core": "^4.5.4" } }, + "@babel/polyfill": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/polyfill/-/polyfill-7.4.4.tgz", + "integrity": "sha512-WlthFLfhQQhh+A2Gn5NSFl0Huxz36x86Jn+E9OW7ibK8edKPq+KLy4apM1yDpQ8kJOVi1OVjpP4vSDLdrI04dg==", + "requires": { + "core-js": "^2.6.5", + "regenerator-runtime": "^0.13.2" + }, + "dependencies": { + "core-js": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.9.tgz", + "integrity": "sha512-HOpZf6eXmnl7la+cUdMnLvUxKNqLUzJvgIziQ0DiF3JwSImNphIqdGqzj6hIKyX04MmV0poclQ7+wjWvxQyR2A==" + } + } + }, "@babel/preset-env": { "version": "7.4.5", "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.4.5.tgz", @@ -1382,6 +1398,12 @@ "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-1.0.1.tgz", "integrity": "sha512-l42BggppR6zLmpfU6fq9HEa2oGPEI8yrSPL3GITjfRInppYFahObbIQOQK3UGxEnyQpltZLaPe75046NOZQikw==" }, + "@types/underscore": { + "version": "1.8.20", + "resolved": "https://registry.npmjs.org/@types/underscore/-/underscore-1.8.20.tgz", + "integrity": "sha512-J/f05EqP41VFuJQdDXE9YhzyQngjKm0/WRGBUyaoobBagBFXk9JCNlpc9V8kF10On/jQ6mkHNqHT13/ZvngOaA==", + "dev": true + }, "@types/unist": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.3.tgz", @@ -2431,6 +2453,11 @@ "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=" }, + "brace": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/brace/-/brace-0.11.1.tgz", + "integrity": "sha1-SJb8ydVE7vRfS7dmDbMg07N5/lg=" + }, "brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -2600,6 +2627,11 @@ "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", "integrity": "sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk=" }, + "builtin-modules": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", + "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=" + }, "builtin-status-codes": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz", @@ -2777,7 +2809,8 @@ }, "ansi-regex": { "version": "2.1.1", - "bundled": true + "bundled": true, + "optional": true }, "aproba": { "version": "1.2.0", @@ -2795,11 +2828,13 @@ }, "balanced-match": { "version": "1.0.0", - "bundled": true + "bundled": true, + "optional": true }, "brace-expansion": { "version": "1.1.11", "bundled": true, + "optional": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -2812,15 +2847,18 @@ }, "code-point-at": { "version": "1.1.0", - "bundled": true + "bundled": true, + "optional": true }, "concat-map": { "version": "0.0.1", - "bundled": true + "bundled": true, + "optional": true }, "console-control-strings": { "version": "1.1.0", - "bundled": true + "bundled": true, + "optional": true }, "core-util-is": { "version": "1.0.2", @@ -2923,7 +2961,8 @@ }, "inherits": { "version": "2.0.3", - "bundled": true + "bundled": true, + "optional": true }, "ini": { "version": "1.3.5", @@ -2933,6 +2972,7 @@ "is-fullwidth-code-point": { "version": "1.0.0", "bundled": true, + "optional": true, "requires": { "number-is-nan": "^1.0.0" } @@ -2945,17 +2985,20 @@ "minimatch": { "version": "3.0.4", "bundled": true, + "optional": true, "requires": { "brace-expansion": "^1.1.7" } }, "minimist": { "version": "0.0.8", - "bundled": true + "bundled": true, + "optional": true }, "minipass": { "version": "2.3.5", "bundled": true, + "optional": true, "requires": { "safe-buffer": "^5.1.2", "yallist": "^3.0.0" @@ -2972,6 +3015,7 @@ "mkdirp": { "version": "0.5.1", "bundled": true, + "optional": true, "requires": { "minimist": "0.0.8" } @@ -3044,7 +3088,8 @@ }, "number-is-nan": { "version": "1.0.1", - "bundled": true + "bundled": true, + "optional": true }, "object-assign": { "version": "4.1.1", @@ -3054,6 +3099,7 @@ "once": { "version": "1.4.0", "bundled": true, + "optional": true, "requires": { "wrappy": "1" } @@ -3129,7 +3175,8 @@ }, "safe-buffer": { "version": "5.1.2", - "bundled": true + "bundled": true, + "optional": true }, "safer-buffer": { "version": "2.1.2", @@ -3159,6 +3206,7 @@ "string-width": { "version": "1.0.2", "bundled": true, + "optional": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -3176,6 +3224,7 @@ "strip-ansi": { "version": "3.0.1", "bundled": true, + "optional": true, "requires": { "ansi-regex": "^2.0.0" } @@ -3214,11 +3263,13 @@ }, "wrappy": { "version": "1.0.2", - "bundled": true + "bundled": true, + "optional": true }, "yallist": { "version": "3.0.3", - "bundled": true + "bundled": true, + "optional": true } } }, @@ -4127,6 +4178,16 @@ } } }, + "diff": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", + "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==" + }, + "diff-match-patch": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/diff-match-patch/-/diff-match-patch-1.0.4.tgz", + "integrity": "sha512-Uv3SW8bmH9nAtHKaKSanOQmj2DnlH65fUpcrMdfdaOxUG02QQ4YGZ8AE7kKOMisF7UqvOlGKVYWRvezdncW9lg==" + }, "diff-sequences": { "version": "24.3.0", "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-24.3.0.tgz", @@ -6661,11 +6722,13 @@ }, "balanced-match": { "version": "1.0.0", - "bundled": true + "bundled": true, + "optional": true }, "brace-expansion": { "version": "1.1.11", "bundled": true, + "optional": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -6682,7 +6745,8 @@ }, "concat-map": { "version": "0.0.1", - "bundled": true + "bundled": true, + "optional": true }, "console-control-strings": { "version": "1.1.0", @@ -7738,6 +7802,16 @@ "resolved": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz", "integrity": "sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0=" }, + "lodash.get": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", + "integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=" + }, + "lodash.isequal": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", + "integrity": "sha1-QVxEePK8wwEgwizhDtMib30+GOA=" + }, "lodash.memoize": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", @@ -9953,6 +10027,19 @@ "scheduler": "^0.13.6" } }, + "react-ace": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/react-ace/-/react-ace-7.0.2.tgz", + "integrity": "sha512-+TFuO1nO6dme/q+qEHjb7iOuWI8jRDzeALs9JyH8HoyHb9+A2bC8WHuJyNU3pmPo8623bytgAgzEJAzDMkzjlw==", + "requires": { + "@babel/polyfill": "^7.4.4", + "brace": "^0.11.1", + "diff-match-patch": "^1.0.4", + "lodash.get": "^4.4.2", + "lodash.isequal": "^4.5.0", + "prop-types": "^15.7.2" + } + }, "react-app-polyfill": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/react-app-polyfill/-/react-app-polyfill-1.0.1.tgz", @@ -11648,6 +11735,41 @@ "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz", "integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==" }, + "tslint": { + "version": "5.17.0", + "resolved": "https://registry.npmjs.org/tslint/-/tslint-5.17.0.tgz", + "integrity": "sha512-pflx87WfVoYepTet3xLfDOLDm9Jqi61UXIKePOuca0qoAZyrGWonDG9VTbji58Fy+8gciUn8Bt7y69+KEVjc/w==", + "requires": { + "@babel/code-frame": "^7.0.0", + "builtin-modules": "^1.1.1", + "chalk": "^2.3.0", + "commander": "^2.12.1", + "diff": "^3.2.0", + "glob": "^7.1.1", + "js-yaml": "^3.13.1", + "minimatch": "^3.0.4", + "mkdirp": "^0.5.1", + "resolve": "^1.3.2", + "semver": "^5.3.0", + "tslib": "^1.8.0", + "tsutils": "^2.29.0" + }, + "dependencies": { + "semver": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz", + "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==" + }, + "tsutils": { + "version": "2.29.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.29.0.tgz", + "integrity": "sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA==", + "requires": { + "tslib": "^1.8.1" + } + } + } + }, "tsutils": { "version": "3.14.0", "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.14.0.tgz", @@ -11722,6 +11844,11 @@ } } }, + "underscore": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.9.1.tgz", + "integrity": "sha512-5/4etnCkd9c8gwgowi5/om/mYO5ajCaOgdzj/oW+0eQV9WxKBDZw5+ycmKmeaTXjInS/W0BzpGLo2xR2aBwZdg==" + }, "unicode-canonical-property-names-ecmascript": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz", diff --git a/app/package.json b/app/package.json index e222b29..eb1bda7 100644 --- a/app/package.json +++ b/app/package.json @@ -8,9 +8,12 @@ "@types/react": "16.8.20", "@types/react-dom": "16.8.4", "react": "^16.8.6", + "react-ace": "^7.0.2", "react-dom": "^16.8.6", "react-scripts": "3.0.1", - "typescript": "3.5.2" + "tslint": "^5.17.0", + "typescript": "3.5.2", + "underscore": "^1.9.1" }, "scripts": { "start": "react-scripts start", @@ -32,5 +35,8 @@ "last 1 firefox version", "last 1 safari version" ] + }, + "devDependencies": { + "@types/underscore": "^1.8.20" } } diff --git a/app/src/App.css b/app/src/App.css index b41d297..9d3aef5 100644 --- a/app/src/App.css +++ b/app/src/App.css @@ -1,33 +1,9 @@ -.App { - text-align: center; -} - -.App-logo { - animation: App-logo-spin infinite 20s linear; - height: 40vmin; - pointer-events: none; -} - -.App-header { - background-color: #282c34; - min-height: 100vh; - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - font-size: calc(10px + 2vmin); - color: white; -} - -.App-link { - color: #61dafb; -} - -@keyframes App-logo-spin { - from { - transform: rotate(0deg); - } - to { - transform: rotate(360deg); - } -} +#code-linter-container { + background-color: "red"; + width: "calc(100vw - 16px)"; + height: "100%"; +} +.error { + color: red; + font-size: 10px; +} \ No newline at end of file diff --git a/app/src/App.tsx b/app/src/App.tsx index 226ee63..8ba41d8 100644 --- a/app/src/App.tsx +++ b/app/src/App.tsx @@ -1,26 +1,90 @@ -import React from 'react'; -import logo from './logo.svg'; -import './App.css'; - -const App: React.FC = () => { - return ( -
-
- logo -

- Edit src/App.tsx and save to reload. -

- - Learn React - -
-
- ); +import React, { Component, Fragment, ChangeEvent } from 'react'; +import AceEditor from "react-ace"; +import { sampleCppProgram, sampleJavaProgram } from "./samples"; +import { getLintResults } from "./api"; +import "./App.css"; + +import "brace/mode/java"; +import "brace/mode/c_cpp"; +import "brace/theme/monokai"; + +export interface IAnnotation { + row: number; + column: number; + type: string; + text: string; +} + +interface IAppState { + lang: string; + annotations: IAnnotation[]; + code: string; + hasSyntacticErrors: boolean; +} + +class App extends Component<{}, IAppState> { + state = { + lang: "", + annotations: [], + code: "", + hasSyntacticErrors: false + } + + setJavaCode = () => { + this.setState({ code: sampleJavaProgram, lang: "java", annotations: [], hasSyntacticErrors: false }) + } + + setCppCode = () => { + this.setState({ code: sampleCppProgram, lang: "cpp", annotations: [], hasSyntacticErrors: false }) + } + + setLanguage = (e: ChangeEvent) => { + this.setState({ lang: e.target.value }) + } + + componentDidUpdate = (prevProps: {}, prevState: IAppState) => { + if (prevState.code !== this.state.code || prevState.lang !== this.state.lang) { + this.refreshLint() + } + } + + refreshLint = async () => { + try { + const annotations = await getLintResults(this.state.code, this.state.lang); + this.setState({ annotations, hasSyntacticErrors: false }); + } catch(e) { + this.setState({ hasSyntacticErrors: true }) + } + } + + onCodeChange = async (value: string) => { + this.setState({ code: value }) + this.refreshLint() + } + + render = () => ( + +

Simple Linter

+

This utility lints source code to verify if it conforms Google's Style Guide. It uses checkstyle and cpplint for the linting. Currently implemented languages: Java, C++

+

Add sample code:

+

Language:

+ {this.state.hasSyntacticErrors &&

There are syntax errors! Please correct them.

} +
+ +
+
+ ) } + export default App; diff --git a/app/src/api.ts b/app/src/api.ts new file mode 100644 index 0000000..6b360c1 --- /dev/null +++ b/app/src/api.ts @@ -0,0 +1,42 @@ +import { debounce } from "underscore"; +import { IAnnotation } from "./App"; +const CPP_ERROR_REGEX = /^[a-zA-Z0-9/\-.]+.cpp:([0-9]+): (.*)/; + +const _getLintResults = (code: string, lang: string): Promise => { + const options = { + method: 'post', + headers: { + 'Content-type': 'application/x-www-form-urlencoded; charset=UTF-8' + }, + body: `code=${encodeURI(code)}&lang=${lang}` + } + return new Promise((resolve, reject) => { + fetch(`${process.env.REACT_APP_API_URI}/lint`, options).then((res) => { + res.json().then(json => { + switch(json.lang) { + case "cpp": + const errors = json.errors.split("\n").filter((line: string) => line.length !== 0).map((line: string) => { + const match = line.match(CPP_ERROR_REGEX); + if (match != null) { + return { row: Number(match[1]) - 1, column: 0, type: "error", text: match[2] } + } else return {} + }); + resolve(errors); + break; + case "java": + if (json.errors.length > 0) + reject("There are syntactic errors"); + console.log(json) + break; + + } + + }) + }).catch(err => { + reject(err) + }) + }) + +} + +export const getLintResults = debounce(_getLintResults, 100, true); \ No newline at end of file diff --git a/app/src/index.css b/app/src/index.css index ec2585e..8270034 100644 --- a/app/src/index.css +++ b/app/src/index.css @@ -5,6 +5,7 @@ body { sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; + padding: 8px; } code { diff --git a/app/src/samples.ts b/app/src/samples.ts new file mode 100644 index 0000000..c5f3d2c --- /dev/null +++ b/app/src/samples.ts @@ -0,0 +1,72 @@ +export const sampleCppProgram = `#include +using namespace std; + +int main() +{ + int count, i, arr[30], num, first, last, middle; + cout<<"how many elements would you like to enter?:"; + cin>>count; + + for (i=0; i>arr[i]; + } + cout<<"Enter the number that you want to search:"; + cin>>num; + first = 0; + last = count-1; + middle = (first+last)/2; + while (first <= last) + { + if(arr[middle] < num) + { + first = middle + 1; + + } + else if(arr[middle] == num) + { + cout< last) + { + cout<