diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..9d885a0 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,16 @@ +root = true + +[*] +charset = utf-8 +end_of_line = lf +indent_style = space +indent_size = 2 +insert_final_newline = true +trim_trailing_whitespace = true + +[*.md] +trim_trailing_whitespace = false + +[*.{png,svg,vsix}] +insert_final_newline = false +trim_trailing_whitespace = false diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 0000000..a639765 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,11 @@ +blank_issues_enabled: false +contact_links: + - name: Security vulnerability + url: https://github.com/krotname/VsCodeMarkdownTableEditor/security/advisories/new + about: Report privately through GitHub security advisories instead of a public issue. + - name: Question or usage help + url: https://github.com/krotname/VsCodeMarkdownTableEditor/discussions + about: Ask about behavior, shortcuts, or settings. + - name: Other editions + url: https://markdowntableeditor.ru/ + about: The same table engine for JetBrains IDEs and Notepad++. diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml new file mode 100644 index 0000000..4fde2f4 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.yml @@ -0,0 +1,30 @@ +name: Feature request +description: Suggest a table editing capability or a change to an existing command +title: '[Feature]: ' +labels: [enhancement] +body: + - type: textarea + id: problem + attributes: + label: Problem + description: What does editing a table cost you today? + validations: + required: true + - type: textarea + id: proposal + attributes: + label: Proposed behavior + description: Include a before and after table if the change affects table output. + render: markdown + validations: + required: true + - type: dropdown + id: parity + attributes: + label: Should the JetBrains and Notepad++ editions behave the same way? + options: + - Yes, this belongs in the shared table engine + - No, this is specific to VS Code + - Not sure + validations: + required: true diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..7a9b46d --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,17 @@ +## User impact + + + +## Validation + + + +- [ ] `npm run check` +- [ ] `npm run test:coverage` +- [ ] `npm run test:e2e` +- [ ] `npm run package` (only when packaging or manifest metadata changed) + +## Core parity + +- [ ] No change to `src/core.ts` behavior, or the shared golden fixture and the JetBrains and + Notepad++ repositories were updated together with this change. diff --git a/.github/workflows/actionlint.yml b/.github/workflows/actionlint.yml new file mode 100644 index 0000000..2216cbc --- /dev/null +++ b/.github/workflows/actionlint.yml @@ -0,0 +1,23 @@ +name: Actionlint + +on: + push: + paths: + - '.github/workflows/**' + pull_request: + paths: + - '.github/workflows/**' + workflow_dispatch: + +permissions: + contents: read + +jobs: + actionlint: + name: Lint workflows + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false + - uses: raven-actions/actionlint@3d39aea434753780c3b3d4a1a31c854b4dbf49d7 # v2.2.0 diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3886ee2..ccd2add 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -18,8 +18,10 @@ jobs: name: Unit, contract, coverage, build runs-on: ubuntu-latest steps: - - uses: actions/checkout@v7 - - uses: actions/setup-node@v7 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false + - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 with: node-version: 24 cache: npm @@ -28,7 +30,7 @@ jobs: - run: npm run typecheck - run: npm run test:coverage - run: npm run build - - uses: actions/upload-artifact@v7 + - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: coverage path: coverage/lcov.info @@ -41,8 +43,10 @@ jobs: matrix: os: [ubuntu-latest, windows-latest] steps: - - uses: actions/checkout@v7 - - uses: actions/setup-node@v7 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false + - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 with: node-version: 24 cache: npm @@ -59,8 +63,10 @@ jobs: needs: [quality, e2e] runs-on: ubuntu-latest steps: - - uses: actions/checkout@v7 - - uses: actions/setup-node@v7 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false + - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 with: node-version: 24 cache: npm @@ -68,7 +74,7 @@ jobs: - run: npm run package - run: npm run test:vsix - run: sha256sum build/markdown-table-editor.vsix > build/SHA256SUMS.txt - - uses: actions/upload-artifact@v7 + - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: markdown-table-editor-vsix path: | diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index a7180c4..78b986f 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -20,24 +20,26 @@ jobs: name: JavaScript/TypeScript runs-on: ubuntu-latest steps: - - uses: actions/checkout@v7 - - uses: github/codeql-action/init@v4.37.4 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false + - uses: github/codeql-action/init@5595ccaf912efad79be6eef63a5619ff05969be3 # v4.37.6 with: languages: javascript-typescript - - uses: actions/setup-node@v7 + - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 with: node-version: 24 cache: npm - run: npm ci - run: npm run build - - uses: github/codeql-action/analyze@v4.37.4 + - uses: github/codeql-action/analyze@5595ccaf912efad79be6eef63a5619ff05969be3 # v4.37.6 with: upload: never upload-database: false output: codeql-results - name: Fail on CodeQL findings run: node scripts/check-sarif.mjs codeql-results - - uses: actions/upload-artifact@v7 + - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 if: always() with: name: codeql-sarif diff --git a/.github/workflows/dependency-review.yml b/.github/workflows/dependency-review.yml new file mode 100644 index 0000000..498357b --- /dev/null +++ b/.github/workflows/dependency-review.yml @@ -0,0 +1,20 @@ +name: Dependency Review + +# Pull request only: the action compares the base and head of a pull request, and a +# workflow_dispatch run has no such refs to compare. +on: + pull_request: + +permissions: + contents: read + pull-requests: read + +jobs: + dependency-review: + name: Review dependency changes + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false + - uses: actions/dependency-review-action@a1d282b36b6f3519aa1f3fc636f609c47dddb294 # v5.0.0 diff --git a/.github/workflows/publish-marketplace.yml b/.github/workflows/publish-marketplace.yml new file mode 100644 index 0000000..fe0afe2 --- /dev/null +++ b/.github/workflows/publish-marketplace.yml @@ -0,0 +1,142 @@ +name: Publish to VS Code Marketplace + +on: + workflow_dispatch: + inputs: + version: + description: Extension version without leading v; must match package.json. + required: true + type: string + mode: + description: Dry-run builds and verifies the VSIX; publish uploads it to the Marketplace. + required: true + default: dry-run + type: choice + options: + - dry-run + - publish + confirmation: + description: For publish, type markdown-table-editor:. + required: false + type: string + +permissions: + contents: read + +concurrency: + group: markdown-table-editor-marketplace + cancel-in-progress: false + +jobs: + # Runs for both modes and never sees the Marketplace token: workflow_dispatch takes the workflow + # file and the build scripts from the dispatched ref, so anything reachable here is untrusted. + verify: + name: Verify ${{ inputs.version }} + runs-on: ubuntu-latest + timeout-minutes: 30 + env: + RELEASE_VERSION: ${{ inputs.version }} + RELEASE_MODE: ${{ inputs.mode }} + RELEASE_CONFIRMATION: ${{ inputs.confirmation }} + RELEASE_REF: ${{ github.ref }} + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false + + - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 + with: + node-version: 24 + cache: npm + + - name: Validate release request + run: | + set -euo pipefail + if ! [[ "$RELEASE_VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then + echo "Invalid version: '$RELEASE_VERSION'." >&2 + exit 1 + fi + manifest_version="$(node -p "require('./package.json').version")" + if [ "$RELEASE_VERSION" != "$manifest_version" ]; then + echo "Requested version '$RELEASE_VERSION' does not match package.json '$manifest_version'." >&2 + exit 1 + fi + if [ "$RELEASE_MODE" = publish ]; then + if [ "$RELEASE_REF" != refs/heads/main ]; then + echo "Publishing is allowed only from refs/heads/main; got '$RELEASE_REF'." >&2 + exit 1 + fi + if [ "$RELEASE_CONFIRMATION" != "markdown-table-editor:$RELEASE_VERSION" ]; then + echo "Publish confirmation must exactly match 'markdown-table-editor:$RELEASE_VERSION'." >&2 + exit 1 + fi + fi + echo "Validated $RELEASE_MODE request for markdown-table-editor:$RELEASE_VERSION." + + - run: npm ci + # npm run package runs typecheck, unit tests, and the bundle build before vsce package. + - run: npm run package + - run: npm run test:vsix + + - name: Record the artifact checksum + run: sha256sum build/markdown-table-editor.vsix > build/SHA256SUMS.txt + + - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 + with: + name: marketplace-${{ inputs.version }}-${{ inputs.mode }} + path: | + build/markdown-table-editor.vsix + build/SHA256SUMS.txt + if-no-files-found: error + retention-days: 14 + + # The token lives in the "marketplace" environment, which requires reviewer approval and is + # limited to protected branches. Dropping the environment from this job would also drop access + # to the secret, so the gate cannot be removed by pushing a modified workflow to a side branch. + publish: + name: Publish ${{ inputs.version }} + needs: verify + if: ${{ inputs.mode == 'publish' }} + runs-on: ubuntu-latest + timeout-minutes: 30 + environment: marketplace + env: + RELEASE_VERSION: ${{ inputs.version }} + RELEASE_REF: ${{ github.ref }} + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false + + - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 + with: + node-version: 24 + cache: npm + + - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 + with: + name: marketplace-${{ inputs.version }}-publish + path: build + + - name: Confirm the publish ref, artifact, and secret + env: + VSCE_PAT: ${{ secrets.VSCE_PAT }} + run: | + set -euo pipefail + if [ "$RELEASE_REF" != refs/heads/main ]; then + echo "Publishing is allowed only from refs/heads/main; got '$RELEASE_REF'." >&2 + exit 1 + fi + if [ -z "${VSCE_PAT:-}" ]; then + echo "Required environment secret 'VSCE_PAT' is missing." >&2 + exit 1 + fi + sha256sum --check build/SHA256SUMS.txt + echo "Publishing markdown-table-editor:$RELEASE_VERSION from main." + + - run: npm ci + + - name: Publish the verified VSIX + env: + VSCE_PAT: ${{ secrets.VSCE_PAT }} + run: npx --no-install vsce publish --packagePath build/markdown-table-editor.vsix diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 974a92c..6072bad 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -13,8 +13,10 @@ jobs: release: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v7 - - uses: actions/setup-node@v7 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false + - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 with: node-version: 24 cache: npm @@ -22,7 +24,7 @@ jobs: - run: npm run test:coverage - run: npm run package - run: sha256sum build/markdown-table-editor.vsix > build/SHA256SUMS.txt - - uses: actions/attest-build-provenance@v4 + - uses: actions/attest-build-provenance@0f67c3f4856b2e3261c31976d6725780e5e4c373 # v4.1.1 with: subject-path: build/markdown-table-editor.vsix - name: Create GitHub release diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml new file mode 100644 index 0000000..9be27b3 --- /dev/null +++ b/.github/workflows/scorecard.yml @@ -0,0 +1,45 @@ +name: OpenSSF Scorecard + +on: + branch_protection_rule: + push: + branches: [main] + schedule: + - cron: '23 3 * * 1' + workflow_dispatch: + +permissions: read-all + +jobs: + scorecard: + name: OSSF Scorecards + runs-on: ubuntu-latest + timeout-minutes: 15 + permissions: + actions: read + checks: read + contents: read + id-token: write + issues: read + pull-requests: read + security-events: write + statuses: read + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false + - name: Run Scorecard + uses: ossf/scorecard-action@2d1146689b8cda280b9bc96326124645441f03bc # v2.4.4 + with: + results_file: scorecard-results.sarif + results_format: sarif + publish_results: true + - name: Upload Scorecard SARIF + uses: github/codeql-action/upload-sarif@5595ccaf912efad79be6eef63a5619ff05969be3 # v4.37.6 + with: + sarif_file: scorecard-results.sarif + - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 + with: + name: openssf-scorecard + path: scorecard-results.sarif + if-no-files-found: error diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..e2b171a --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,24 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "name": "Run Extension", + "type": "extensionHost", + "request": "launch", + "args": ["--extensionDevelopmentPath=${workspaceFolder}"], + "outFiles": ["${workspaceFolder}/dist/**/*.js"], + "preLaunchTask": "npm: build" + }, + { + "name": "Extension Host E2E", + "type": "extensionHost", + "request": "launch", + "args": [ + "--extensionDevelopmentPath=${workspaceFolder}", + "--extensionTestsPath=${workspaceFolder}/dist/e2e/index.js" + ], + "outFiles": ["${workspaceFolder}/dist/**/*.js"], + "preLaunchTask": "npm: build" + } + ] +} diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 0000000..42be9d8 --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,24 @@ +{ + "version": "2.0.0", + "tasks": [ + { + "type": "npm", + "script": "build", + "group": { "kind": "build", "isDefault": true }, + "problemMatcher": [] + }, + { + "type": "npm", + "script": "watch", + "isBackground": true, + "group": "build", + "problemMatcher": [] + }, + { + "type": "npm", + "script": "test", + "group": { "kind": "test", "isDefault": true }, + "problemMatcher": ["$tsc"] + } + ] +} diff --git a/CHANGELOG.md b/CHANGELOG.md index df72e92..3593da1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,14 +4,23 @@ All notable changes follow [Keep a Changelog](https://keepachangelog.com/en/1.1. ## [Unreleased] +## [0.2.0] - 2026-08-04 + +### Added + +- Marketplace metadata for the first public release: gallery banner, Q&A link, free pricing, + and declared support for untrusted and virtual workspaces. + +### Changed + +- The extension activates on Markdown documents, so light auto align and the status-bar + toggles are live as soon as a Markdown file is opened instead of after the first command. + ### Fixed - Fit Width and the manual narrow/widen actions no longer merge sparse rows that wrapping could not have produced, so distinct records survive power auto fit. Rows that wrapping did produce are still rejoined. - -### Fixed - - The table core is now a faithful port of the shared JetBrains/Notepad++ engine and matches it byte for byte across the differential corpus. This corrects several behaviours that diverged: - Prose that merely contains a pipe is no longer swallowed into the table and rewritten. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index e3a035a..12c8e35 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,5 +1,7 @@ # Contributing +Participation is covered by the [Code of Conduct](CODE_OF_CONDUCT.md). + 1. Create a focused branch from `main`. 2. Run `npm ci` and make the smallest coherent change. 3. Add or update contract tests. Core behavior changes must also update the canonical fixtures in the JetBrains and Notepad++ repositories. @@ -7,3 +9,27 @@ 5. Open a pull request explaining the user impact and validation. Do not commit generated `dist`, `build`, coverage, downloaded VS Code runtimes, credentials, or private document data. + +## Layout + +- `src/core.ts` — the editor-independent table engine, a port of the shared JetBrains/Notepad++ core. + It has no VS Code imports, so it can be tested on plain Node.js. +- `src/extension.ts` — the VS Code bindings: commands, keybindings, automatic modes, status bar. +- `test/` — unit, contract, golden, and parity suites run by `tsx --test`. +- `e2e/` — the suite that runs inside a real Extension Host through `@vscode/test-electron`. +- `scripts/` — build, packaging, and verification helpers; no build tool beyond Node.js and esbuild. + +Behavior shared with the other editions belongs in `src/core.ts` and must stay byte-for-byte +compatible with `test-fixtures/markdown-table-core-golden.json`. + +Opening the repository in VS Code and pressing `F5` builds the bundle and launches an Extension +Development Host with the extension loaded; the second launch configuration runs the E2E suite in +the same way the `test:e2e` script does. + +## Releasing + +1. Update `CHANGELOG.md` and the `version` field in `package.json` in one pull request. +2. After it is merged, tag the merge commit as `v` and push the tag. The release workflow + builds the VSIX, records `SHA256SUMS.txt`, attests build provenance, and creates the GitHub release. +3. Publish to the Marketplace with the **Publish to VS Code Marketplace** workflow as described in + [MARKETPLACE_SUBMISSION.md](MARKETPLACE_SUBMISSION.md): `dry-run` first, then `publish`. diff --git a/MARKETPLACE_SUBMISSION.md b/MARKETPLACE_SUBMISSION.md new file mode 100644 index 0000000..7979ad2 --- /dev/null +++ b/MARKETPLACE_SUBMISSION.md @@ -0,0 +1,77 @@ +# Visual Studio Marketplace submission + +Status: release metadata for version `0.2.0`, the first public Marketplace submission. +Keep the version here in sync with `package.json`; the publish workflow refuses a mismatch. + +## Artifact + +- Version: `0.2.0` +- VSIX: `build/markdown-table-editor.vsix`, produced by `npm run package` +- Checksum: `build/SHA256SUMS.txt`, produced by the release and publish workflows +- Marketplace item: fill after upload +- Marketplace verification status: fill after upload +- GitHub release: fill after tagging `v0.2.0` + +## Extension metadata + +- Extension identifier: `krotname.markdown-table-editor` +- Display name: `Markdown Table Editor` +- Publisher: `krotname` +- Categories: `Formatters`, `Other` +- Keywords: `markdown`, `table`, `formatter`, `csv`, `tsv` +- VS Code compatibility: `^1.96.0` +- Extension kind: `ui`, `workspace` (no workspace file system access) +- Workspace trust: supported in untrusted workspaces +- Virtual workspaces: supported +- Pricing: free +- License: `GPL-3.0-or-later` +- License URL: `https://github.com/krotname/VsCodeMarkdownTableEditor/blob/main/LICENSE` +- Repository: `https://github.com/krotname/VsCodeMarkdownTableEditor` +- Issues and Q&A: `https://github.com/krotname/VsCodeMarkdownTableEditor/issues` +- Project site: `https://markdowntableeditor.ru/` + +## Short description + +Edit Markdown pipe tables directly in VS Code: align with `Tab`, fit the table width, narrow or +widen columns, sort rows, convert CSV/TSV, insert tables by size, and move rows or columns without +leaving the editor. Everything runs locally, with no telemetry and no network access. + +## Marketplace release notes for 0.2.0 + +```markdown +- The table engine is a faithful port of the shared JetBrains/Notepad++ core and matches it byte + for byte across the differential corpus, correcting table detection, header protection, caret + placement, width fitting, and CSV/TSV whitespace handling. +- Fit Width and the manual narrow/widen actions keep sparse rows that wrapping could not have + produced, so distinct records survive Power Auto Fit. +- The extension activates on Markdown documents, so Light Auto Align and the status-bar toggles + are live as soon as a Markdown file is opened. +``` + +## Automated submission + +Run the **Publish to VS Code Marketplace** workflow from `main`: start with `dry-run`, then use +`publish` with the confirmation `markdown-table-editor:0.2.0`. The verify job builds the VSIX, +installs it into a throwaway VS Code profile, and records a checksum without ever seeing the +Marketplace token. The publish job then waits for approval in the `marketplace` GitHub environment, +which holds the `VSCE_PAT` secret, verifies the checksum of the artifact built by the verify job, +and uploads exactly that file with `vsce publish --packagePath`. + +Locally the same upload is `npx vsce publish --packagePath build/markdown-table-editor.vsix` with +`VSCE_PAT` set in the environment. + +## Manual submission + +1. Sign in at with the Microsoft account that owns + the `krotname` publisher, creating the publisher first if it does not exist. +2. Open the publisher page and choose `New extension` / `Visual Studio Code`. +3. Upload `build/markdown-table-editor.vsix`. +4. Confirm that the rendered README, icon, categories, license, and repository links are correct. +5. Wait for the automated Marketplace verification to finish and record the resulting status above. + +## Token note + +Publishing requires an Azure DevOps personal access token with `Marketplace → Manage` scope, issued +for **all accessible organizations**. Store it outside the repository (`secrets.txt` is git-ignored) +and in the `marketplace` GitHub environment as `VSCE_PAT`. Never commit or paste the token into the +repository, an issue, or a pull request. diff --git a/README.en.md b/README.en.md index d276274..698eeda 100644 --- a/README.en.md +++ b/README.en.md @@ -1,30 +1,111 @@ # Markdown Table Editor for Visual Studio Code [![CI](https://github.com/krotname/VsCodeMarkdownTableEditor/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/krotname/VsCodeMarkdownTableEditor/actions/workflows/ci.yml) -[![CodeQL](https://github.com/krotname/VsCodeMarkdownTableEditor/actions/workflows/codeql.yml/badge.svg?branch=main)](https://github.com/krotname/VsCodeMarkdownTableEditor/actions/workflows/codeql.yml) +[![CodeQL](https://github.com/krotname/VsCodeMarkdownTableEditor/actions/workflows/codeql.yml/badge.svg?branch=main)](https://github.com/krotname/VsCodeMarkdownTableEditor/actions/workflows/codeql.yml?query=branch%3Amain) +[![OpenSSF Scorecard](https://api.securityscorecards.dev/projects/github.com/krotname/VsCodeMarkdownTableEditor/badge)](https://securityscorecards.dev/viewer/?uri=github.com/krotname/VsCodeMarkdownTableEditor) +[![Release](https://img.shields.io/github/v/release/krotname/VsCodeMarkdownTableEditor?label=release)](https://github.com/krotname/VsCodeMarkdownTableEditor/releases/latest) [![License](https://img.shields.io/github/license/krotname/VsCodeMarkdownTableEditor)](LICENSE) +[![Website](https://img.shields.io/badge/website-markdowntableeditor.ru-0f766e)](https://markdowntableeditor.ru/) -A native VS Code extension for fast GitHub-flavored Markdown table editing. `Tab` aligns the table under the cursor and remains the normal Tab command outside tables. +Markdown Table Editor turns VS Code into a comfortable Markdown table editor. Take a crooked table +written by hand or generated by an AI, press `Tab`, and the extension aligns the columns while +keeping the Markdown intact — then helps you move rows, columns, and data without leaving the editor. -The dependency-free TypeScript core is checked against the same `markdown-table-core-golden.json` used by the [JetBrains IDE](https://github.com/krotname/IdeaMarkdownTableEditor) and [Notepad++](https://github.com/krotname/NppMarkdownTableEditor) versions. +**Quick start:** [download the VSIX from the latest release](https://github.com/krotname/VsCodeMarkdownTableEditor/releases/latest) · +[open the project site](https://markdowntableeditor.ru/) · +[README на русском](README.md) + +The Visual Studio Marketplace listing is in preparation; until then the extension installs from the VSIX. + +## Other editions + +- For JetBrains IDEs: [IdeaMarkdownTableEditor](https://github.com/krotname/IdeaMarkdownTableEditor) + ([JetBrains Marketplace](https://plugins.jetbrains.com/plugin/32159-markdown-table-editor)) +- For Notepad++: [NppMarkdownTableEditor](https://github.com/krotname/NppMarkdownTableEditor) + +All three editions share the same core behavior and are checked against the same +`markdown-table-core-golden.json` fixture, so a table looks identical in every editor. + +## What it looks like + +Before, a hand-written table: + +```markdown +| Команда | Клавиши | Что делает | +|---|:---:|---| +| Align Table | Ctrl+Alt+Shift+1 | выравнивает таблицу под курсором | +| Sort Rows Ascending | Command Palette | сортирует строки по колонке | +| 変換 CSV/TSV | Ctrl+Alt+Shift+0 | превращает CSV или TSV в таблицу | +``` + +After a single `Tab` inside the table: + +```markdown +| Команда | Клавиши | Что делает | +| ------------------- | :--------------: | -------------------------------- | +| Align Table | Ctrl+Alt+Shift+1 | выравнивает таблицу под курсором | +| Sort Rows Ascending | Command Palette | сортирует строки по колонке | +| 変換 CSV/TSV | Ctrl+Alt+Shift+0 | превращает CSV или TSV в таблицу | +``` + +Alignment comes from the separator row and is preserved, and widths are measured in display +columns: CJK and emoji take two columns, combining marks take none. + +Pasted CSV becomes a table through `Convert CSV/TSV to Table`, including quoted fields that +contain the delimiter: + +```markdown +| name | role | city | +| -------------- | ---------- | ------ | +| Ovcharenko, A. | maintainer | Moscow | +| lena | reviewer | Sochi | +``` + +`Fit Table Width to Editor` shrinks the table to the configured width and physically wraps long +cells without changing what each row means: + +```markdown +| Режим | Что делает | +| ----- | ---------------------------------------------------- | +| Light | выравнивает таблицу через мгновение после правки, не | +| Auto | трогая ширину колонок | +| Align | | +| Power | дополнительно ужимает таблицу до заданной ширины и | +| Auto | переносит длинные ячейки | +| Fit | | +``` + +## Why use it + +- No need to leave VS Code for a dedicated table editor. +- Large pipe tables stay readable in plain text, not only in the preview. +- `Tab`, sorting, and row or column operations remove manual alignment work. +- CSV/TSV from an email or an export becomes a tidy Markdown table in one command. +- Everything runs locally: no telemetry, no network requests, no account. ## Features -- Unicode-aware alignment for CJK, emoji, combining marks, and escaped pipes; -- next/previous cell navigation with automatic row creation; -- insert, delete, and move rows and columns; -- resize columns and physically wrap long cells; -- numeric and Unicode-aware sorting; -- strict CSV/TSV conversion, including quoted and multiline fields; -- insert a new table; -- Light Auto Align and Power Auto Fit; -- fully local operation with no telemetry or extension-originated network requests. +- `Tab` aligns the table under the cursor and stays the regular `Tab` everywhere else. +- Unicode-aware alignment for CJK, emoji, combining marks, and escaped `\|`. +- Next and previous cell navigation that appends a row at the end of the table. +- Insert, delete, and move rows and columns. +- Narrow or widen a column and physically wrap long cells. +- Numeric and Unicode-aware row sorting by the column under the cursor. +- Strict CSV and TSV conversion, including quoted and multiline fields. +- Insert a new table of a given size. +- Light Auto Align and Power Auto Fit with status-bar toggles. -## Install a local VSIX +## Install -1. Run `npm run package`. -2. Open `Extensions: Install from VSIX...` in VS Code. -3. Select `build/markdown-table-editor.vsix`. +From a VSIX: + +1. Download `markdown-table-editor.vsix` from the [latest release](https://github.com/krotname/VsCodeMarkdownTableEditor/releases/latest) + or build it locally with `npm run package`. +2. Run `Extensions: Install from VSIX...` in VS Code. +3. Select the downloaded or built `markdown-table-editor.vsix`. + +Every released VSIX ships with a `SHA256SUMS.txt` file and a GitHub Actions build provenance +attestation. ## Commands @@ -41,17 +122,33 @@ The dependency-free TypeScript core is checked against the same `markdown-table- | Toggle Light Auto Align | `Ctrl+Alt+Shift+A` | | Toggle Power Auto Fit | `Ctrl+Alt+Shift+F` | -All other commands are available from the Command Palette under `Markdown Table Editor`. +macOS uses `Cmd` instead of `Ctrl`. The remaining commands — moving columns, sorting, narrowing or +widening a column, and inserting a table — are available from the Command Palette under +`Markdown Table Editor`. ## Settings -- `markdownTableEditor.lightAutoAlign`: align a table after edits; -- `markdownTableEditor.powerAutoFit`: also physically fit an edited table; -- `markdownTableEditor.fitWidth`: target table width in display columns, default 120. +- `markdownTableEditor.lightAutoAlign`: align a table shortly after an edit, enabled by default; +- `markdownTableEditor.powerAutoFit`: also fit the physical width after an edit, disabled by default; +- `markdownTableEditor.fitWidth`: target table width in display columns, 120 by default. + +## Privacy and security + +The extension processes document text locally inside the Extension Host: no telemetry, no document +contents leaving the machine, no network requests — see [PRIVACY.md](PRIVACY.md). It is declared +safe for untrusted workspaces and works in virtual workspaces because it never reads or executes +project files. Vulnerability reporting is described in [SECURITY.md](SECURITY.md). + +## Compatibility + +- VS Code `1.96` and newer. +- Windows, macOS, Linux; Remote SSH, WSL, Dev Containers, and Codespaces (the extension can run on + either the UI or the workspace side). +- Virtual file systems and untrusted workspaces are supported. ## Build and verify -Node.js 20+ and npm are required. +Node.js 20+ and npm are required; CI uses Node.js 24. ```powershell npm ci @@ -61,7 +158,11 @@ npm run test:e2e npm run package ``` -The E2E suite downloads stable VS Code from the official update service and launches a separate Extension Host. CI repeats unit, coverage, E2E, and VSIX packaging on clean runners. +`test:e2e` downloads stable VS Code from the official update service and launches a separate +Extension Host. CI repeats unit tests, coverage, E2E on Linux and Windows, the VSIX build, and its +installation into a clean profile. Contribution rules are in [CONTRIBUTING.md](CONTRIBUTING.md), +the package contents in [THIRD_PARTY_NOTICES.md](THIRD_PARTY_NOTICES.md), and the publishing +procedure in [MARKETPLACE_SUBMISSION.md](MARKETPLACE_SUBMISSION.md). ## License diff --git a/README.md b/README.md index 36e7041..4a74a38 100644 --- a/README.md +++ b/README.md @@ -1,30 +1,111 @@ # Markdown Table Editor для Visual Studio Code [![CI](https://github.com/krotname/VsCodeMarkdownTableEditor/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/krotname/VsCodeMarkdownTableEditor/actions/workflows/ci.yml) -[![CodeQL](https://github.com/krotname/VsCodeMarkdownTableEditor/actions/workflows/codeql.yml/badge.svg?branch=main)](https://github.com/krotname/VsCodeMarkdownTableEditor/actions/workflows/codeql.yml) +[![CodeQL](https://github.com/krotname/VsCodeMarkdownTableEditor/actions/workflows/codeql.yml/badge.svg?branch=main)](https://github.com/krotname/VsCodeMarkdownTableEditor/actions/workflows/codeql.yml?query=branch%3Amain) +[![OpenSSF Scorecard](https://api.securityscorecards.dev/projects/github.com/krotname/VsCodeMarkdownTableEditor/badge)](https://securityscorecards.dev/viewer/?uri=github.com/krotname/VsCodeMarkdownTableEditor) +[![Release](https://img.shields.io/github/v/release/krotname/VsCodeMarkdownTableEditor?label=release)](https://github.com/krotname/VsCodeMarkdownTableEditor/releases/latest) [![License](https://img.shields.io/github/license/krotname/VsCodeMarkdownTableEditor)](LICENSE) +[![Website](https://img.shields.io/badge/website-markdowntableeditor.ru-0f766e)](https://markdowntableeditor.ru/) -Нативное расширение VS Code для быстрого редактирования GitHub-flavored Markdown-таблиц. Нажатие `Tab` внутри таблицы выравнивает её; вне таблицы остаётся обычным Tab. +Markdown Table Editor превращает VS Code в удобный редактор Markdown-таблиц. Берёте чужую косую +таблицу или сгенерированную ИИ, жмёте `Tab` — и расширение выравнивает колонки, сохраняя разметку, +а дальше помогает переставлять строки, колонки и данные, не выходя из редактора. -Ядро написано на TypeScript без Java, .NET или внешнего процесса. Его поведение проверяется тем же `markdown-table-core-golden.json`, который используют версии для [JetBrains IDEs](https://github.com/krotname/IdeaMarkdownTableEditor) и [Notepad++](https://github.com/krotname/NppMarkdownTableEditor). +**Быстрый старт:** [скачать VSIX из последнего релиза](https://github.com/krotname/VsCodeMarkdownTableEditor/releases/latest) · +[открыть сайт проекта](https://markdowntableeditor.ru/) · +[English README](README.en.md) + +Публикация в Visual Studio Marketplace готовится; до неё расширение ставится из VSIX. + +## Другие версии + +- Для JetBrains IDEs: [IdeaMarkdownTableEditor](https://github.com/krotname/IdeaMarkdownTableEditor) + ([JetBrains Marketplace](https://plugins.jetbrains.com/plugin/32159-markdown-table-editor)) +- Для Notepad++: [NppMarkdownTableEditor](https://github.com/krotname/NppMarkdownTableEditor) + +Все три версии используют одно и то же поведение ядра и проверяются общим набором эталонных +данных `markdown-table-core-golden.json`, поэтому таблица выглядит одинаково в любом редакторе. + +## Как это выглядит + +Было — таблица, набранная руками: + +```markdown +| Команда | Клавиши | Что делает | +|---|:---:|---| +| Align Table | Ctrl+Alt+Shift+1 | выравнивает таблицу под курсором | +| Sort Rows Ascending | Command Palette | сортирует строки по колонке | +| 変換 CSV/TSV | Ctrl+Alt+Shift+0 | превращает CSV или TSV в таблицу | +``` + +Стало — после одного нажатия `Tab` внутри таблицы: + +```markdown +| Команда | Клавиши | Что делает | +| ------------------- | :--------------: | -------------------------------- | +| Align Table | Ctrl+Alt+Shift+1 | выравнивает таблицу под курсором | +| Sort Rows Ascending | Command Palette | сортирует строки по колонке | +| 変換 CSV/TSV | Ctrl+Alt+Shift+0 | превращает CSV или TSV в таблицу | +``` + +Выравнивание задаётся строкой-разделителем и сохраняется, а ширина считается по экранным +позициям: CJK и emoji занимают две колонки, combining marks — ноль. + +Вставленный CSV превращается в таблицу командой `Convert CSV/TSV to Table`, включая поля в +кавычках с запятыми внутри: + +```markdown +| name | role | city | +| -------------- | ---------- | ------ | +| Ovcharenko, A. | maintainer | Moscow | +| lena | reviewer | Sochi | +``` + +`Fit Table Width to Editor` ужимает таблицу до заданной ширины и переносит длинные ячейки +физически, без изменения смысла строк: + +```markdown +| Режим | Что делает | +| ----- | ---------------------------------------------------- | +| Light | выравнивает таблицу через мгновение после правки, не | +| Auto | трогая ширину колонок | +| Align | | +| Power | дополнительно ужимает таблицу до заданной ширины и | +| Auto | переносит длинные ячейки | +| Fit | | +``` + +## Зачем он нужен + +- Не нужно уходить из VS Code в отдельный редактор таблиц. +- Большие pipe-таблицы остаются читаемыми в обычном тексте, а не только в предпросмотре. +- `Tab`, сортировка и операции со строками и колонками экономят ручное выравнивание. +- CSV/TSV из письма или выгрузки быстро превращается в аккуратную Markdown-таблицу. +- Всё работает локально: ни телеметрии, ни сетевых запросов, ни аккаунта. ## Возможности -- выравнивание с учётом CJK, emoji, combining marks и escaped pipes; -- переход между ячейками и добавление новой строки в конце; -- вставка, удаление и перемещение строк и колонок; -- изменение ширины колонки и физический перенос длинных ячеек; -- числовая и Unicode-aware сортировка; -- преобразование CSV/TSV, включая quoted и multiline поля; -- вставка новой таблицы; -- Light Auto Align и Power Auto Fit; -- работа полностью локально, без телеметрии и сетевых запросов расширения. +- `Tab` внутри Markdown-таблицы выравнивает её, вне таблицы работает как обычный `Tab`. +- Выравнивание с учётом CJK, emoji, combining marks и экранированных `\|`. +- Переход между ячейками с созданием новой строки в конце таблицы. +- Вставка, удаление и перемещение строк и колонок. +- Сужение и расширение колонки, физический перенос длинных ячеек. +- Числовая и Unicode-aware сортировка строк по колонке под курсором. +- Преобразование CSV и TSV, включая поля в кавычках и многострочные значения. +- Вставка новой таблицы заданного размера. +- Light Auto Align и Power Auto Fit с переключателями в строке состояния. -## Установка локального VSIX +## Установка -1. Соберите пакет командой `npm run package`. -2. В VS Code откройте `Extensions: Install from VSIX...`. -3. Выберите `build/markdown-table-editor.vsix`. +Из VSIX: + +1. Скачайте `markdown-table-editor.vsix` из [последнего релиза](https://github.com/krotname/VsCodeMarkdownTableEditor/releases/latest) + или соберите его локально командой `npm run package`. +2. В VS Code выполните `Extensions: Install from VSIX...`. +3. Выберите скачанный или собранный файл `markdown-table-editor.vsix`. + +Каждый релизный VSIX сопровождается файлом `SHA256SUMS.txt` и подписью происхождения сборки +(build provenance attestation), созданной GitHub Actions. ## Команды @@ -41,17 +122,34 @@ | Toggle Light Auto Align | `Ctrl+Alt+Shift+A` | | Toggle Power Auto Fit | `Ctrl+Alt+Shift+F` | -Остальные команды доступны через Command Palette в категории `Markdown Table Editor`. +На macOS вместо `Ctrl` используется `Cmd`. Остальные команды — перемещение колонок, сортировка, +сужение и расширение колонки, вставка таблицы — доступны через Command Palette в категории +`Markdown Table Editor`. ## Настройки -- `markdownTableEditor.lightAutoAlign` — выравнивать таблицу после правки; -- `markdownTableEditor.powerAutoFit` — после правки также подгонять физическую ширину; -- `markdownTableEditor.fitWidth` — целевая ширина таблицы в display columns, по умолчанию 120. +- `markdownTableEditor.lightAutoAlign` — выравнивать таблицу вскоре после правки, по умолчанию включено; +- `markdownTableEditor.powerAutoFit` — после правки также подгонять физическую ширину, по умолчанию выключено; +- `markdownTableEditor.fitWidth` — целевая ширина таблицы в экранных колонках, по умолчанию 120. + +## Приватность и безопасность + +Расширение обрабатывает текст документа локально внутри Extension Host и не собирает телеметрию, +не отправляет содержимое документов и не делает сетевых запросов — см. [PRIVACY.md](PRIVACY.md). +Оно объявлено безопасным для untrusted workspaces и работает в виртуальных рабочих областях, +потому что не выполняет и не читает файлы проекта. Порядок сообщений об уязвимостях описан в +[SECURITY.md](SECURITY.md). + +## Совместимость + +- VS Code `1.96` и новее. +- Windows, macOS, Linux; Remote SSH, WSL, Dev Containers и Codespaces (расширение может работать + как на стороне UI, так и на стороне workspace). +- Виртуальные файловые системы и untrusted workspaces поддерживаются. ## Разработка и проверка -Требуются Node.js 20+ и npm. +Требуются Node.js 20+ и npm; CI использует Node.js 24. ```powershell npm ci @@ -61,7 +159,11 @@ npm run test:e2e npm run package ``` -`test:e2e` скачивает из официального канала стабильный VS Code и запускает отдельный Extension Host. CI повторяет unit, coverage, E2E и VSIX-сборку на чистых runner-ах. +`test:e2e` скачивает из официального канала стабильный VS Code и запускает отдельный Extension +Host. CI повторяет unit, coverage, E2E на Linux и Windows, сборку VSIX и его установку в чистый +профиль. Требования к вкладу описаны в [CONTRIBUTING.md](CONTRIBUTING.md), состав пакета — +в [THIRD_PARTY_NOTICES.md](THIRD_PARTY_NOTICES.md), порядок публикации — +в [MARKETPLACE_SUBMISSION.md](MARKETPLACE_SUBMISSION.md). ## Лицензия diff --git a/THIRD_PARTY_NOTICES.md b/THIRD_PARTY_NOTICES.md new file mode 100644 index 0000000..6080bae --- /dev/null +++ b/THIRD_PARTY_NOTICES.md @@ -0,0 +1,32 @@ +# Third-Party Notices + +## Distributed extension + +The published `markdown-table-editor.vsix` does not bundle third-party runtime code. It contains +the bundled extension entry point built from this repository's TypeScript sources, its source map, +the extension manifest, the icon, and the project documentation, including the GPL-3.0-or-later +license text. + +The extension is compiled against the Visual Studio Code extension API (`@types/vscode`, type +declarations only). At runtime that API is provided by the user's VS Code installation and is not +redistributed inside the package. The extension declares no runtime `dependencies`, and the VSIX is +packaged with `vsce package --no-dependencies`. + +## Build and test tooling + +These packages are development dependencies. They are used to build, test, and package the +extension and are not shipped inside the VSIX: + +| Component | Use | License | +| --- | --- | --- | +| `esbuild` | Bundles `src/extension.ts` into `dist/extension.js` | MIT | +| `typescript` | Type checking of the sources and tests | Apache-2.0 | +| `tsx` | Runs the TypeScript unit tests on the Node.js test runner | MIT | +| `c8` | Coverage measurement and thresholds | ISC | +| `mocha` | Test runner inside the VS Code Extension Host | MIT | +| `@vscode/test-electron` | Downloads VS Code and runs the Extension Host E2E suite | MIT | +| `@vscode/vsce` | Packages and publishes the VSIX | MIT | +| `@types/vscode`, `@types/node`, `@types/mocha` | Type declarations only | MIT | + +Transitive dependency licenses resolve from `package-lock.json`; `npm audit --audit-level=low` +runs on every CI build. diff --git a/package-lock.json b/package-lock.json index 27851cf..1836964 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "markdown-table-editor", - "version": "0.1.0", + "version": "0.2.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "markdown-table-editor", - "version": "0.1.0", + "version": "0.2.0", "license": "GPL-3.0-or-later", "devDependencies": { "@types/mocha": "^10.0.10", diff --git a/package.json b/package.json index 4285774..5f5ba88 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "markdown-table-editor", "displayName": "Markdown Table Editor", "description": "Fast, local Markdown table editing for Visual Studio Code.", - "version": "0.1.0", + "version": "0.2.0", "publisher": "krotname", "license": "GPL-3.0-or-later", "repository": { @@ -13,14 +13,29 @@ "url": "https://github.com/krotname/VsCodeMarkdownTableEditor/issues" }, "homepage": "https://github.com/krotname/VsCodeMarkdownTableEditor#readme", + "qna": "https://github.com/krotname/VsCodeMarkdownTableEditor/issues", "engines": { "vscode": "^1.96.0" }, "categories": ["Formatters", "Other"], "keywords": ["markdown", "table", "formatter", "csv", "tsv"], "icon": "docs/icon.png", + "galleryBanner": { + "color": "#0F172A", + "theme": "dark" + }, + "pricing": "Free", + "extensionKind": ["ui", "workspace"], + "capabilities": { + "untrustedWorkspaces": { + "supported": true, + "description": "The extension only rewrites Markdown tables in the open editor and never executes workspace content." + }, + "virtualWorkspaces": true + }, "main": "./dist/extension.js", - "files": ["dist/extension.js", "dist/extension.js.map", "docs/icon.png", "LICENSE", "README.md", "README.en.md", "CHANGELOG.md", "PRIVACY.md"], + "activationEvents": ["onLanguage:markdown"], + "files": ["dist/extension.js", "dist/extension.js.map", "docs/icon.png", "LICENSE", "README.md", "README.en.md", "CHANGELOG.md", "PRIVACY.md", "THIRD_PARTY_NOTICES.md"], "scripts": { "clean": "node scripts/clean.mjs", "build": "node scripts/build.mjs", diff --git a/scripts/verify-vsix.mjs b/scripts/verify-vsix.mjs index dd00597..fa298e5 100644 --- a/scripts/verify-vsix.mjs +++ b/scripts/verify-vsix.mjs @@ -1,8 +1,11 @@ import assert from 'node:assert/strict'; +import { readFile } from 'node:fs/promises'; import { join } from 'node:path'; import { runVSCodeCommand } from '@vscode/test-electron'; const root = process.cwd(); +const { name, publisher, version } = JSON.parse(await readFile(join(root, 'package.json'), 'utf8')); +const expected = `${publisher}.${name}@${version}`; const vsix = join(root, 'build', 'markdown-table-editor.vsix'); const extensionsDirectory = join(root, 'build', 'vsix-extensions'); const userDataDirectory = join(root, 'build', 'vsix-user-data'); @@ -10,5 +13,8 @@ const profileArgs = ['--extensions-dir', extensionsDirectory, '--user-data-dir', await runVSCodeCommand(['--install-extension', vsix, '--force', ...profileArgs], { version: 'stable' }); const { stdout } = await runVSCodeCommand(['--list-extensions', '--show-versions', ...profileArgs], { version: 'stable' }); -assert.match(stdout, /^krotname\.markdown-table-editor@0\.1\.0$/mu); -console.log('Packaged VSIX installed and enumerated successfully.'); +assert.ok( + stdout.split(/\r?\n/u).includes(expected), + `Expected the installed extension list to contain ${expected}, got:\n${stdout}`, +); +console.log(`Packaged VSIX installed and enumerated successfully as ${expected}.`);