# jQuery ESLint Runner

Automated tool for cloning multiple repositories and running ESLint with jQuery breaking change detection rules.

## Quick Start

### Running as a CLI Tool

#### Option 1: NPX (After Publishing to NPM registry)

```bash
npx @atlassian/jquery-eslint-runner --help
npx @atlassian/jquery-eslint-runner lint-directory --directory /path/to/code
```

#### Option 2: Direct Node Execution (Local Testing)

Run individual commands directly:

```bash
# View help
node src/cli.js --help

# Lint a single directory
node src/cli.js lint-directory --directory /path/to/code

# Clone and lint repositories
node src/cli.js clone-and-lint

# Convert results to CSV
node src/cli.js write-csv output.csv
```

### Available Commands

#### `lint-directory` - Lint a Single Directory

Lint a directory with configurable ESLint settings:

```bash
jquery-eslint-runner lint-directory \
  --directory /path/to/project \
  --format json \
  --output results.json
```

**Options:**
- `--directory <path>` - Path to directory to lint (required)
- `--linter-configuration <path>` - ESLint config file (default: `eslint-configs/jira-dc/jquery-v2.js`)
- `--format <string>` - Output format: json, html, stylish, etc (default: `json`)
- `--output <path>` - Output file path (default: `<directory-name>.<format>` in current directory)
- `--fix` - Automatically fix fixable errors (default: false)

**Example:**
```bash
jquery-eslint-runner lint-directory \
  --directory ./src \
  --format json \
  --output lint-results.json \
  --fix
```

#### `clone-and-lint` - Clone and Lint Multiple Repositories

Automated workflow for cloning repositories and linting them:

```bash
jquery-eslint-runner clone-and-lint \
  --repositoriesFile samples/repositories.json \
  --unified-report unified-report.json
```

**Options:**
- `--repositoriesFile <path>` - Repositories config file (default: `samples/repositories.json`)
- `--linter-configuration <path>` - ESLint config file (default: `../../eslint-configs/jira-dc/jquery-v2.js`)
- `--tmp-dir <path>` - Temporary directory for clones (default: `tmp/jquery-eslint-reposetories`)
- `--format <string>` - ESLint output format (default: `json`)
- `--clone <boolean>` - Clone/pull repositories (default: true)
- `--unified-report <path>` - Merged report path (default: `unified-report.json`)
- `--rule-prefix <string>` - Filter by rule prefix, e.g., `jquery-jira` (optional)
- `--max-source-lines <number>` - Max source lines around violations (default: 100)

**Example:**
```bash
jquery-eslint-runner clone-and-lint \
  --repositoriesFile samples/repositories.json \
  --unified-report unified-report.json \
  --rule-prefix jquery-jira \
  --max-source-lines 100
```

#### `write-csv` - Convert ESLint Results to CSV

Convert JSON ESLint results to CSV format:

```bash
jquery-eslint-runner write-csv output.csv \
  --tmp-dir tmp/jquery-eslint-reposetories \
  --filter-pattern jQuery
```

**Options:**
- `<outputFile>` - Output CSV file path (required)
- `--repositoriesFile <path>` - Repositories config file (default: `samples/repositories.json`)
- `--tmp-dir <path>` - Temporary directory with results (default: `tmp/jquery-eslint-reposetories`)
- `--filter-pattern <string>` - Filter pattern for rules (default: `jQuery`)
- `--format <string>` - Input format of ESLint results (default: `json`)

### Testing the Package

#### Test lint-directory command:

```bash
# Lint the eslint-configs directory itself
jquery-eslint-runner lint-directory --directory ./eslint-configs --format json --output test-results.json

# Check the results
cat test-results.json
```

#### Test the CLI help commands:

```bash
# Main help
jquery-eslint-runner --help

# Subcommand help
jquery-eslint-runner lint-directory --help
jquery-eslint-runner clone-and-lint --help
jquery-eslint-runner write-csv --help
```

#### Test with sample repositories:

```bash
# Run clone-and-lint with sample repositories (optional, requires git access)
jquery-eslint-runner clone-and-lint \
  --repositoriesFile samples/repositories.json \
  --tmp-dir ./tmp/test-repos \
  --format json
```

## How `yarn clone-and-lint` Works

The `yarn clone-and-lint` command automates the process of detecting jQuery 3.0 breaking changes across multiple repositories. It reads a repository configuration file (default: `samples/repositories.json`) containing Git repository names and URLs, then clones each repository into a temporary directory (or pulls latest changes if already cloned). For each repository, it spawns an ESLint process with a specified configuration file (default: jQuery v2 breaking changes rules), running with `--no-eslintrc` to ignore project-specific ESLint configs and `--quiet` to show only errors.

The linting results are saved per repository (e.g., `jira.json`, `jira-software.json`) in the specified format (JSON by default, also supports HTML, stylish). When using JSON format with the `--unified-report` option, it merges all individual reports into a single consolidated report, optionally filtering by rule prefix (e.g., `jquery-jira`). The tool intelligently trims source code context to center around violations (configurable via `--max-source-lines`), making reports more focused and manageable. Finally, it splits the unified report by project into individual files under `./report/` directory, organizing results for easier analysis and processing by downstream tools like the analyzer.

**Key Features:**
- Parallel repository cloning and linting
- Configurable ESLint rules and output formats
- Smart source code trimming around violations
- Unified and per-project report generation
- Rule prefix filtering for targeted analysis

## Configuration

Create a `repositories.json` file with your repositories. You can specify a branch to clone/pull by appending `#<branch>` to the repository URL (similar to npm package.json syntax). If no branch is specified, it defaults to `master`.

