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