Skip to content

Commit dead917

Browse files
chore(pre-commit) / refactor(templates): add ESLint pre-commit hook + refactor result.jinja (#379)
* chore(pre-commit) / refactor(templates): add ESLint hook + refactor `result.jinja` * Add `eslint` to `pre-commit` hooks * `getFileName` + `toggleFile` moved to `utils.js` * Run linter
1 parent 1c80d7a commit dead917

File tree

10 files changed

+331
-191
lines changed

10 files changed

+331
-191
lines changed

.pre-commit-config.yaml

Lines changed: 50 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -2,65 +2,82 @@ repos:
22
- repo: https://github.com/pre-commit/pre-commit-hooks
33
rev: v5.0.0
44
hooks:
5-
# Files
65
- id: check-added-large-files
7-
description: "Prevent large files from being committed."
8-
args: ["--maxkb=10000"]
6+
description: 'Prevent large files from being committed.'
7+
args: ['--maxkb=10000']
8+
99
- id: check-case-conflict
10-
description: "Check for files that would conflict in case-insensitive filesystems."
10+
description: 'Check for files that would conflict in case-insensitive filesystems.'
11+
1112
- id: fix-byte-order-marker
12-
description: "Remove utf-8 byte order marker."
13+
description: 'Remove utf-8 byte order marker.'
14+
1315
- id: mixed-line-ending
14-
description: "Replace mixed line ending."
16+
description: 'Replace mixed line ending.'
1517

16-
# Links
1718
- id: destroyed-symlinks
18-
description: "Detect symlinks which are changed to regular files with a content of a path which that symlink was pointing to."
19+
description: 'Detect symlinks which are changed to regular files with a content of a path which that symlink was pointing to.'
1920

20-
# File files for parseable syntax: python
2121
- id: check-ast
22+
description: 'Check for parseable syntax.'
2223

23-
# File and line endings
2424
- id: end-of-file-fixer
25-
description: "Ensure that a file is either empty, or ends with one newline."
25+
description: 'Ensure that a file is either empty, or ends with one newline.'
26+
2627
- id: trailing-whitespace
27-
description: "Trim trailing whitespace."
28+
description: 'Trim trailing whitespace.'
2829

29-
# Python
3030
- id: check-docstring-first
31-
description: "Check a common error of defining a docstring after code."
31+
description: 'Check a common error of defining a docstring after code.'
32+
3233
- id: requirements-txt-fixer
33-
description: "Sort entries in requirements.txt."
34+
description: 'Sort entries in requirements.txt.'
3435

3536
- repo: https://github.com/MarcoGorelli/absolufy-imports
3637
rev: v0.3.1
3738
hooks:
3839
- id: absolufy-imports
39-
description: "Automatically convert relative imports to absolute. (Use `args: [--never]` to revert.)"
40+
description: 'Automatically convert relative imports to absolute. (Use `args: [--never]` to revert.)'
4041

4142
- repo: https://github.com/asottile/pyupgrade
4243
rev: v3.20.0
4344
hooks:
4445
- id: pyupgrade
45-
description: "Automatically upgrade syntax for newer versions."
46+
description: 'Automatically upgrade syntax for newer versions.'
4647
args: [--py3-plus, --py36-plus]
4748

4849
- repo: https://github.com/pre-commit/pygrep-hooks
4950
rev: v1.10.0
5051
hooks:
5152
- id: python-check-blanket-noqa
52-
description: "Enforce that `noqa` annotations always occur with specific codes. Sample annotations: `# noqa: F401`, `# noqa: F401,W203`."
53+
description: 'Enforce that `# noqa` annotations always occur with specific codes.'
54+
5355
- id: python-check-blanket-type-ignore
54-
description: "Enforce that `# type: ignore` annotations always occur with specific codes. Sample annotations: `# type: ignore[attr-defined]`, `# type: ignore[attr-defined, name-defined]`."
56+
description: 'Enforce that `# type: ignore` annotations always occur with specific codes.'
57+
5558
- id: python-use-type-annotations
56-
description: "Enforce that python3.6+ type annotations are used instead of type comments."
59+
description: 'Enforce that python3.6+ type annotations are used instead of type comments.'
5760

5861
- repo: https://github.com/PyCQA/isort
5962
rev: 6.0.1
6063
hooks:
6164
- id: isort
62-
description: "Sort imports alphabetically, and automatically separated into sections and by type."
65+
description: 'Sort imports alphabetically, and automatically separated into sections and by type.'
6366

67+
- repo: https://github.com/pre-commit/mirrors-eslint
68+
rev: v9.30.1
69+
hooks:
70+
- id: eslint
71+
description: 'Lint javascript files.'
72+
files: \.js$
73+
args: [--max-warnings=0, --fix]
74+
additional_dependencies:
75+
[
76+
'eslint@9.30.1',
77+
'@eslint/js@9.30.1',
78+
'eslint-plugin-import@2.32.0',
79+
'globals@16.3.0',
80+
]
6481

6582
- repo: https://github.com/djlint/djLint
6683
rev: v1.36.4
@@ -71,11 +88,11 @@ repos:
7188
rev: v0.45.0
7289
hooks:
7390
- id: markdownlint
74-
description: "Lint markdown files."
75-
args: ["--disable=line-length"]
91+
description: 'Lint markdown files.'
92+
args: ['--disable=line-length']
7693

7794
- repo: https://github.com/astral-sh/ruff-pre-commit
78-
rev: v0.12.1
95+
rev: v0.12.2
7996
hooks:
8097
- id: ruff-check
8198
- id: ruff-format
@@ -97,17 +114,19 @@ repos:
97114
additional_dependencies:
98115
[
99116
click>=8.0.0,
100-
"fastapi[standard]>=0.109.1",
117+
'fastapi[standard]>=0.109.1',
118+
httpx,
119+
pathspec>=0.12.1,
101120
pydantic,
102121
pytest-asyncio,
103122
pytest-mock,
104123
python-dotenv,
105124
slowapi,
106125
starlette>=0.40.0,
107-
tiktoken,
108-
pathspec,
126+
tiktoken>=0.7.0,
109127
uvicorn>=0.11.7,
110128
]
129+
111130
- id: pylint
112131
name: pylint for tests
113132
files: ^tests/
@@ -116,15 +135,16 @@ repos:
116135
additional_dependencies:
117136
[
118137
click>=8.0.0,
119-
"fastapi[standard]>=0.109.1",
138+
'fastapi[standard]>=0.109.1',
139+
httpx,
140+
pathspec>=0.12.1,
120141
pydantic,
121142
pytest-asyncio,
122143
pytest-mock,
123144
python-dotenv,
124145
slowapi,
125146
starlette>=0.40.0,
126-
tiktoken,
127-
pathspec,
147+
tiktoken>=0.7.0,
128148
uvicorn>=0.11.7,
129149
]
130150

eslint.config.cjs

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
const js = require('@eslint/js');
2+
const globals = require('globals');
3+
const importPlugin = require('eslint-plugin-import');
4+
5+
module.exports = [
6+
js.configs.recommended,
7+
8+
{
9+
files: ['src/static/js/**/*.js'],
10+
11+
languageOptions: {
12+
parserOptions: { ecmaVersion: 2021, sourceType: 'module' },
13+
globals: {
14+
...globals.browser,
15+
changePattern: 'readonly',
16+
copyFullDigest: 'readonly',
17+
copyText: 'readonly',
18+
downloadFullDigest: 'readonly',
19+
handleSubmit: 'readonly',
20+
posthog: 'readonly',
21+
submitExample: 'readonly',
22+
toggleAccessSettings: 'readonly',
23+
toggleFile: 'readonly',
24+
},
25+
},
26+
27+
plugins: { import: importPlugin },
28+
29+
rules: {
30+
// Import hygiene (eslint-plugin-import)
31+
'import/no-extraneous-dependencies': 'error',
32+
'import/no-unresolved': 'error',
33+
'import/order': ['warn', { alphabetize: { order: 'asc' } }],
34+
35+
// Safety & bug-catchers
36+
'consistent-return': 'error',
37+
'default-case': 'error',
38+
'no-implicit-globals': 'error',
39+
'no-shadow': 'error',
40+
41+
// Maintainability / complexity
42+
complexity: ['warn', 10],
43+
'max-depth': ['warn', 4],
44+
'max-lines': ['warn', 500],
45+
'max-params': ['warn', 5],
46+
47+
// Stylistic consistency (auto-fixable)
48+
'arrow-parens': ['error', 'always'],
49+
curly: ['error', 'all'],
50+
indent: ['error', 4, { SwitchCase: 2 }],
51+
'newline-per-chained-call': ['warn', { ignoreChainWithDepth: 2 }],
52+
'no-multi-spaces': 'error',
53+
'object-shorthand': ['error', 'always'],
54+
'padding-line-between-statements': [
55+
'warn',
56+
{ blankLine: 'always', prev: '*', next: 'return' },
57+
{ blankLine: 'always', prev: ['const', 'let', 'var'], next: '*' },
58+
{ blankLine: 'any', prev: ['const', 'let', 'var'], next: ['const', 'let', 'var'] },
59+
],
60+
'quote-props': ['error', 'consistent-as-needed'],
61+
quotes: ['error', 'single', { avoidEscape: true }],
62+
semi: 'error',
63+
64+
// Modern / performance tips
65+
'arrow-body-style': ['warn', 'as-needed'],
66+
'prefer-arrow-callback': 'error',
67+
'prefer-exponentiation-operator': 'error',
68+
'prefer-numeric-literals': 'error',
69+
'prefer-object-has-own': 'warn',
70+
'prefer-object-spread': 'error',
71+
'prefer-template': 'error',
72+
},
73+
},
74+
];
Lines changed: 0 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -1,57 +1 @@
1-
<script>
2-
function getFileName(element) {
3-
const indentSize = 4;
4-
let path = "";
5-
let prevIndentLevel = null;
6-
7-
while (element) {
8-
const line = element.textContent;
9-
const index = line.search(/[a-zA-Z0-9_.-]/);
10-
const indentLevel = index / indentSize;
11-
12-
// Stop when we reach or go above the top-level directory
13-
if (indentLevel <= 1) {
14-
break;
15-
}
16-
17-
// Only include directories that are one level above the previous
18-
if (prevIndentLevel === null || indentLevel === prevIndentLevel - 1) {
19-
const fileName = line.substring(index).trim();
20-
path = fileName + path;
21-
prevIndentLevel = indentLevel;
22-
}
23-
24-
element = element.previousElementSibling;
25-
}
26-
27-
return path;
28-
}
29-
30-
function toggleFile(element) {
31-
const patternInput = document.getElementById("pattern");
32-
const patternFiles = patternInput.value ? patternInput.value.split(",").map(item => item.trim()) : [];
33-
34-
const directoryContainer = document.getElementById("directory-structure-container");
35-
const treeLineElements = Array.from(directoryContainer.children).filter(child => child.tagName === "PRE");
36-
37-
// Skip the first two tree lines (header and repository name)
38-
if (treeLineElements[0] === element || treeLineElements[1] === element) {
39-
return;
40-
}
41-
42-
element.classList.toggle('line-through');
43-
element.classList.toggle('text-gray-500');
44-
45-
const fileName = getFileName(element);
46-
const fileIndex = patternFiles.indexOf(fileName);
47-
48-
if (fileIndex !== -1) {
49-
patternFiles.splice(fileIndex, 1);
50-
} else {
51-
patternFiles.push(fileName);
52-
}
53-
54-
patternInput.value = patternFiles.join(", ");
55-
}
56-
</script>
571
<div class="mt-10" data-results></div>
Lines changed: 27 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,32 @@
11
<style type="text/tailwindcss">
2-
@layer components {
3-
.badge-new { @apply inline-block -rotate-6 -translate-y-1 mx-1 px-1 bg-[#FE4A60] border border-gray-900 text-white text-[10px] font-bold shadow-[2px_2px_0_0_rgba(0,0,0,1)]; }
4-
.landing-page-title { @apply inline-block w-full relative text-center text-4xl sm:text-5xl md:text-6xl lg:text-7xl sm:pt-20 lg:pt-5 font-bold tracking-tighter; }
5-
.intro-text { @apply text-center text-gray-600 text-lg max-w-2xl mx-auto; }
6-
.sparkle-red { @apply absolute flex-shrink-0 h-auto w-14 sm:w-20 md:w-24 p-2 left-0 lg:ml-32 -translate-x-2 md:translate-x-10 lg:-translate-x-full -translate-y-4 sm:-translate-y-8 md:-translate-y-0 lg:-translate-y-10; }
7-
.sparkle-green { @apply absolute flex-shrink-0 right-0 bottom-0 w-10 sm:w-16 lg:w-20 -translate-x-10 lg:-translate-x-12 translate-y-4 sm:translate-y-10 md:translate-y-2 lg:translate-y-4; }
8-
.pattern-select { @apply min-w-max appearance-none pr-6 pl-2 py-2 bg-[#e6e8eb] border-r-[3px] border-gray-900 cursor-pointer focus:outline-none; }
2+
@layer components {
3+
.badge-new {
4+
@apply inline-block -rotate-6 -translate-y-1 mx-1 px-1 bg-[#FE4A60] border border-gray-900 text-white text-[10px] font-bold shadow-[2px_2px_0_0_rgba(0,0,0,1)];
95
}
6+
.landing-page-title {
7+
@apply inline-block w-full relative text-center text-4xl sm:text-5xl md:text-6xl lg:text-7xl sm:pt-20 lg:pt-5 font-bold tracking-tighter;
8+
}
9+
.intro-text {
10+
@apply text-center text-gray-600 text-lg max-w-2xl mx-auto;
11+
}
12+
.sparkle-red {
13+
@apply absolute flex-shrink-0 h-auto w-14 sm:w-20 md:w-24 p-2 left-0 lg:ml-32 -translate-x-2 md:translate-x-10 lg:-translate-x-full -translate-y-4 sm:-translate-y-8 md:-translate-y-0 lg:-translate-y-10;
14+
}
15+
.sparkle-green {
16+
@apply absolute flex-shrink-0 right-0 bottom-0 w-10 sm:w-16 lg:w-20 -translate-x-10 lg:-translate-x-12 translate-y-4 sm:translate-y-10 md:translate-y-2 lg:translate-y-4;
17+
}
18+
.pattern-select {
19+
@apply min-w-max appearance-none pr-6 pl-2 py-2 bg-[#e6e8eb] border-r-[3px] border-gray-900 cursor-pointer focus:outline-none;
20+
}
21+
}
1022

11-
@layer utilities {
12-
.no-drag { @apply pointer-events-none select-none; -webkit-user-drag: none; }
13-
.link-bounce { @apply transition-transform hover:-translate-y-0.5; }
23+
@layer utilities {
24+
.no-drag {
25+
@apply pointer-events-none select-none;
26+
-webkit-user-drag: none;
27+
}
28+
.link-bounce {
29+
@apply transition-transform hover:-translate-y-0.5;
1430
}
31+
}
1532
</style>

src/static/js/git.js

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,29 @@
1-
21
function waitForStars() {
32
return new Promise((resolve) => {
43
const check = () => {
5-
const stars = document.getElementById("github-stars");
6-
if (stars && stars.textContent !== "0") resolve();
7-
else setTimeout(check, 10);
4+
const stars = document.getElementById('github-stars');
5+
6+
if (stars && stars.textContent !== '0') {resolve();}
7+
else {setTimeout(check, 10);}
88
};
9+
910
check();
1011
});
1112
}
1213

13-
document.addEventListener("DOMContentLoaded", () => {
14-
const urlInput = document.getElementById("input_text");
15-
const form = document.getElementById("ingestForm");
14+
document.addEventListener('DOMContentLoaded', () => {
15+
const urlInput = document.getElementById('input_text');
16+
const form = document.getElementById('ingestForm');
1617

1718
if (urlInput && urlInput.value.trim() && form) {
18-
// Wait for stars to be loaded before submitting
19+
// Wait for stars to be loaded before submitting
1920
waitForStars().then(() => {
20-
const submitEvent = new SubmitEvent("submit", {
21+
const submitEvent = new SubmitEvent('submit', {
2122
cancelable: true,
2223
bubbles: true
2324
});
24-
Object.defineProperty(submitEvent, "target", {
25+
26+
Object.defineProperty(submitEvent, 'target', {
2527
value: form,
2628
enumerable: true
2729
});

0 commit comments

Comments
 (0)