diff --git a/Dockerfile b/Dockerfile deleted file mode 100644 index cb632d6..0000000 --- a/Dockerfile +++ /dev/null @@ -1,4 +0,0 @@ -FROM node:6.14 -MAINTAINER Federico Scarpa - -RUN npm install -g mocha@5.2.0 chai diff --git a/Gemfile b/Gemfile index fa75df1..15ec89f 100644 --- a/Gemfile +++ b/Gemfile @@ -1,3 +1,5 @@ source 'https://rubygems.org' gemspec + +gem 'mumukit-inspection', github: 'mumuki/mumukit-inspection', branch: 'feature-eslint-warnings' diff --git a/lib/expectations_hook.rb b/lib/expectations_hook.rb index 838c02d..c7961d9 100644 --- a/lib/expectations_hook.rb +++ b/lib/expectations_hook.rb @@ -1,6 +1,35 @@ class JavascriptExpectationsHook < Mumukit::Templates::MulangExpectationsHook include_smells true + ESLINT_RULES = { + 'semi' => 'JavaScript#LacksOfEndingSemicolon' + }.freeze + + def run!(spec) + super(spec) + run_eslint(spec[:request][:content]) + end + + def run_eslint(content) + lines = content.lines.map(&:rstrip) + out, status = Open3.capture2("eslint --format json --stdin", stdin_data: content) + result = JSON.parse(out)[0] + + if result["fatalErrorCount"] == 0 + result["messages"].map do |it| + { + expectation: { + binding: lines[it["line"] - 1], + inspection: ESLINT_RULES[it["ruleId"]] + }, + result: false + } + end + else + [] + end + + end + def language 'JavaScript' end diff --git a/lib/javascript_runner.rb b/lib/javascript_runner.rb index fff55a5..23edbbe 100644 --- a/lib/javascript_runner.rb +++ b/lib/javascript_runner.rb @@ -4,7 +4,7 @@ Mumukit.runner_name = 'javascript' Mumukit.configure do |config| - config.docker_image = 'mumuki/mumuki-mocha-worker:2.0' + config.docker_image = 'mumuki/mumuki-mocha-worker:2.1' config.structured = true config.stateful = true config.content_type = 'markdown' @@ -18,3 +18,5 @@ require_relative './feedback_hook' require_relative './query_hook' require_relative './try_hook' + +Mulang::Inspection.register_extension! Mumukit::Inspection::JavaScript diff --git a/mumuki-javascript-runner.gemspec b/mumuki-javascript-runner.gemspec index ca953a8..4e09823 100644 --- a/mumuki-javascript-runner.gemspec +++ b/mumuki-javascript-runner.gemspec @@ -18,6 +18,7 @@ Gem::Specification.new do |spec| spec.require_paths = ['lib'] spec.add_dependency 'mumukit', '~> 2.40' + spec.add_dependency 'mumukit-inspection', '~> 6.0' spec.add_development_dependency 'bundler', '~> 2.0' spec.add_development_dependency 'rake', '~> 10.0' diff --git a/spec/expectations_spec.rb b/spec/expectations_spec.rb index 3c5d04f..074e7b3 100644 --- a/spec/expectations_spec.rb +++ b/spec/expectations_spec.rb @@ -11,6 +11,7 @@ def compile_and_run(request) let(:runner) { JavascriptExpectationsHook.new } let(:result) { compile_and_run(req(expectations, code)) } + let(:translations) { result.select { |it| !it[:result] }.map { |it| Mulang::Expectation.parse(it[:expectation]).translate } } describe 'HasTooShortIdentifiers' do let(:code) { "function f(x) { retun g(x); }" } @@ -20,7 +21,7 @@ def compile_and_run(request) end describe 'HasWrongCaseIdentifiers' do - let(:code) { "function a_function_with_bad_case() { return 3 }" } + let(:code) { "function a_function_with_bad_case() { return 3; }" } let(:expectations) { [] } it { expect(result).to eq [{expectation: {binding: 'a_function_with_bad_case', inspection: 'HasWrongCaseIdentifiers'}, result: false}] } @@ -86,4 +87,20 @@ def compile_and_run(request) {expectation: expectations[2], result: false}] } end + describe "eslint smells" do + let(:expectations) { [] } + + describe 'JavaScript#LacksOfEndingSemicolon' do + let(:code) { "let variable1 = 1\nlet variable2 = 2;\nlet variable3 = 3" } + + it { expect(result).to eq [ + {expectation: {binding: "let variable1 = 1", inspection: 'JavaScript#LacksOfEndingSemicolon'}, result: false}, + {expectation: {binding: 'let variable3 = 3', inspection: 'JavaScript#LacksOfEndingSemicolon'}, result: false}] } + it { expect(translations).to eq [ + "the following line should end with ;:
let variable1 = 1
", + "the following line should end with ;:
let variable3 = 3
" + ] } + end + end + end diff --git a/spec/integration_spec.rb b/spec/integration_spec.rb index 8fd5870..59d74aa 100644 --- a/spec/integration_spec.rb +++ b/spec/integration_spec.rb @@ -36,7 +36,7 @@ it 'answers a valid hash when submission is ok' do response = bridge.run_tests!(test: 'describe("foo", () => it("bar", () => assert.equal(aVariable, 3)))', extra: '', - content: 'let aVariable = 3', + content: 'let aVariable = 3;', expectations: []) expect(response).to eq(response_type: :structured, @@ -50,7 +50,7 @@ it 'answers a valid hash when submission is ok but has part of blacklisted words' do response = bridge.run_tests!(test: 'describe("foos", () => it("bar", () => assert.equal(aVariable, 3)))', extra: 'let flos = 75;', - content: 'let aVariable = 3', + content: 'let aVariable = 3;', expectations: []) expect(response).to eq(response_type: :structured, @@ -64,7 +64,7 @@ it 'answers a valid hash when submission is ok with warnings' do response = bridge.run_tests!(test: 'describe("foo", () => it("bar", () => assert.equal(x, 3)))', extra: '', - content: 'let x = 3', + content: 'let x = 3;', expectations: []) expect(response).to eq(response_type: :structured, @@ -78,7 +78,7 @@ it 'answers a valid hash when submission is ok with JS-specific warnings' do response = bridge.run_tests!(test: 'describe("foo", () => it("bar", () => assert.equal(something, 3)))', extra: '', - content: 'var something = 3', + content: 'var something = 3;', expectations: []) expect(response).to eq(response_type: :structured, @@ -93,7 +93,7 @@ response = bridge. run_tests!(test: 'describe("foo", () => it("bar", () => assert.equal(aVariable, 3)))', extra: '', - content: 'let aVariable = 2', + content: 'let aVariable = 2;', expectations: []) expect(response).to eq(response_type: :structured, @@ -109,7 +109,7 @@ response = bridge. run_tests!(test: 'describe("foo", () => it("bar", function (done) { this.timeout(5000); setTimeout(() => { assert.equal(x, 3); done() }, 5000) }))', extra: '', - content: 'let x = 2', + content: 'let x = 2;', expectations: []) expect(response).to eq(response_type: :unstructured, @@ -138,7 +138,7 @@ it 'answers a valid hash when given a known locale' do response = bridge.run_tests!(test: 'describe("foo", () => it("bar", () => assert.equal(aVariable, 4)))', extra: '', - content: 'let aVariable = 3', + content: 'let aVariable = 3;', expectations: [], locale: 'pt') @@ -164,7 +164,7 @@ }); }, extra: '', - content: 'function average(list) { return sum(list) / list.length }', + content: 'function average(list) { return sum(list) / list.length; }', expectations: []) expect(response).to eq(response_type: :structured, @@ -194,9 +194,9 @@ }, extra: '', content: %q{ - function resumenLector(quien) { - return quien.nombre + " se suscribió hace " + (2020 - quien.anioSuscripcion) + " años"; - }}, +function resumenLector(quien) { + return quien.nombre + " se suscribió hace " + (2020 - quien.anioSuscripcion) + " años"; +}}, expectations: []) expect(response).to eq(response_type: :structured, @@ -244,9 +244,9 @@ }, extra: 'function longitud(unStringOLista) { return unStringOLista.length;}', content: %q{ - function resumenSuscripcion(registro) { - return registro.nombre + " " + "se suscribio hace " + ( 2020 - registro.anioSuscripcion) + " " + "años" + " " + "y leyo " + " " + longitud(registro.librosLeidos) + " " + "libros"; - }}, +function resumenSuscripcion(registro) { + return registro.nombre + " " + "se suscribio hace " + ( 2020 - registro.anioSuscripcion) + " " + "años" + " " + "y leyo " + " " + longitud(registro.librosLeidos) + " " + "libros"; +}}, expectations: []) expect(response).to eq(response_type: :structured, diff --git a/worker/.eslintrc.yml b/worker/.eslintrc.yml new file mode 100644 index 0000000..58b9018 --- /dev/null +++ b/worker/.eslintrc.yml @@ -0,0 +1,9 @@ +env: + browser: true + es2021: true +parserOptions: + ecmaVersion: 12 +rules: + semi: + - error + - always diff --git a/worker/Dockerfile b/worker/Dockerfile new file mode 100644 index 0000000..c3ce7dd --- /dev/null +++ b/worker/Dockerfile @@ -0,0 +1,5 @@ +FROM node:6.14 +MAINTAINER Federico Scarpa + +COPY .eslintrc.yml .eslintrc.yml +RUN npm install -g mocha@5.2.0 chai@4.3.4 eslint@7.32.0