feat: Add `no-implicit-coercion` rule
Adds the no-implicit-coercion
ESLint rule with all options enabled. This rule prevents type coercion shortcuts that can be difficult to understand:
var b = !!foo;
var b = ~foo.indexOf(".");
var n = +foo;
var n = 1 * foo;
var s = "" + foo;
foo += ``;
Right now, we use both Boolean(...)
and !!
throughout our codebase - this change would allow us to standardize on a single style (Boolean(...)
).
This change also disallows some of the shortcuts above related to String
and Number
conversions. My original goal was to standardize on Boolean(...)
vs !!
, but these additional changes seem like a good idea as well, so I'm includinging them in this merge request. If this is an issue, I can reduce the scope of the merge request to only the Boolean
conversions.
All errors can be auto-fixed by ESLint, which makes this rule easy to implement. Currently there are 92 violations of this rule in EE:
Click here to expand the result of running ESLint on EE with this new rule enabled
~/source/gdk-ee/gitlab (master) $ yarn eslint
yarn run v1.16.0
$ eslint --max-warnings 0 --report-unused-disable-directives --ext .js,.vue .
/Users/nathanfriend/source/gdk-ee/gitlab/app/assets/javascripts/behaviors/shortcuts/shortcuts_issuable.js
40:24 error use `Boolean(documentFragment.querySelector('.md'))` instead no-implicit-coercion
/Users/nathanfriend/source/gdk-ee/gitlab/app/assets/javascripts/boards/components/board_list.vue
146:70 error use `Number(e.item.dataset.issueId)` instead no-implicit-coercion
/Users/nathanfriend/source/gdk-ee/gitlab/app/assets/javascripts/boards/components/modal/index.vue
127:30 error use `Boolean(foundSelectedIssue)` instead no-implicit-coercion
/Users/nathanfriend/source/gdk-ee/gitlab/app/assets/javascripts/boards/models/list.js
40:19 error use `Boolean(typeInfo.isPreset)` instead no-implicit-coercion
41:25 error use `Boolean(typeInfo.isExpandable)` instead no-implicit-coercion
/Users/nathanfriend/source/gdk-ee/gitlab/app/assets/javascripts/branches/branches_delete_modal.js
26:21 error use `Boolean(branchData.isMerged)` instead no-implicit-coercion
/Users/nathanfriend/source/gdk-ee/gitlab/app/assets/javascripts/clusters/components/application_row.vue
141:14 error use `Boolean(this.logoUrl)` instead no-implicit-coercion
/Users/nathanfriend/source/gdk-ee/gitlab/app/assets/javascripts/compare_autocomplete.js
43:21 error use `Boolean($dropdown.data('refsUrl'))` instead no-implicit-coercion
/Users/nathanfriend/source/gdk-ee/gitlab/app/assets/javascripts/create_item_dropdown.js
15:26 error use `Boolean(options.filterRemote)` instead no-implicit-coercion
/Users/nathanfriend/source/gdk-ee/gitlab/app/assets/javascripts/error_tracking_settings/store/getters.js
5:37 error use `Boolean(state.projects)` instead no-implicit-coercion
8:3 error use `Boolean(state.selectedProject)` instead no-implicit-coercion
/Users/nathanfriend/source/gdk-ee/gitlab/app/assets/javascripts/frequent_items/store/actions.js
54:17 error use `Boolean(gon.current_user_id)` instead no-implicit-coercion
/Users/nathanfriend/source/gdk-ee/gitlab/app/assets/javascripts/gl_dropdown.js
310:22 error use `Boolean(this.options.highlight)` instead no-implicit-coercion
311:17 error use `Boolean(this.options.icon)` instead no-implicit-coercion
/Users/nathanfriend/source/gdk-ee/gitlab/app/assets/javascripts/gl_form.js
16:32 error use `Boolean(dataSources[item])` instead no-implicit-coercion
/Users/nathanfriend/source/gdk-ee/gitlab/app/assets/javascripts/ide/components/preview/clientside.vue
108:44 error use `Boolean(this.entries[createPathWithExt(p)])` instead no-implicit-coercion
/Users/nathanfriend/source/gdk-ee/gitlab/app/assets/javascripts/ide/components/repo_commit_section.vue
33:14 error use `Boolean(this.someUncommittedChanges || this.lastCommitMsg || !this.unusedSeal)` instead no-implicit-coercion
/Users/nathanfriend/source/gdk-ee/gitlab/app/assets/javascripts/ide/lib/editor_options.js
14:24 error use `Boolean(model.file.file_lock)` instead no-implicit-coercion
/Users/nathanfriend/source/gdk-ee/gitlab/app/assets/javascripts/ide/stores/getters.js
45:36 error use `Boolean(state.changedFiles.length)` instead no-implicit-coercion
45:67 error use `Boolean(state.stagedFiles.length)` instead no-implicit-coercion
47:41 error use `Boolean(state.currentMergeRequestId)` instead no-implicit-coercion
73:3 error use `Boolean(state.changedFiles.length || state.stagedFiles.length)` instead no-implicit-coercion
/Users/nathanfriend/source/gdk-ee/gitlab/app/assets/javascripts/ide/stores/modules/commit/actions.js
105:16 error use `Boolean(changedFile)` instead no-implicit-coercion
/Users/nathanfriend/source/gdk-ee/gitlab/app/assets/javascripts/ide/stores/modules/pipelines/getters.js
3:71 error use `Boolean(state.latestPipeline)` instead no-implicit-coercion
/Users/nathanfriend/source/gdk-ee/gitlab/app/assets/javascripts/ide/stores/mutations.js
145:16 error use `Boolean(changedFile)` instead no-implicit-coercion
/Users/nathanfriend/source/gdk-ee/gitlab/app/assets/javascripts/image_diff/helpers/comment_indicator_helper.js
17:22 error use `Boolean(commentIndicatorEl)` instead no-implicit-coercion
/Users/nathanfriend/source/gdk-ee/gitlab/app/assets/javascripts/image_diff/image_diff.js
9:26 error use `Boolean(options && options.canCreateNote)` instead no-implicit-coercion
10:31 error use `Boolean(options && options.renderCommentBadge)` instead no-implicit-coercion
/Users/nathanfriend/source/gdk-ee/gitlab/app/assets/javascripts/image_diff/view_types.js
8:10 error use `Boolean(Object.getOwnPropertyNames(viewTypes).find(viewType => viewType === validate))` instead no-implicit-coercion
/Users/nathanfriend/source/gdk-ee/gitlab/app/assets/javascripts/issuable_index.js
15:32 error use `Boolean(this.bulkUpdateSidebar)` instead no-implicit-coercion
/Users/nathanfriend/source/gdk-ee/gitlab/app/assets/javascripts/issue_show/components/app.vue
159:14 error use `Boolean(this.state.updatedAt)` instead no-implicit-coercion
/Users/nathanfriend/source/gdk-ee/gitlab/app/assets/javascripts/label_manager.js
56:7 error use `Boolean(this.prioritizedLabels[0].querySelector(':scope > li'))` instead no-implicit-coercion
/Users/nathanfriend/source/gdk-ee/gitlab/app/assets/javascripts/lib/utils/accessor.js
5:12 error use `Boolean(base[property])` instead no-implicit-coercion
/Users/nathanfriend/source/gdk-ee/gitlab/app/assets/javascripts/lib/utils/datetime_utility.js
516:25 error use `Boolean(unitValue)` instead no-implicit-coercion
/Users/nathanfriend/source/gdk-ee/gitlab/app/assets/javascripts/lib/utils/text_markdown.js
226:20 error use `String(val.replace(tag, ''))` instead no-implicit-coercion
228:20 error use `String(tag)` instead no-implicit-coercion
236:20 error use `String(startChar)` instead no-implicit-coercion
/Users/nathanfriend/source/gdk-ee/gitlab/app/assets/javascripts/mr_notes/stores/getters.js
3:12 error use `Boolean(getters.getUserData.id)` instead no-implicit-coercion
/Users/nathanfriend/source/gdk-ee/gitlab/app/assets/javascripts/notes/components/discussion_notes.vue
52:14 error use `Boolean(this.replies.length)` instead no-implicit-coercion
/Users/nathanfriend/source/gdk-ee/gitlab/app/assets/javascripts/notes/components/noteable_note.vue
78:14 error use `Boolean(this.note.report_abuse_path)` instead no-implicit-coercion
/Users/nathanfriend/source/gdk-ee/gitlab/app/assets/javascripts/notes/mixins/issuable_state.js
4:14 error use `Boolean(issue.confidential)` instead no-implicit-coercion
8:14 error use `Boolean(issue.discussion_locked)` instead no-implicit-coercion
/Users/nathanfriend/source/gdk-ee/gitlab/app/assets/javascripts/notes/stores/getters.js
23:38 error use `Boolean(state.noteableData.current_user.can_create_note)` instead no-implicit-coercion
/Users/nathanfriend/source/gdk-ee/gitlab/app/assets/javascripts/pages/projects/pipeline_schedules/shared/components/interval_pattern_input.vue
32:14 error use `Boolean(this.customInputEnabled || !this.intervalIsPreset)` instead no-implicit-coercion
/Users/nathanfriend/source/gdk-ee/gitlab/app/assets/javascripts/profile/account/index.js
38:32 error use `Boolean(deleteAccountModalEl.dataset.confirmWithPassword)` instead no-implicit-coercion
/Users/nathanfriend/source/gdk-ee/gitlab/app/assets/javascripts/projects/gke_cluster_dropdowns/store/actions.js
60:50 error use `Boolean(billingEnabled)` instead no-implicit-coercion
/Users/nathanfriend/source/gdk-ee/gitlab/app/assets/javascripts/projects/gke_cluster_dropdowns/store/getters.js
1:36 error use `Boolean(state.selectedProject.projectId)` instead no-implicit-coercion
2:33 error use `Boolean(state.selectedZone)` instead no-implicit-coercion
3:40 error use `Boolean(state.selectedMachineType)` instead no-implicit-coercion
/Users/nathanfriend/source/gdk-ee/gitlab/app/assets/javascripts/registry/stores/mutations.js
12:20 error use `Boolean(el.destroy_path)` instead no-implicit-coercion
45:18 error use `Boolean(element.destroy_path)` instead no-implicit-coercion
/Users/nathanfriend/source/gdk-ee/gitlab/app/assets/javascripts/right_sidebar.js
85:11 error use `String($this.data('deletePath'))` instead no-implicit-coercion
87:11 error use `String($this.data('createPath'))` instead no-implicit-coercion
/Users/nathanfriend/source/gdk-ee/gitlab/app/assets/javascripts/search_autocomplete.js
382:40 error use `Boolean(e.target.value)` instead no-implicit-coercion
399:40 error use `Boolean(e.target.value)` instead no-implicit-coercion
/Users/nathanfriend/source/gdk-ee/gitlab/app/assets/javascripts/sidebar/components/time_tracking/time_tracker.vue
52:14 error use `Boolean(this.timeSpent)` instead no-implicit-coercion
55:14 error use `Boolean(this.timeEstimate)` instead no-implicit-coercion
70:14 error use `Boolean(this.showHelp)` instead no-implicit-coercion
/Users/nathanfriend/source/gdk-ee/gitlab/app/assets/javascripts/vue_merge_request_widget/components/deployment.vue
80:14 error use `Boolean(this.deployment.external_url && this.deployment.external_url_formatted)` instead no-implicit-coercion
83:14 error use `Boolean(this.deployment.deployed_at && this.deployment.deployed_at_formatted)` instead no-implicit-coercion
86:14 error use `Boolean(this.deployment.url && this.deployment.name)` instead no-implicit-coercion
89:14 error use `Boolean(this.deployment.metrics_url)` instead no-implicit-coercion
/Users/nathanfriend/source/gdk-ee/gitlab/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_pipeline_container.vue
59:14 error use `Boolean(this.mr.visualReviewFF && this.mr.visualReviewAppAvailable)` instead no-implicit-coercion
/Users/nathanfriend/source/gdk-ee/gitlab/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue
100:14 error use `Boolean(this.mr.relatedLinks)` instead no-implicit-coercion
/Users/nathanfriend/source/gdk-ee/gitlab/app/assets/javascripts/vue_merge_request_widget/stores/mr_widget_store.js
81:28 error use `Boolean(data.should_be_rebased)` instead no-implicit-coercion
94:21 error use `Boolean(data.merge_path)` instead no-implicit-coercion
96:36 error use `Boolean(data.cancel_merge_when_pipeline_succeeds_path)` instead no-implicit-coercion
/Users/nathanfriend/source/gdk-ee/gitlab/app/assets/javascripts/vue_shared/components/pikaday.vue
37:23 error use `Boolean(this.selectedDate)` instead no-implicit-coercion
/Users/nathanfriend/source/gdk-ee/gitlab/app/assets/javascripts/vue_shared/components/table_pagination.vue
124:23 error use `Number(text)` instead no-implicit-coercion
/Users/nathanfriend/source/gdk-ee/gitlab/babel.config.js
42:16 error use `Boolean(process.env.JEST_WORKER_ID)` instead no-implicit-coercion
/Users/nathanfriend/source/gdk-ee/gitlab/ee/app/assets/javascripts/approvals/mappers.js
18:14 error use `Boolean(res.source_rule)` instead no-implicit-coercion
/Users/nathanfriend/source/gdk-ee/gitlab/ee/app/assets/javascripts/batch_comments/stores/modules/batch_comments/getters.js
32:3 error use `Boolean(diffFileSha in getters.draftsPerFileHashAndLine &&
getters.draftsPerFileHashAndLine[diffFileSha][line.line_code])` instead no-implicit-coercion
41:26 error use `Boolean(draftsForFile[lkey] || draftsForFile[rkey])` instead no-implicit-coercion
/Users/nathanfriend/source/gdk-ee/gitlab/ee/app/assets/javascripts/burndown_chart/burndown_chart.js
178:34 error use `Boolean(animate)` instead no-implicit-coercion
/Users/nathanfriend/source/gdk-ee/gitlab/ee/app/assets/javascripts/custom_metrics/components/custom_metrics_form_fields.vue
58:14 error use `Boolean(this.queryIsValid &&
this.title.length &&
this.yLabel.length &&
this.unit.length &&
this.group.length)` instead no-implicit-coercion
/Users/nathanfriend/source/gdk-ee/gitlab/ee/app/assets/javascripts/epic/sidebar_context.js
23:27 error use `Boolean($selectbox.get(0).offsetParent)` instead no-implicit-coercion
/Users/nathanfriend/source/gdk-ee/gitlab/ee/app/assets/javascripts/epic/store/getters.js
9:37 error use `Boolean(gon.current_user_id)` instead no-implicit-coercion
/Users/nathanfriend/source/gdk-ee/gitlab/ee/app/assets/javascripts/monitoring/components/alert_widget.vue
65:14 error use `Boolean(Object.keys(this.alertsToManage).length)` instead no-implicit-coercion
68:14 error use `Boolean(this.errorMessage || this.isLoading)` instead no-implicit-coercion
/Users/nathanfriend/source/gdk-ee/gitlab/ee/app/assets/javascripts/vue_merge_request_widget/components/approvals/multiple_rule/approvals_summary.vue
54:14 error use `Boolean(this.approvers.length)` instead no-implicit-coercion
/Users/nathanfriend/source/gdk-ee/gitlab/ee/app/assets/javascripts/vue_merge_request_widget/components/approvals/multiple_rule/approvals.vue
53:14 error use `Boolean(this.approvals.has_approval_rules)` instead no-implicit-coercion
59:14 error use `Boolean(this.approvals.approved)` instead no-implicit-coercion
68:14 error use `Boolean(this.approvals.user_has_approved)` instead no-implicit-coercion
71:14 error use `Boolean(this.approvals.user_can_approve)` instead no-implicit-coercion
109:14 error use `Boolean(this.action)` instead no-implicit-coercion
/Users/nathanfriend/source/gdk-ee/gitlab/ee/app/assets/javascripts/vue_merge_request_widget/stores/mr_widget_store.js
71:26 error use `Boolean(data.approvals_left)` instead no-implicit-coercion
/Users/nathanfriend/source/gdk-ee/gitlab/ee/app/assets/javascripts/vue_shared/components/linked_pipelines_mini_list.vue
39:14 error use `Boolean(this.triggeredBy.length)` instead no-implicit-coercion
42:42 error use `Boolean(this.triggered.length)` instead no-implicit-coercion
/Users/nathanfriend/source/gdk-ee/gitlab/ee/app/assets/javascripts/vue_shared/license_management/components/license_management_row.vue
27:9 error use `Boolean(license.name)` instead no-implicit-coercion
/Users/nathanfriend/source/gdk-ee/gitlab/spec/frontend/helpers/vue_test_utils_helper.js
19:3 error use `Boolean(shallowWrapper.vm.$slots[slotName].filter(vnode => vNodeContainsText(vnode, text)).length)` instead no-implicit-coercion
/Users/nathanfriend/source/gdk-ee/gitlab/spec/javascripts/helpers/vue_test_utils_helper.js
19:3 error use `Boolean(shallowWrapper.vm.$slots[slotName].filter(vnode => vNodeContainsText(vnode, text)).length)` instead no-implicit-coercion
/Users/nathanfriend/source/gdk-ee/gitlab/spec/javascripts/matchers.js
31:15 error use `Boolean(matchingIcon)` instead no-implicit-coercion
✖ 92 problems (92 errors, 0 warnings)
92 errors and 0 warnings potentially fixable with the `--fix` option.
error Command failed with exit code 1.
Context: this Slack thread (internal only)
Fixes
Here's an MR to fix all of these violations: https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/13803
And here's the CE backport of the above: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/29007