Skip to content

Commit b85d11e

Browse files
staredclaude
andcommitted
Update ESLint configuration and fix linting issues
- Upgrade to stricter Vue3 recommended rules - Add TypeScript ESLint parser configuration - Update linting rules for better code quality - Fix linting issues across all components - Add CLAUDE.md for development workflow 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]>
1 parent 4c63fa2 commit b85d11e

File tree

11 files changed

+106
-32
lines changed

11 files changed

+106
-32
lines changed

.eslintrc.cjs

Lines changed: 65 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,22 +4,67 @@ require('@rushstack/eslint-patch/modern-module-resolution')
44
module.exports = {
55
root: true,
66
extends: [
7-
'plugin:vue/vue3-strongly-recommended',
7+
'plugin:vue/vue3-recommended',
88
'eslint:recommended',
9+
'plugin:@typescript-eslint/recommended',
10+
'plugin:@typescript-eslint/recommended-requiring-type-checking',
911
'@vue/eslint-config-typescript/recommended',
1012
'@vue/eslint-config-prettier/skip-formatting'
1113
],
14+
parser: 'vue-eslint-parser',
1215
parserOptions: {
13-
ecmaVersion: 'latest'
16+
parser: '@typescript-eslint/parser',
17+
ecmaVersion: 'latest',
18+
sourceType: 'module',
19+
project: ['./tsconfig.json', './tsconfig.node.json'],
20+
tsconfigRootDir: __dirname,
21+
extraFileExtensions: ['.vue']
1422
},
23+
ignorePatterns: ['.eslintrc.cjs', 'dist', 'node_modules'],
1524
rules: {
16-
'no-console': 'off',
17-
'no-debugger': 'error',
25+
// Line length
26+
'max-len': ['error', {
27+
code: 120,
28+
ignoreComments: true,
29+
ignoreStrings: true,
30+
ignoreTemplateLiterals: true,
31+
ignoreRegExpLiterals: true
32+
}],
33+
34+
// General rules
35+
'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
36+
'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'warn',
1837
'no-var': 'error',
1938
'prefer-const': 'error',
2039
'prefer-arrow-callback': 'error',
21-
'@typescript-eslint/no-unused-vars': 'error',
40+
'eqeqeq': ['error', 'always'],
41+
'curly': ['error', 'all'],
42+
43+
// TypeScript rules
44+
'@typescript-eslint/no-unused-vars': ['error', {
45+
argsIgnorePattern: '^_',
46+
varsIgnorePattern: '^_'
47+
}],
2248
'@typescript-eslint/no-explicit-any': 'warn',
49+
'@typescript-eslint/explicit-function-return-type': 'off',
50+
'@typescript-eslint/explicit-module-boundary-types': 'off',
51+
'@typescript-eslint/no-non-null-assertion': 'warn',
52+
'@typescript-eslint/no-floating-promises': 'error',
53+
'@typescript-eslint/no-misused-promises': 'error',
54+
'@typescript-eslint/await-thenable': 'error',
55+
'@typescript-eslint/no-unnecessary-type-assertion': 'error',
56+
'@typescript-eslint/prefer-as-const': 'error',
57+
'@typescript-eslint/consistent-type-imports': ['error', {
58+
prefer: 'type-imports'
59+
}],
60+
// Relax rules for external library types
61+
'@typescript-eslint/no-unsafe-assignment': 'off',
62+
'@typescript-eslint/no-unsafe-member-access': 'off',
63+
'@typescript-eslint/no-unsafe-call': 'off',
64+
'@typescript-eslint/no-unsafe-argument': 'off',
65+
'@typescript-eslint/restrict-template-expressions': 'off',
66+
67+
// Vue rules
2368
'vue/multi-word-component-names': 'off',
2469
'vue/no-unused-components': 'error',
2570
'vue/no-unused-vars': 'error',
@@ -28,7 +73,20 @@ module.exports = {
2873
}],
2974
'vue/block-tag-newline': 'error',
3075
'vue/component-name-in-template-casing': ['error', 'PascalCase'],
31-
'vue/define-props-declaration': 'error',
32-
'vue/no-empty-component-block': 'error'
76+
'vue/define-props-declaration': ['error', 'type-based'],
77+
'vue/define-emits-declaration': ['error', 'type-based'],
78+
'vue/no-empty-component-block': 'error',
79+
'vue/padding-line-between-blocks': 'error',
80+
'vue/prefer-separate-static-class': 'error',
81+
'vue/prefer-true-attribute-shorthand': 'error',
82+
'vue/v-on-function-call': ['error', 'never'],
83+
'vue/no-useless-v-bind': 'error',
84+
'vue/no-useless-mustaches': 'error',
85+
'vue/no-constant-condition': 'warn',
86+
'vue/require-macro-variable-name': 'error',
87+
'vue/valid-define-options': 'error',
88+
'vue/block-lang': ['error', {
89+
'script': { 'lang': 'ts' }
90+
}]
3391
}
3492
}

