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: 1 addition & 1 deletion .github/ISSUE_TEMPLATE/bug_report.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name: Bug report
description: Something in Workspace File Bookmarks isn't working as expected
labels: ["bug"]
labels: ['bug']
body:
- type: textarea
id: description
Expand Down
2 changes: 1 addition & 1 deletion .github/ISSUE_TEMPLATE/feature_request.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name: Feature request
description: Suggest a feature or improvement for Workspace File Bookmarks
labels: ["enhancement"]
labels: ['enhancement']
body:
- type: textarea
id: problem
Expand Down
18 changes: 18 additions & 0 deletions .github/PULL_REQUEST_TEMPLATE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
## Summary

<!-- What does this PR do, and why? Link the issue it closes, if any. -->

## Testing

<!-- How did you verify this? Include commands run and their output/result. -->

## Checklist

- [ ] PR title follows [Conventional Commits](https://www.conventionalcommits.org/) (enforced by `pr-title-lint.yml`)
- [ ] `npm run lint` passes (`tsc --noEmit` + `eslint .`)
- [ ] `npm run format:check` passes
- [ ] `npm run test` passes, and `npm run test:coverage` / `scripts/local-patch-report.sh` shows patch coverage ≥85%
- [ ] `npm run build` passes
- [ ] New/changed user-facing commands or tree behavior have `test/e2e/*.test.ts` coverage in addition to unit tests
- [ ] `npm run test:e2e` passes locally
- [ ] No new high/critical findings from `npm audit --audit-level=high` or CodeQL
3 changes: 3 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,9 @@ jobs:
- name: Lint
run: npm run lint

- name: Format check
run: npm run format:check

- name: Test with coverage
run: npm run test:coverage

Expand Down
8 changes: 4 additions & 4 deletions .github/workflows/renovate_prune.yml
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
name: "Prune Renovate Branches"
name: 'Prune Renovate Branches'

on:
workflow_dispatch:
schedule:
- cron: '0 3 * * *' # daily at 03:00 UTC
- cron: '0 3 * * *' # daily at 03:00 UTC

permissions:
contents: write # required to delete branch refs
contents: write # required to delete branch refs
pull-requests: read

jobs:
Expand All @@ -17,7 +17,7 @@ jobs:
cancel-in-progress: true

env:
BRANCH_PREFIX: "renovate/" # adjust if you use a different prefix
BRANCH_PREFIX: 'renovate/' # adjust if you use a different prefix

steps:
- name: Prune renovate branches
Expand Down
8 changes: 8 additions & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
dist/
coverage/
out-e2e/
.vscode-test/
node_modules/
*.md
*.vsix
package-lock.json
6 changes: 6 additions & 0 deletions .prettierrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"singleQuote": true,
"printWidth": 100,
"tabWidth": 2,
"trailingComma": "all"
}
12 changes: 6 additions & 6 deletions .vscode-test.mjs
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { defineConfig } from '@vscode/test-cli';

export default defineConfig({
files: 'out-e2e/**/*.test.js',
workspaceFolder: 'test/e2e/fixtures/workspace',
mocha: {
ui: 'bdd',
timeout: 20000
}
files: 'out-e2e/**/*.test.js',
workspaceFolder: 'test/e2e/fixtures/workspace',
mocha: {
ui: 'bdd',
timeout: 20000,
},
});
10 changes: 7 additions & 3 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,13 @@ drives versioning and publishing off Conventional Commit prefixes on `main`.

Every change is expected to clear this bar before it's mergeable:

