Skip to content

Commit 064a48f

Browse files
authored
Add ESLint for JavaScript and Vue linting (#920)
1 parent a0ba4e9 commit 064a48f

File tree

8 files changed

+622
-49
lines changed

8 files changed

+622
-49
lines changed

.github/scripts/validate-fixtures-json.js

Lines changed: 31 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -10,35 +10,35 @@ const path = require('path');
1010
*/
1111
function extractJsonFromHttpFile(filePath) {
1212
const content = fs.readFileSync(filePath, 'utf8');
13-
13+
1414
// Split by double newline to separate headers from body
1515
const parts = content.split(/\n\s*\n/, 2);
16-
17-
if (parts.length < 2) {
16+
17+
if (parts.length < 2)
1818
return null;
19-
}
20-
19+
20+
2121
const body = parts[1].trim();
22-
if (!body) {
22+
if (!body)
2323
return null;
24-
}
25-
24+
25+
2626
// Check if content-type indicates JSON
2727
const headers = parts[0];
28-
const isJsonContentType = headers.includes('Content-Type: application/json') ||
28+
const isJsonContentType = headers.includes('Content-Type: application/json') ||
2929
headers.includes('content-type: application/json');
30-
30+
3131
// If no explicit JSON content-type, try to parse as JSON anyway
3232
// (some files might have JSON without proper content-type header)
33-
if (!isJsonContentType) {
33+
if (!isJsonContentType)
3434
try {
3535
JSON.parse(body);
3636
return body;
37-
} catch (e) {
37+
} catch {
3838
return null;
3939
}
40-
}
41-
40+
41+
4242
return body;
4343
}
4444

@@ -49,22 +49,22 @@ function extractJsonFromHttpFile(filePath) {
4949
*/
5050
function findHttpFiles(dir) {
5151
const files = [];
52-
52+
5353
function traverse(currentDir) {
5454
const items = fs.readdirSync(currentDir);
55-
55+
5656
for (const item of items) {
5757
const fullPath = path.join(currentDir, item);
5858
const stat = fs.statSync(fullPath);
59-
60-
if (stat.isDirectory()) {
59+
60+
if (stat.isDirectory())
6161
traverse(fullPath);
62-
} else if (item.endsWith('.http')) {
62+
else if (item.endsWith('.http'))
6363
files.push(fullPath);
64-
}
64+
6565
}
6666
}
67-
67+
6868
traverse(dir);
6969
return files;
7070
}
@@ -77,21 +77,21 @@ function validateJsonInFixtures(fixturesDir) {
7777
const errors = [];
7878
let filesChecked = 0;
7979
let jsonFilesFound = 0;
80-
80+
8181
console.log(`🔍 Scanning for HTTP fixtures in: ${fixturesDir}`);
82-
82+
8383
const httpFiles = findHttpFiles(fixturesDir);
84-
84+
8585
for (const filePath of httpFiles) {
8686
filesChecked++;
8787
const jsonContent = extractJsonFromHttpFile(filePath);
88-
89-
if (!jsonContent) {
88+
89+
if (!jsonContent)
9090
continue;
91-
}
92-
91+
92+
9393
jsonFilesFound++;
94-
94+
9595
try {
9696
JSON.parse(jsonContent);
9797
console.log(`✅ ${filePath}`);
@@ -101,12 +101,12 @@ function validateJsonInFixtures(fixturesDir) {
101101
errors.push(errorMsg);
102102
}
103103
}
104-
104+
105105
console.log('\n📊 Summary:');
106106
console.log(`Files checked: ${filesChecked}`);
107107
console.log(`JSON files found: ${jsonFilesFound}`);
108108
console.log(`Validation errors: ${errors.length}`);
109-
109+
110110
if (errors.length > 0) {
111111
console.log('\n❌ Errors found:');
112112
errors.forEach(error => console.log(` ${error}`));

.github/workflows/ci.yml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,22 @@ concurrency:
1212
cancel-in-progress: true
1313

1414
jobs:
15+
lint:
16+
name: Lint JavaScript
17+
runs-on: ubuntu-latest
18+
timeout-minutes: 10
19+
steps:
20+
- uses: actions/checkout@v6
21+
- name: Install Node
22+
uses: actions/setup-node@v6
23+
with:
24+
node-version-file: '.tool-versions'
25+
cache: yarn
26+
- name: Install JS Deps
27+
run: yarn install --frozen-lockfile
28+
- name: Run ESLint
29+
run: yarn lint
30+
1531
lint_openapi:
1632
name: Lint OpenAPI Spec
1733
runs-on: ubuntu-latest

eslint.config.mjs

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import js from '@eslint/js';
2+
import pluginVue from 'eslint-plugin-vue';
3+
import globals from 'globals';
4+
5+
export default [
6+
{
7+
ignores: ['dist/', 'output/', 'node_modules/', 'tmp/'],
8+
},
9+
js.configs.recommended,
10+
...pluginVue.configs['flat/recommended'],
11+
{
12+
languageOptions: {
13+
ecmaVersion: 'latest',
14+
sourceType: 'module',
15+
globals: {
16+
...globals.browser,
17+
},
18+
},
19+
rules: {
20+
semi: ['error', 'always'], // Enforce semicolons
21+
curly: ['error', 'multi'], // Enforce curly braces only for multi-line blocks
22+
'vue/multi-word-component-names': 'off',
23+
'vue/no-v-html': 'off',
24+
},
25+
},
26+
{
27+
files: ['webpack.config.js', '.github/**/*.js'],
28+
languageOptions: {
29+
sourceType: 'commonjs',
30+
globals: {
31+
...globals.node,
32+
},
33+
},
34+
},
35+
];

package.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,23 @@
33
"version": "0.0.1",
44
"private": true,
55
"devDependencies": {
6+
"@eslint/js": "^9.18.0",
67
"@fortawesome/fontawesome-free": "^7.1.0",
78
"@redocly/cli": "^2.14.4",
89
"@vue/compiler-sfc": "^3.4.21",
910
"concurrently": "^9.2.1",
1011
"copy-webpack-plugin": "^13.0.1",
12+
"eslint": "^9.18.0",
13+
"eslint-plugin-vue": "^9.32.0",
14+
"globals": "^15.14.0",
1115
"tachyons": "^4.12.0",
1216
"vue-loader": "^17.4.2",
1317
"webpack": "^5.104.1",
1418
"webpack-cli": "^6.0.1"
1519
},
1620
"scripts": {
21+
"lint": "eslint .",
22+
"lint:fix": "eslint . --fix",
1723
"live": "concurrently 'bundle exec nanoc live' 'bundle exec rake compile'",
1824
"build": "npx webpack",
1925
"openapi-lint": "redocly lint content/v2/openapi.yml"

src/components/tabs.vue

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,21 @@
11
<template>
22
<div class="pv3">
3-
<div v-for="tab in tabs" v-bind:key="'tab-top-' + tab" @click="currentTab = tab" v-bind:class="{ 'b bg-moon-gray': currentTab === tab }" class="dib pv1 ph2 bt bl br b--moon-gray pointer ttc">
3+
<div
4+
v-for="tab in tabs"
5+
:key="'tab-top-' + tab"
6+
:class="{ 'b bg-moon-gray': currentTab === tab }"
7+
class="dib pv1 ph2 bt bl br b--moon-gray pointer ttc"
8+
@click="currentTab = tab"
9+
>
410
{{ tab }}
511
</div>
612
<div class="tab-content ba pa3 b--moon-gray">
7-
<div v-for="(tab, index) in tabs" :key="`tab${index}`" v-if="currentTab === tab">
8-
<div v-html="contents[index]"></div>
13+
<div
14+
v-for="(tab, index) in tabs"
15+
v-show="currentTab === tab"
16+
:key="`tab${index}`"
17+
>
18+
<div v-html="contents[index]" />
919
</div>
1020
</div>
1121
</div>
@@ -21,7 +31,7 @@
2131
tabs: [],
2232
contents: [],
2333
currentTab: ""
24-
}
34+
};
2535
},
2636
mounted () {
2737
this.tabs = Object.keys(this.$slots);
@@ -31,5 +41,5 @@
3141
this.contents = Object.values(this.$slots).map(content => marked(content[0].text, codeHighlightOptions));
3242
this.currentTab = this.tabs[0];
3343
},
34-
}
44+
};
3545
</script>

src/index.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
import { createApp } from 'vue';
2-
import Tabs from "./components/tabs.vue"
2+
import Tabs from "./components/tabs.vue";
33

4-
createApp(Tabs).mount('.component')
4+
createApp(Tabs).mount('.component');
55

66
function toggleColorMode (e) {
77
// Switch to Light Mode
88
if (e.currentTarget.classList.contains("light--hidden")) {
99
document.documentElement.setAttribute("color-mode", "light");
10-
localStorage.setItem("color-mode", "light")
10+
localStorage.setItem("color-mode", "light");
1111
return;
1212
}
1313

webpack.config.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
const path = require('path');
22
const CopyPlugin = require('copy-webpack-plugin');
3-
const { VueLoaderPlugin } = require('vue-loader')
3+
const { VueLoaderPlugin } = require('vue-loader');
44

55
module.exports = {
66
mode: 'production',

0 commit comments

Comments
 (0)