diff --git a/app/server/package.json b/app/server/package.json index c63facf0..21dda24d 100644 --- a/app/server/package.json +++ b/app/server/package.json @@ -5,6 +5,7 @@ "scripts": { "start": "cross-env HOT_RELOAD=1 DEBUG=1 webpack-dev-server", "build": "webpack", + "lint": "eslint --max-warnings=0 static/js", "test": "echo \"Error: no test specified\" && exit 1" }, "author": "", diff --git a/app/server/static/js/.eslintrc.js b/app/server/static/js/.eslintrc.js index 060800bd..5456e427 100644 --- a/app/server/static/js/.eslintrc.js +++ b/app/server/static/js/.eslintrc.js @@ -1,4 +1,21 @@ module.exports = { - "extends": "airbnb-base" + env: { + browser: true, + es6: true, + node: true, + }, + parserOptions: { + parser: "babel-eslint", + }, + extends: [ + "airbnb-base", + ], + rules: { + "no-param-reassign": "off", + "no-plusplus": "off", + "object-shorthand": "off", + "prefer-destructuring": "off", + "prefer-template": "off", + }, }; // https://travishorn.com/setting-up-eslint-on-vs-code-with-airbnb-javascript-style-guide-6eb78a535ba6 \ No newline at end of file diff --git a/app/server/static/js/dataset.js b/app/server/static/js/dataset.js index ff3a3a76..9ef1a65a 100644 --- a/app/server/static/js/dataset.js +++ b/app/server/static/js/dataset.js @@ -1,9 +1,9 @@ import Vue from 'vue'; -const vm = new Vue({ +const vm = new Vue({ // eslint-disable-line no-unused-vars el: '#mail-app', delimiters: ['[[', ']]'], data: { - messages: [] + messages: [], }, }); diff --git a/app/server/static/js/demo/demo_mixin.js b/app/server/static/js/demo/demo_mixin.js index 52de65c7..d232548f 100644 --- a/app/server/static/js/demo/demo_mixin.js +++ b/app/server/static/js/demo/demo_mixin.js @@ -1,3 +1,5 @@ +/* global marked:readonly */ + const annotationMixin = { data() { return { @@ -113,7 +115,7 @@ const annotationMixin = { }, id2label() { - let id2label = {}; + const id2label = {}; for (let i = 0; i < this.labels.length; i++) { const label = this.labels[i]; id2label[label.id] = label; diff --git a/app/server/static/js/demo/demo_named_entity.js b/app/server/static/js/demo/demo_named_entity.js index 0664b36b..e60c5fef 100644 --- a/app/server/static/js/demo/demo_named_entity.js +++ b/app/server/static/js/demo/demo_named_entity.js @@ -6,14 +6,14 @@ Vue.use(require('vue-shortkey'), { }); Vue.component('annotator', { - template: '
\ - {{ text.slice(r.start_offset, r.end_offset) }}\ -
', + template: '
' + + ' {{ text.slice(r.start_offset, r.end_offset) }}' + + '
', props: { labels: Array, // [{id: Integer, color: String, text: String}] text: String, @@ -27,7 +27,7 @@ Vue.component('annotator', { }, methods: { - setSelectedRange(e) { + setSelectedRange() { let start; let end; if (window.getSelection) { @@ -47,7 +47,7 @@ Vue.component('annotator', { } this.startOffset = start; this.endOffset = end; - console.log(start, end); + console.log(start, end); // eslint-disable-line no-console }, validRange() { @@ -132,7 +132,7 @@ Vue.component('annotator', { }, id2label() { - let id2label = {}; + const id2label = {}; // default value; id2label[-1] = { text_color: '', @@ -147,7 +147,7 @@ Vue.component('annotator', { }, }); -const vm = new Vue({ +const vm = new Vue({ // eslint-disable-line no-unused-vars el: '#mail-app', delimiters: ['[[', ']]'], mixins: [annotationMixin], diff --git a/app/server/static/js/demo/demo_text_classification.js b/app/server/static/js/demo/demo_text_classification.js index 3b6c93b6..226aca7e 100644 --- a/app/server/static/js/demo/demo_text_classification.js +++ b/app/server/static/js/demo/demo_text_classification.js @@ -6,7 +6,7 @@ Vue.use(require('vue-shortkey'), { }); -const vm = new Vue({ +const vm = new Vue({ // eslint-disable-line no-unused-vars el: '#mail-app', delimiters: ['[[', ']]'], mixins: [annotationMixin], @@ -88,7 +88,7 @@ const vm = new Vue({ label: label.id, }; this.annotations[this.pageNumber].push(annotation); - console.log(this.annotations); + console.log(this.annotations); // eslint-disable-line no-console } }, }, diff --git a/app/server/static/js/demo/demo_translation.js b/app/server/static/js/demo/demo_translation.js index 9c5eafd6..c603c8d5 100644 --- a/app/server/static/js/demo/demo_translation.js +++ b/app/server/static/js/demo/demo_translation.js @@ -4,7 +4,7 @@ import annotationMixin from './demo_mixin'; Vue.use(require('vue-shortkey')); -const vm = new Vue({ +const vm = new Vue({ // eslint-disable-line no-unused-vars el: '#mail-app', delimiters: ['[[', ']]'], data: { @@ -55,7 +55,7 @@ const vm = new Vue({ }, mixins: [annotationMixin], directives: { - 'todo-focus': function(el, binding) { + 'todo-focus': (el, binding) => { if (binding.value) { el.focus(); } diff --git a/app/server/static/js/document_classification.js b/app/server/static/js/document_classification.js index a6054a49..6a599f13 100644 --- a/app/server/static/js/document_classification.js +++ b/app/server/static/js/document_classification.js @@ -10,7 +10,7 @@ Vue.use(require('vue-shortkey'), { Vue.filter('simpleShortcut', simpleShortcut); -const vm = new Vue({ +const vm = new Vue({ // eslint-disable-line no-unused-vars el: '#mail-app', delimiters: ['[[', ']]'], mixins: [annotationMixin], diff --git a/app/server/static/js/filter.js b/app/server/static/js/filter.js index ce94eb09..d250ac6e 100644 --- a/app/server/static/js/filter.js +++ b/app/server/static/js/filter.js @@ -1,10 +1,7 @@ export default function simpleShortcut(shortcut) { - if (shortcut === null) { - shortcut = ''; - } else { - shortcut = shortcut.replace('ctrl', 'C'); - shortcut = shortcut.replace('shift', 'S'); - shortcut = shortcut.split(' ').join('-'); - } - return shortcut; + let simplified = shortcut === null ? '' : shortcut; + simplified = simplified.replace('ctrl', 'C'); + simplified = simplified.replace('shift', 'S'); + simplified = simplified.split(' ').join('-'); + return simplified; } diff --git a/app/server/static/js/guideline.js b/app/server/static/js/guideline.js index 8966f98e..3f5819c4 100644 --- a/app/server/static/js/guideline.js +++ b/app/server/static/js/guideline.js @@ -1,7 +1,10 @@ +/* global _:readonly */ +/* global marked:readonly */ + import Vue from 'vue'; import HTTP from './http'; -const vm = new Vue({ +const vm = new Vue({ // eslint-disable-line no-unused-vars el: '#mail-app', data: { input: '', @@ -25,10 +28,10 @@ const vm = new Vue({ }, methods: { - update: _.debounce(function (e) { + update: _.debounce((e) => { this.input = e.target.value; const payload = { - 'guideline': this.input + guideline: this.input, }; HTTP.patch('', payload).then((response) => { this.project = response.data; diff --git a/app/server/static/js/label.js b/app/server/static/js/label.js index d08b11b0..2999ed53 100644 --- a/app/server/static/js/label.js +++ b/app/server/static/js/label.js @@ -5,7 +5,7 @@ import simpleShortcut from './filter'; Vue.filter('simpleShortcut', simpleShortcut); -const vm = new Vue({ +const vm = new Vue({ // eslint-disable-line no-unused-vars el: '#mail-app', delimiters: ['[[', ']]'], data: { @@ -24,7 +24,7 @@ const vm = new Vue({ * combineKeys: Combine selectedKey and checkedKey to get shortcutKey * saveKeys: Save null to database if shortcutKey is empty string */ - combineKeys: function () { + combineKeys: () => { this.shortcutKey = ''; // If checkedKey exits, add it to shortcutKey @@ -45,7 +45,7 @@ const vm = new Vue({ return this.shortcutKey; }, - saveKeys: function () { + saveKeys: () => { this.shortcutKey = this.combineKeys; if (this.shortcutKey === '') { return null; @@ -70,7 +70,7 @@ const vm = new Vue({ removeLabel(label) { const labelId = label.id; - HTTP.delete(`labels/${labelId}`).then((response) => { + HTTP.delete(`labels/${labelId}`).then(() => { const index = this.labels.indexOf(label); this.labels.splice(index, 1); }); diff --git a/app/server/static/js/mixin.js b/app/server/static/js/mixin.js index 8a853ee7..7f9b80c4 100644 --- a/app/server/static/js/mixin.js +++ b/app/server/static/js/mixin.js @@ -1,6 +1,8 @@ +/* global marked:readonly */ + import HTTP from './http'; -const getOffsetFromUrl = function (url) { +const getOffsetFromUrl = (url) => { const offsetMatch = url.match(/[?#].*offset=(\d+)/); if (offsetMatch == null) { return 0; @@ -9,7 +11,7 @@ const getOffsetFromUrl = function (url) { return parseInt(offsetMatch[1], 10); }; -const storeOffsetInUrl = function (offset) { +const storeOffsetInUrl = (offset) => { let href = window.location.href; const fragmentStart = href.indexOf('#') + 1; @@ -19,7 +21,7 @@ const storeOffsetInUrl = function (offset) { const prefix = href.substring(0, fragmentStart); const fragment = href.substring(fragmentStart); - const newFragment = fragment.split('&').map(function (fragmentPart) { + const newFragment = fragment.split('&').map((fragmentPart) => { const keyValue = fragmentPart.split('='); return keyValue[0] === 'offset' ? 'offset=' + offset @@ -112,7 +114,7 @@ const annotationMixin = { removeLabel(annotation) { const docId = this.docs[this.pageNumber].id; - HTTP.delete(`docs/${docId}/annotations/${annotation.id}`).then((response) => { + HTTP.delete(`docs/${docId}/annotations/${annotation.id}`).then(() => { const index = this.annotations[this.pageNumber].indexOf(annotation); this.annotations[this.pageNumber].splice(index, 1); }); @@ -169,7 +171,7 @@ const annotationMixin = { }, id2label() { - let id2label = {}; + const id2label = {}; for (let i = 0; i < this.labels.length; i++) { const label = this.labels[i]; id2label[label.id] = label; diff --git a/app/server/static/js/projects.js b/app/server/static/js/projects.js index 098b5ee6..13bba464 100644 --- a/app/server/static/js/projects.js +++ b/app/server/static/js/projects.js @@ -6,7 +6,7 @@ axios.defaults.xsrfHeaderName = 'X-CSRFToken'; const baseUrl = window.location.href.split('/').slice(0, 3).join('/'); -const vm = new Vue({ +const vm = new Vue({ // eslint-disable-line no-unused-vars el: '#projects_root', delimiters: ['[[', ']]'], data: { @@ -26,7 +26,7 @@ const vm = new Vue({ methods: { deleteProject() { - axios.delete(`${baseUrl}/v1/projects/${this.project.id}`).then((response) => { + axios.delete(`${baseUrl}/v1/projects/${this.project.id}`).then(() => { this.isDelete = false; const index = this.items.indexOf(this.project); this.items.splice(index, 1); @@ -108,13 +108,7 @@ const vm = new Vue({ computed: { selectedProjects() { - const projects = []; - for (let item of this.items) { - if ((this.selected === 'All Project') || this.matchType(item.project_type)) { - projects.push(item); - } - } - return projects; + return this.items.filter(item => this.selected === 'All Project' || this.matchType(item.project_type)); }, }, diff --git a/app/server/static/js/seq2seq.js b/app/server/static/js/seq2seq.js index d7d6eb3e..a00abfc2 100644 --- a/app/server/static/js/seq2seq.js +++ b/app/server/static/js/seq2seq.js @@ -5,7 +5,7 @@ import HTTP from './http'; Vue.use(require('vue-shortkey')); -const vm = new Vue({ +const vm = new Vue({ // eslint-disable-line no-unused-vars el: '#mail-app', delimiters: ['[[', ']]'], data: { @@ -14,7 +14,7 @@ const vm = new Vue({ }, mixins: [annotationMixin], directives: { - 'todo-focus': function (el, binding) { + 'todo-focus': (el, binding) => { if (binding.value) { el.focus(); } @@ -41,7 +41,7 @@ const vm = new Vue({ removeTodo(todo) { const docId = this.docs[this.pageNumber].id; - HTTP.delete(`docs/${docId}/annotations/${todo.id}`).then((response) => { + HTTP.delete(`docs/${docId}/annotations/${todo.id}`).then(() => { const index = this.annotations[this.pageNumber].indexOf(todo); this.annotations[this.pageNumber].splice(index, 1); }); @@ -63,7 +63,7 @@ const vm = new Vue({ } const docId = this.docs[this.pageNumber].id; HTTP.put(`docs/${docId}/annotations/${todo.id}`, todo).then((response) => { - console.log(response); + console.log(response); // eslint-disable-line no-console }); }, diff --git a/app/server/static/js/sequence_labeling.js b/app/server/static/js/sequence_labeling.js index 904a8cea..54b231ae 100644 --- a/app/server/static/js/sequence_labeling.js +++ b/app/server/static/js/sequence_labeling.js @@ -10,16 +10,16 @@ Vue.use(require('vue-shortkey'), { Vue.filter('simpleShortcut', simpleShortcut); Vue.component('annotator', { - template: '
\ - {{ [...text].slice(r.start_offset, r.end_offset).join(\'\') }}\ -
', + template: '
' + + ' {{ [...text].slice(r.start_offset, r.end_offset).join(\'\') }}' + + '
', props: { labels: Array, // [{id: Integer, color: String, text: String}] text: String, @@ -33,7 +33,7 @@ Vue.component('annotator', { }, methods: { - setSelectedRange(e) { + setSelectedRange() { let start; let end; if (window.getSelection) { @@ -53,7 +53,7 @@ Vue.component('annotator', { } this.startOffset = start; this.endOffset = end; - console.log(start, end); + console.log(start, end); // eslint-disable-line no-console }, validRange() { @@ -144,7 +144,7 @@ Vue.component('annotator', { }, id2label() { - let id2label = {}; + const id2label = {}; // default value; id2label[-1] = { text_color: '', @@ -159,7 +159,7 @@ Vue.component('annotator', { }, }); -const vm = new Vue({ +const vm = new Vue({ // eslint-disable-line no-unused-vars el: '#mail-app', delimiters: ['[[', ']]'], mixins: [annotationMixin], diff --git a/app/server/static/js/stats.js b/app/server/static/js/stats.js index b4ddd91e..914e0427 100644 --- a/app/server/static/js/stats.js +++ b/app/server/static/js/stats.js @@ -2,7 +2,7 @@ import { HorizontalBar, mixins, Doughnut } from 'vue-chartjs'; import Vue from 'vue'; import HTTP from './http'; -const { reactiveProp, reactiveData } = mixins; +const { reactiveProp } = mixins; Vue.component('line-chart', { extends: HorizontalBar, @@ -50,7 +50,7 @@ Vue.component('doughnut-chart', { }, }); -const vm = new Vue({ +const vm = new Vue({ // eslint-disable-line no-unused-vars el: '#mail-app', delimiters: ['[[', ']]'], data: { @@ -94,6 +94,5 @@ const vm = new Vue({ ], }; }); - }, }); diff --git a/app/server/static/js/upload.js b/app/server/static/js/upload.js index 508801e6..fdd4e42a 100644 --- a/app/server/static/js/upload.js +++ b/app/server/static/js/upload.js @@ -1,7 +1,7 @@ import Vue from 'vue'; import HTTP from './http'; -const vm = new Vue({ +const vm = new Vue({ // eslint-disable-line no-unused-vars el: '#mail-app', delimiters: ['[[', ']]'], data: { @@ -16,7 +16,7 @@ const vm = new Vue({ upload() { this.isLoading = true; this.file = this.$refs.file.files[0]; - let formData = new FormData(); + const formData = new FormData(); formData.append('file', this.file); formData.append('format', this.format); HTTP.post('docs/upload', @@ -27,7 +27,7 @@ const vm = new Vue({ }, }) .then((response) => { - console.log(response); + console.log(response); // eslint-disable-line no-console this.messages = []; window.location = window.location.pathname.split('/').slice(0, -1).join('/'); }) @@ -42,7 +42,7 @@ const vm = new Vue({ }, download() { - let headers = {}; + const headers = {}; if (this.format === 'csv') { headers.Accept = 'text/csv; charset=utf-8'; headers['Content-Type'] = 'text/csv; charset=utf-8'; @@ -62,7 +62,7 @@ const vm = new Vue({ const url = window.URL.createObjectURL(new Blob([response.data])); const link = document.createElement('a'); link.href = url; - link.setAttribute('download', 'file.' + this.format); //or any other extension + link.setAttribute('download', 'file.' + this.format); // or any other extension document.body.appendChild(link); link.click(); }).catch((error) => {