```json
[
  {
    "repository": {
      "name": "bitbucket.org/atlassian/jira",
      "url": "git@bitbucket.org:atlassian/jira.git"
    }
  },
  {
    "repository": {
      "name": "bitbucket.org/atlassian/confluence",
      "url": "git@bitbucket.org:atlassian/confluence.git#release/9.1"
    }
  }
]
```

## Command Options

```bash
yarn clone-and-lint \
  --repositoriesFile samples/repositories.json \
  --linter-configuration eslint-configs/jira-dc/jquery-v2.js \
  --tmp-dir tmp/repos \
  --format json \
  --clone true \
  --unified-report unified-report.json \
  --rule-prefix jquery-jira \
  --max-source-lines 100
```

- `--repositoriesFile`: Path to repositories JSON file (default: `samples/repositories.json`)
- `--linter-configuration`: Path to ESLint config file (default: `../../eslint-configs/jira-dc/jquery-v2.js`)
- `--tmp-dir`: Temporary directory for cloned repos (default: `tmp/jquery-eslint-repositories`)
- `--format`: ESLint output format - json, html, stylish, etc (default: `json`)
- `--clone`: Whether to clone/pull repositories (default: `true`)
- `--unified-report`: Path for merged JSON report (default: `unified-report.json`)
- `--rule-prefix`: Filter rules by prefix, e.g., `jquery-jira` (optional)
- `--max-source-lines`: Max source lines to include around violations (default: `100`)

## Output

- Individual lint reports: `<repo-name>.json` (or specified format)
- Unified report: `unified-report.json` (merged results from all repos)
- Split reports: `./report/<project-name>/*.json` (organized by project)

## ESLint Configuration - jira-dc Plugin

The `eslint-configs/jira-dc/` directory contains specialized ESLint configurations for detecting jQuery breaking changes in JIRA codebases.

### Available Configurations

**`jquery-v2.js`** - Detects jQuery 1.9+ breaking changes
- Uses `plugin:jquery-breaking-changes/1.9` for standard jQuery 1.9 deprecations
- Includes custom `jquery-jira` rules: `no-ajax-datatype-json`, `no-curcss`
- Suitable for codebases migrating from jQuery 1.x to 2.x

**`jquery-v3.js`** - Detects jQuery 3.0+ breaking changes
- Extends `jquery-v2.js` and adds `plugin:jquery-breaking-changes/3.0`
- Comprehensive `jquery-jira` rules covering:
  - Event methods: `bind-removed`, `unbind-removed`, `delegate-removed`, `undelegate-removed`
  - Utility functions: `jquery-parseJSON-deprecated`, `jquery-unique-deprecated`, `jquery-trim-deprecated`, `jquery-isArray-deprecated`, `jquery-isFunction-deprecated`
  - Traversal methods: `andSelf-removed`
- Disables noisy rules: `context-removed`, `selector-removed`, `return-values-on-empty-sets-are-undefined`, `select-multiple-returns-empty-array`

### Custom Plugin: eslint-plugin-jquery-jira

Located in `eslint-configs/jira-dc/plugins/eslint-plugin-jquery-jira/`, this custom ESLint plugin provides intelligent jQuery detection with reduced false positives:

**Smart Detection Features:**
- **Non-jQuery library filtering**: Recognizes lodash, Backbone, Ramda patterns (e.g., `_.bind()`, `collection.size()`)
- **Function.prototype.bind detection**: Distinguishes `func.bind(this)` from `$el.bind('click', handler)` by analyzing first argument patterns
- **Variable name heuristics**: Uses naming patterns to identify jQuery objects (`$`, `$j`, `jq`, common element names)
- **Context-aware analysis**: Reduces false positives by understanding code context

**Rule Categories:**
1. **Event bindings**: Detects deprecated `.bind()`, `.unbind()`, `.delegate()`, `.undelegate()`
2. **Utility deprecations**: Flags `$.parseJSON()`, `$.unique()`, `$.trim()`, `$.isArray()`, `$.isFunction()`
3. **JIRA-specific**: `no-ajax-datatype-json` (explicit dataType required), `no-curcss` (internal API usage)

**How it’s bundled:** Plugins are loaded by path from the config (no `file:` dependencies). Their runtime dependencies are synced into the runner’s `package.json` by `scripts/sync-plugin-dependencies.js` (run automatically on `preinstall`). See “Bundled plugin dependencies” below.

**Usage:**
```javascript
// In your ESLint config
plugins: ['eslint-plugin-jquery-jira'],
rules: {
  'jquery-jira/bind-removed': 'error',
  'jquery-jira/jquery-parseJSON-deprecated': 'error'
}
```

This plugin is specifically tuned for JIRA codebase patterns, significantly reducing false positives compared to generic jQuery linting rules.

## Bundled plugin dependencies

ESLint configs load plugins by path (`eslint-configs/jira-dc/plugins/...`), so the runner must declare those plugins’ runtime dependencies.

- **When adding a new plugin:** put it in `eslint-configs/jira-dc/plugins/<plugin-name>/` (or add a `copyFiles` entry if it’s copied from node_modules).

## Release

1. You'll need to first get package publishing permissions with `atlas packages permission grant`.
2. Remember to add a changelog entry in `CHANGELOG.md` and create a tag in the repo matching the version.
3. Run `npm publish --tag alpha` for testing version only in PAC or `npm publish --userconfig=~/.npmrc-public` for release to public PAC and npm (see https://hello.atlassian.net/wiki/spaces/~zxu2/pages/5795449397/How+to+locally+npm+publish+to+public+npm+2025+mid).
4. Then create a PR bumping the package version in `package.json` for the next development iteration.

## License

Copyright (c) 2025 Atlassian US., Inc.
Apache 2.0 licensed, see [LICENSE](./LICENSE) file.