CLAUDE.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
## Development Workflow
2+
3+
- Run pnpm lint before any commit (and after major edits as well).

src/App.vue

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ const handleFileUpload = async (csvData: CsvData) => {
5151
5252
const handleFileRemoved = () => {
5353
// Clear any data-related variables in R
54-
executeCode('if (exists("data")) rm(data)')
54+
void executeCode('if (exists("data")) rm(data)')
5555
}
5656
5757
const handleExampleSelect = async (example: RExample) => {
@@ -64,7 +64,7 @@ const handleExampleSelect = async (example: RExample) => {
6464
}
6565
6666
onMounted(() => {
67-
initializeWebR(code.value)
67+
void initializeWebR(code.value)
6868
// Set initial executed code after auto-execution
6969
setTimeout(() => {
7070
lastExecutedCode.value = code.value
@@ -114,12 +114,20 @@ onMounted(() => {
114114
<div class="console-content">
115115
<div class="console-header">
116116
<span class="console-title">Console Output</span>
117-
<button @click="showConsole = false" class="console-close">×</button>
117+
<button class="console-close" @click="showConsole = false">×</button>
118118
</div>
119119
<div class="console-messages">
120-
<div v-for="(message, index) in textMessages" :key="'text-' + index" class="console-message" :class="message.type">
120+
<div
121+
v-for="(message, index) in textMessages"
122+
:key="'text-' + index"
123+
class="console-message"
124+
:class="message.type"
125+
>
121126
<span class="message-label">{{ message.type.toUpperCase() }}:</span>
122-
<pre v-if="message.type === 'stdout' || message.type === 'stderr'" class="message-text">{{ message.content }}</pre>
127+
<pre
128+
v-if="message.type === 'stdout' || message.type === 'stderr'"
129+
class="message-text"
130+
>{{ message.content }}</pre>
123131
<span v-else class="message-text">{{ message.content }}</span>
124132
</div>
125133
</div>
@@ -132,20 +140,20 @@ onMounted(() => {
132140
<div class="bottom-bar">
133141
<div class="bottom-bar-left">
134142
<button
135-
@click="runCode"
136143
:disabled="!isReady || isLoading"
137-
:class="{ 'has-changes': hasChanges, 'no-changes': !hasChanges }"
144+
:class="{ 'has-changes': hasChanges, 'no-changes': !hasChanges }"
138145
class="run-button"
146+
@click="runCode"
139147
>
140148
{{ isLoading ? 'Running...' : 'Run Code' }}
141149
</button>
142150
</div>
143151
<div class="bottom-bar-right">
144152
<button
145153
v-if="textMessages.length > 0"
146-
@click="showConsole = !showConsole"
147154
class="console-toggle"
148155
:class="{ 'has-errors': hasErrors }"
156+
@click="showConsole = !showConsole"
149157
>
150158
Console ({{ textMessages.length }})
151159
<span class="toggle-arrow" :class="{ 'open': showConsole }">▼</span>

src/components/CodeEditor.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ const editorRef = ref<HTMLElement>()
1919
let editor: monaco.editor.IStandaloneCodeEditor | null = null
2020
2121
onMounted(() => {
22-
if (!editorRef.value) return
22+
if (!editorRef.value) {return}
2323
2424
editor = monaco.editor.create(editorRef.value, {
2525
value: props.modelValue,

src/components/ExampleSelector.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,8 @@ const handleExampleChange = () => {
2525
<select
2626
id="example-select"
2727
v-model="selectedExample"
28-
@change="handleExampleChange"
2928
class="select"
29+
@change="handleExampleChange"
3030
>
3131
<option v-for="example in examples" :key="example.id" :value="example.id">
3232
{{ example.title }}

src/components/FileUpload.vue

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ onUnmounted(() => {
106106
</script>
107107

108108
<template>
109-
<div class="file-upload" ref="dropdownRef">
109+
<div ref="dropdownRef" class="file-upload">
110110
<div
111111
v-if="!uploadedFile"
112112
class="upload-button"
@@ -120,9 +120,9 @@ onUnmounted(() => {
120120
ref="fileInputRef"
121121
type="file"
122122
accept=".csv"
123-
@change="handleFileSelect"
124123
class="file-input"
125124
style="display: none;"
125+
@change="handleFileSelect"
126126
/>
127127
<span class="upload-icon">📁</span>
128128
<span class="upload-text">Upload CSV</span>
@@ -131,8 +131,8 @@ onUnmounted(() => {
131131

132132
<div v-else class="csv-info-container">
133133
<button
134-
@click="toggleDropdown"
135134
class="csv-button"
135+
@click="toggleDropdown"
136136
>
137137
<span class="csv-icon">📊</span>
138138
<span class="csv-text">{{ uploadedFile.name }} ({{ uploadedFile.rows }} × {{ uploadedFile.columns }})</span>
@@ -142,7 +142,7 @@ onUnmounted(() => {
142142
<div v-if="isOpen" class="csv-dropdown">
143143
<div class="csv-header">
144144
<span class="header-text">CSV Information</span>
145-
<button @click="removeFile" class="remove-btn" title="Remove file">×</button>
145+
<button class="remove-btn" title="Remove file" @click="removeFile">×</button>
146146
</div>
147147
<div class="csv-details">
148148
<div class="detail-item">

src/components/LibrarySelector.vue

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -56,12 +56,12 @@ onUnmounted(() => {
5656
</script>
5757

5858
<template>
59-
<div class="library-selector" ref="dropdownRef">
59+
<div ref="dropdownRef" class="library-selector">
6060
<button
61-
@click="toggleDropdown"
6261
:disabled="isLoading"
6362
class="libraries-button"
6463
:class="{ 'disabled': isLoading }"
64+
@click="toggleDropdown"
6565
>
6666
<span class="libraries-icon">📚</span>
6767
<span class="libraries-text">Libraries ({{ installedCount }})</span>
@@ -83,8 +83,8 @@ onUnmounted(() => {
8383
type="checkbox"
8484
:checked="installedLibraries.has(library.name)"
8585
:disabled="isLoading"
86-
@change="handleToggle(library.name, $event)"
8786
class="library-checkbox"
87+
@change="handleToggle(library.name, $event)"
8888
/>
8989
<div class="library-info">
9090
<span class="library-name">{{ library.name }}</span>

src/components/OutputDisplay.vue

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ const props = defineProps<Props>()
1313
const outputRef = ref<HTMLElement>()
1414
1515
const scrollToBottom = () => {
16-
nextTick(() => {
16+
void nextTick(() => {
1717
if (outputRef.value) {
1818
outputRef.value.scrollTop = outputRef.value.scrollHeight
1919
}
@@ -46,7 +46,7 @@ watch(
4646

4747
<template>
4848
<div class="output-display">
49-
<div class="output-content" ref="outputRef">
49+
<div ref="outputRef" class="output-content">
5050
<div v-if="isLoading" class="loading">
5151
<div class="spinner"></div>
5252
<span>Running R code...</span>
@@ -231,6 +231,4 @@ watch(
231231
color: #374151;
232232
white-space: pre-wrap;
233233
}
234-
235-
236234
</style>

src/components/WebRStatus.vue

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,14 @@ defineProps<Props>()
1010

1111
<template>
1212
<div class="webr-status">
13-
<div class="status-indicator" :class="{ 'loading': isLoading, 'ready': isReady && !isLoading, 'error': !isReady && !isLoading && loadingStatus.includes('Failed') }">
13+
<div
14+
class="status-indicator"
15+
:class="{
16+
'loading': isLoading,
17+
'ready': isReady && !isLoading,
18+
'error': !isReady && !isLoading && loadingStatus.includes('Failed')
19+
}"
20+
>
1421
<div v-if="isLoading" class="spinner"></div>
1522
<span v-else-if="isReady" class="status-icon">✓</span>
1623
<span v-else-if="loadingStatus.includes('Failed')" class="status-icon">✗</span>

src/composables/useWebR.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,7 @@ export const useWebR = () => {
166166
}
167167

168168
const toggleLibrary = async (library: string, install: boolean) => {
169-
if (!webR) return
169+
if (!webR) {return}
170170

171171
try {
172172
if (install) {

0 commit comments

Comments
 (0)