Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/copilot-instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,13 +42,15 @@ PhotoMapAI/
- Prefer f-strings for string formatting
- Use pathlib.Path for file path operations instead of os.path
- Import organization: standard library → third-party → local imports
- Python files must pass ruff check

#### JavaScript
- Use ES6 modules with explicit imports/exports
- Use const/let instead of var
- Use descriptive function and variable names
- Add comments for complex logic, especially in event handlers
- Follow existing file structure: one module per file with clear responsibilities
- JavaScript files must pass `npm lint` and `npm run format:check`

### Testing

Expand Down
56 changes: 56 additions & 0 deletions .github/workflows/lint.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
name: Lint Code

on:
push:
branches: [ master, main ]
pull_request:
branches: [ master, main ]

permissions:
contents: read

jobs:
backend-lint:
name: Backend Linting (Ruff)
runs-on: ubuntu-latest

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.10'

- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install .[development]

- name: Run Ruff
run: |
ruff check photomap tests

frontend-lint:
name: Frontend Linting (ESLint & Prettier)
runs-on: ubuntu-latest

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'

- name: Install dependencies
run: npm ci

- name: Run ESLint
run: npm run lint

- name: Run Prettier check
run: npm run format:check
9 changes: 9 additions & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
node_modules
dist
build
coverage
.pytest_cache
__pycache__
*.min.js
package-lock.json
*.pyc
10 changes: 10 additions & 0 deletions .prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"semi": true,
"trailingComma": "es5",
"singleQuote": false,
"printWidth": 120,
"tabWidth": 2,
"useTabs": false,
"arrowParens": "always",
"endOfLine": "lf"
}
26 changes: 26 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ help:
@echo "docker-demo Build the Docker demo site image."
@echo "docs Serve the mkdocs site with live reload."
@echo "deploy-docs Deploy the mkdocs site to GitHub pages."
@echo "backend-lint Run Python backend linting with Ruff."
@echo "frontend-lint Run JavaScript frontend linting with ESLint and Prettier."
@echo "lint Run both backend and frontend linting."

# Run the unit tests
test:
Expand Down Expand Up @@ -48,3 +51,26 @@ docs:

deploy-docs:
mkdocs gh-deploy

# Run backend linting with Ruff
# fix with ruff check photomap tests photomap --fix
.PHONY: backend-lint
backend-lint:
@echo "Running Ruff on Python backend..."
ruff check photomap tests photomap

# Run frontend linting with ESLint and Prettier
# Fix with npm run lint:fix
# npm run format
.PHONY: frontend-lint
frontend-lint:
@echo "Installing npm dependencies if needed..."
npm install
@echo "Running ESLint on JavaScript frontend..."
npm run lint
@echo "Running Prettier check on JavaScript frontend..."
npm run format:check

# Run both backend and frontend linting
.PHONY: lint
lint: backend-lint frontend-lint
105 changes: 105 additions & 0 deletions eslint.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
export default [
{
ignores: [
'**/node_modules/**',
'**/dist/**',
'**/build/**',
'**/.pytest_cache/**',
'**/__pycache__/**',
'**/coverage/**',
],
},
{
files: ['**/*.js'],
languageOptions: {
ecmaVersion: 2022,
sourceType: 'module',
globals: {
// Browser globals
window: 'readonly',
document: 'readonly',
console: 'readonly',
localStorage: 'readonly',
sessionStorage: 'readonly',
fetch: 'readonly',
FormData: 'readonly',
URLSearchParams: 'readonly',
URL: 'readonly',
setTimeout: 'readonly',
clearTimeout: 'readonly',
setInterval: 'readonly',
clearInterval: 'readonly',
alert: 'readonly',
confirm: 'readonly',
prompt: 'readonly',
CustomEvent: 'readonly',
Event: 'readonly',
MouseEvent: 'readonly',
KeyboardEvent: 'readonly',
TouchEvent: 'readonly',
ResizeObserver: 'readonly',
IntersectionObserver: 'readonly',
MutationObserver: 'readonly',
HTMLElement: 'readonly',
Element: 'readonly',
Node: 'readonly',
NodeList: 'readonly',
Blob: 'readonly',
File: 'readonly',
FileReader: 'readonly',
Image: 'readonly',
navigator: 'readonly',
performance: 'readonly',
requestAnimationFrame: 'readonly',
getComputedStyle: 'readonly',
// Plotly global (used in umap.js)
Plotly: 'readonly',
// Swiper global (used in swiper.js)
Swiper: 'readonly',
},
},
rules: {
// Possible errors
'no-console': 'off',
'no-debugger': 'warn',
'no-unused-vars': ['warn', { argsIgnorePattern: '^_' }],
'no-undef': 'error',

// Best practices
'eqeqeq': ['error', 'always'],
'curly': ['error', 'all'],
'no-eval': 'error',
'no-implied-eval': 'error',
'no-with': 'error',
'no-new-func': 'error',

// ES6+
'prefer-const': 'warn',
'no-var': 'warn',
'prefer-arrow-callback': 'warn',
'arrow-spacing': 'error',

// Style (mostly handled by Prettier, but some logical style rules)
// Note: quotes handled by Prettier, semi retained for logical consistency
'semi': ['error', 'always'],
},
},
{
files: ['tests/**/*.js', '**/*.test.js'],
languageOptions: {
globals: {
// Jest globals
describe: 'readonly',
it: 'readonly',
test: 'readonly',
expect: 'readonly',
beforeEach: 'readonly',
afterEach: 'readonly',
beforeAll: 'readonly',
afterAll: 'readonly',
jest: 'readonly',
global: 'readonly',
},
},
},
];
Loading