- **CI clean.** `npm run lint` (`tsc --noEmit`), `npm run test`,
`npm run build`, and `npm run test:e2e` all pass — see
`.github/workflows/ci.yml`.
- **CI clean.** `npm run lint` (`npm run lint:types` — `tsc --noEmit` —
followed by `npm run lint:style` — `eslint .`), `npm run format:check`,
`npm run test`, `npm run build`, and `npm run test:e2e` all pass — see
`.github/workflows/ci.yml`. `lefthook` runs the same lint/format checks and
the unit suite locally on `pre-commit` against staged files (installed
automatically via the `postinstall` script after `npm install`; see
`lefthook.yml`), so most of this is caught before it ever reaches CI.
- **Unit coverage ≥85%, both patch and project.** Codecov enforces this on
every PR (`codecov.yml`: `project` and `patch`, both `target: 85%,
threshold: 1%`), reported from `npm run test:coverage` (vitest + v8,
Expand Down
80 changes: 80 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
# Contributing

Thanks for considering a contribution to Workspace File Bookmarks. This
document covers the workflow, tooling, and quality bar a PR is expected to
meet.

## Branching model

- Branch off `development`, not `main` — `main` only moves via
`development` → `main` promotion or direct CI/hotfix commits.
- Feature work happens on `feature/**` branches, one PR per feature. A PR
may be split into multiple commits, but don't merge a feature that isn't
complete. If your change spans multiple unrelated features, split it into
multiple PRs rather than combining them.
- `development` batches dependency and small maintenance updates so a merge
into `main` doesn't trigger a release per commit. Once `development`'s CI
is green, a weekly `promote-dev-to-main` PR opens the other direction.
- release-please drives versioning and changelog generation off Conventional
Commit prefixes on `main` — see [Commit messages](#commit-messages) below.

## Getting started

```bash
npm install # also wires up lefthook's pre-commit checks
npm run build # bundle extension.ts -> dist/extension.cjs
npm run watch # rebuild on change
```

Press `F5` in VS Code to launch an Extension Development Host with the
extension loaded, so you can exercise your change interactively.

## Commit messages / PR titles

PR titles must follow [Conventional Commits](https://www.conventionalcommits.org/)
(`feat:`, `fix:`, `chore:`, `docs:`, etc.) — this is enforced by
`.github/workflows/pr-title-lint.yml` and is what release-please uses to
decide the next version and changelog entry on `main`.

## Definition of Done

Every change is expected to clear this bar before it's mergeable:

- **CI clean.** `npm run lint` (type-check via `tsc --noEmit`, then
`eslint .`), `npm run format:check`, `npm run test`, `npm run build`, and
`npm run test:e2e` all pass — see `.github/workflows/ci.yml`.
- **Unit coverage ≥85%, both patch and project.** Codecov enforces this on
every PR (`codecov.yml`), reported from `npm run test:coverage` (vitest +
v8; `vitest.config.mts` mirrors the same 85% thresholds so a local run
fails the same way CI's will). Before pushing, run
`scripts/local-patch-report.sh` — it diffs your branch against
`origin/development`, regenerates a fresh coverage profile, and reports
the same changed-lines coverage number Codecov's patch gate computes, so a
real gap shows up before a CI round-trip instead of after. Write real
tests that close gaps for real — no padding, no vacuous assertions just to
move a number.
- **New features carry e2e coverage, not just unit tests.** Unit tests
(vitest, against `test/vscode-mock.ts`) cover logic in isolation;
`test/e2e/*.test.ts` (mocha, via `@vscode/test-cli` + `@vscode/test-electron`)
runs the real, built extension inside an actual VS Code Extension
Development Host. Any new user-facing command or tree behavior needs both:
a unit test for the logic and an e2e test exercising it end-to-end. Run
locally with `npm run test:e2e` (needs a display, or `xvfb-run -a npm run
test:e2e` on headless Linux).
- **Security scanning clean.** CodeQL runs on every push/PR
(`.github/workflows/codeql.yml`); `npm audit --audit-level=high` gates
dependency updates on high/critical findings.

## Local pre-commit checks

`npm install` runs [lefthook](https://github.com/evilmartians/lefthook)'s
`postinstall` hook, which installs a `pre-commit` hook (see `lefthook.yml`)
that runs lint, format, and the unit suite against your staged files. This
catches most Definition of Done violations before they reach CI — if it's
slow or wrong, please open an issue rather than routinely bypassing it with
`--no-verify`.

## Opening a PR

Fill out the PR template's checklist — it mirrors the Definition of Done
above. Link the issue it closes, if any.
9 changes: 7 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,16 @@ This extension is early — I'm actively looking for feedback on what's useful a
npm install
npm run build # bundle extension.ts -> dist/extension.cjs
npm run watch # rebuild on change
npm run lint # type-check only
npm run lint # type-check (tsc) + eslint
npm run format # prettier --write
```

Press `F5` in VS Code to launch an Extension Development Host with the extension loaded.

`npm install` also wires up [lefthook](https://github.com/evilmartians/lefthook) to
run lint/format/test checks on `pre-commit`. See [CONTRIBUTING.md](CONTRIBUTING.md)
for the full workflow and Definition of Done.

## Packaging / local install

```bash
Expand All @@ -51,4 +56,4 @@ npm run package # builds, packages a .vsix, and installs it into VS Code / In

## Roadmap

Renaming/tagging bookmarks, reordering, and drag-and-drop.
Renaming/tagging bookmarks, reordering, drag-and-drop, a quick-filter search box, and nested (sub-)folders are all shipped.
20 changes: 10 additions & 10 deletions codecov.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,17 +22,17 @@ comment:
require_changes: false
require_base: false
require_head: true
layout: "reach, diff, flags, files"
layout: 'reach, diff, flags, files'
behavior: default

# Keep in sync with scripts/local-patch-report.sh's own exclude list.
ignore:
- "test/**"
- "**/*.test.ts"
- "**/*.d.ts"
- "scripts/**"
- "*.md"
- ".github/**"
- "vitest.config.mts"
- "dist/**"
- "coverage/**"
- 'test/**'
- '**/*.test.ts'
- '**/*.d.ts'
- 'scripts/**'
- '*.md'
- '.github/**'
- 'vitest.config.mts'
- 'dist/**'
- 'coverage/**'
19 changes: 19 additions & 0 deletions eslint.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// @ts-check
import js from '@eslint/js';
import tseslint from 'typescript-eslint';
import eslintConfigPrettier from 'eslint-config-prettier';

export default tseslint.config(
{
ignores: ['dist/**', 'coverage/**', 'out-e2e/**', '.vscode-test/**', 'node_modules/**'],
},
js.configs.recommended,
...tseslint.configs.recommended,
{
rules: {
'@typescript-eslint/no-unused-vars': ['warn', { argsIgnorePattern: '^_' }],
'@typescript-eslint/no-explicit-any': 'off',
},
},
eslintConfigPrettier,
);
Loading