commit e6a7e09ed6fe55bc6e41a0bcaac7e583f2a9da85 Author: Aric Camarata Date: Thu May 28 13:45:11 2026 -0400 chore: scaffold @acamarata/prettier-config 0.1.0 diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..19d5737 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,57 @@ +name: CI + +on: + push: + branches: [main] + pull_request: + branches: [main] + +jobs: + test: + name: Test (Node ${{ matrix.node-version }}) + runs-on: ubuntu-latest + strategy: + matrix: + node-version: [20, 22, 24] + steps: + - uses: actions/checkout@v4 + + - name: Setup Node ${{ matrix.node-version }} + uses: actions/setup-node@v4 + with: + node-version: ${{ matrix.node-version }} + + - name: Enable corepack + run: corepack enable + + - name: Install dependencies + run: pnpm install + + - name: Test + run: pnpm test + + pack-check: + name: Pack Check + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Setup Node 24 + uses: actions/setup-node@v4 + with: + node-version: 24 + + - name: Enable corepack + run: corepack enable + + - name: Install dependencies + run: pnpm install + + - name: Verify pack contents + run: | + npm pack --dry-run 2>&1 | tee pack-output.txt + grep "index.js" pack-output.txt + grep "README.md" pack-output.txt + grep "CHANGELOG.md" pack-output.txt + grep "LICENSE" pack-output.txt + echo "Pack check passed" diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..704ef7c --- /dev/null +++ b/.gitignore @@ -0,0 +1,14 @@ +node_modules/ +*.tgz +.DS_Store +.vscode/* +.idea/ +.claude/ +.codex/ +.cursor/ +.aider/ +.aider.chat.history.md +.continue/ +.windsurf/ +.gemini/ +.codeium/ diff --git a/.npmrc b/.npmrc new file mode 100644 index 0000000..e69de29 diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..22c7e0a --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,22 @@ +# Changelog + +All notable changes to `@acamarata/prettier-config` are documented here. + +Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). +Version numbers follow [Semantic Versioning](https://semver.org/). + +## [Unreleased] + +## [0.1.0] - 2026-05-28 + +### Added + +- Initial release. +- Base Prettier config: `printWidth: 100`, `tabWidth: 2`, `singleQuote: false`, + `trailingComma: "all"`, `semi: true`, `endOfLine: "lf"`. +- Per-file-type overrides for Markdown, JSON, and YAML. +- ESM-only distribution (`"type": "module"`). +- Node test suite verifying config shape and override structure. + +[Unreleased]: https://github.com/acamarata/prettier-config/compare/v0.1.0...HEAD +[0.1.0]: https://github.com/acamarata/prettier-config/releases/tag/v0.1.0 diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..f8c021c --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 Aric Camarata + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..99dc6dc --- /dev/null +++ b/README.md @@ -0,0 +1,76 @@ +# @acamarata/prettier-config + +[![npm](https://img.shields.io/npm/v/@acamarata/prettier-config)](https://www.npmjs.com/package/@acamarata/prettier-config) +[![CI](https://github.com/acamarata/prettier-config/actions/workflows/ci.yml/badge.svg)](https://github.com/acamarata/prettier-config/actions/workflows/ci.yml) + +Shared [Prettier](https://prettier.io) configuration for acamarata JavaScript and TypeScript packages. + +## Install + +```bash +npm install --save-dev @acamarata/prettier-config prettier +``` + +Or with pnpm: + +```bash +pnpm add -D @acamarata/prettier-config prettier +``` + +Prettier 3.x is required as a peer dependency. + +## Usage + +Reference the package in your `package.json`: + +```json +{ + "prettier": "@acamarata/prettier-config" +} +``` + +That is all you need for the defaults. Prettier reads the `prettier` field and loads the config automatically. + +## Defaults + +| Option | Value | +|---|---| +| `printWidth` | `100` | +| `tabWidth` | `2` | +| `useTabs` | `false` | +| `singleQuote` | `false` | +| `trailingComma` | `"all"` | +| `semi` | `true` | +| `bracketSpacing` | `true` | +| `arrowParens` | `"always"` | +| `endOfLine` | `"lf"` | + +### File-type overrides + +| File pattern | Override | +|---|---| +| `*.md`, `*.mdx` | `printWidth: 80`, `proseWrap: "always"`, `trailingComma: "none"` | +| `*.json`, `*.jsonc` | `trailingComma: "none"` | +| `*.yaml`, `*.yml` | `singleQuote: true`, `trailingComma: "none"` | + +## Extending + +If you need to override specific options, use a `prettier.config.mjs` file in your project: + +```js +import acamarataConfig from "@acamarata/prettier-config"; + +/** @type {import("prettier").Config} */ +export default { + ...acamarataConfig, + // Your overrides here + printWidth: 120, +}; +``` + +Note: the `prettier` field in `package.json` does not support extending. Use a config file +when you need project-specific overrides. + +## License + +MIT diff --git a/index.js b/index.js new file mode 100644 index 0000000..94a3b11 --- /dev/null +++ b/index.js @@ -0,0 +1,54 @@ +/** + * Purpose: Shared Prettier configuration for all acamarata JS/TS packages. + * Inputs: none — this file is consumed via the "prettier" field in package.json. + * Outputs: a Prettier config object with base settings and per-file-type overrides. + * Constraints: Prettier 3.x required (see peerDependencies). The overrides array + * is evaluated in order; later entries win on conflict. + * SPORT: packages.md — @acamarata/prettier-config + */ + +/** @type {import("prettier").Config} */ +const config = { + // Base formatting rules + printWidth: 100, + tabWidth: 2, + useTabs: false, + singleQuote: false, + quoteProps: "as-needed", + trailingComma: "all", + semi: true, + bracketSpacing: true, + bracketSameLine: false, + arrowParens: "always", + endOfLine: "lf", + + // Per-file-type overrides + overrides: [ + { + // Markdown: narrower width, no trailing comma, preserve prose wrapping + files: ["*.md", "*.mdx"], + options: { + printWidth: 80, + proseWrap: "always", + trailingComma: "none", + }, + }, + { + // JSON: no trailing comma (JSON spec disallows it) + files: ["*.json", "*.jsonc"], + options: { + trailingComma: "none", + }, + }, + { + // YAML: single quotes match most YAML authoring conventions + files: ["*.yaml", "*.yml"], + options: { + singleQuote: true, + trailingComma: "none", + }, + }, + ], +}; + +export default config; diff --git a/package.json b/package.json new file mode 100644 index 0000000..f119f08 --- /dev/null +++ b/package.json @@ -0,0 +1,58 @@ +{ + "name": "@acamarata/prettier-config", + "version": "0.1.0", + "description": "Shared Prettier configuration for acamarata packages.", + "author": "Aric Camarata", + "license": "MIT", + "type": "module", + "main": "./index.js", + "exports": { + ".": "./index.js", + "./package.json": "./package.json" + }, + "files": [ + "index.js", + "README.md", + "CHANGELOG.md", + "LICENSE" + ], + "sideEffects": false, + "engines": { + "node": ">=20" + }, + "scripts": { + "test": "node --test test.mjs", + "typecheck": "echo 'No TypeScript source \u2014 skipped'" + }, + "peerDependencies": { + "prettier": ">=3.0.0" + }, + "peerDependenciesMeta": { + "prettier": { + "optional": false + } + }, + "devDependencies": { + "prettier": "^3.5.3" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/acamarata/prettier-config.git" + }, + "homepage": "https://github.com/acamarata/prettier-config#readme", + "bugs": { + "url": "https://github.com/acamarata/prettier-config/issues" + }, + "keywords": [ + "prettier", + "prettier-config", + "config", + "formatting", + "acamarata" + ], + "publishConfig": { + "access": "public", + "registry": "https://registry.npmjs.org/" + }, + "packageManager": "pnpm@10.11.1" +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml new file mode 100644 index 0000000..4e9444b --- /dev/null +++ b/pnpm-lock.yaml @@ -0,0 +1,24 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + + .: + devDependencies: + prettier: + specifier: ^3.5.3 + version: 3.8.3 + +packages: + + prettier@3.8.3: + resolution: {integrity: sha512-7igPTM53cGHMW8xWuVTydi2KO233VFiTNyF5hLJqpilHfmn8C8gPf+PS7dUT64YcXFbiMGZxS9pCSxL/Dxm/Jw==} + engines: {node: '>=14'} + hasBin: true + +snapshots: + + prettier@3.8.3: {} diff --git a/test.mjs b/test.mjs new file mode 100644 index 0000000..05cccf6 --- /dev/null +++ b/test.mjs @@ -0,0 +1,83 @@ +/** + * Tests for @acamarata/prettier-config. + * + * Verifies that the config object exports the expected keys and that + * per-file-type overrides are structured correctly. + */ + +import { strict as assert } from "node:assert"; +import { describe, it } from "node:test"; +import config from "./index.js"; + +describe("@acamarata/prettier-config — base config", () => { + it("exports an object", () => { + assert.strictEqual(typeof config, "object"); + assert.notStrictEqual(config, null); + }); + + it("has printWidth", () => { + assert.strictEqual(typeof config.printWidth, "number"); + assert.strictEqual(config.printWidth, 100); + }); + + it("has tabWidth", () => { + assert.strictEqual(typeof config.tabWidth, "number"); + assert.strictEqual(config.tabWidth, 2); + }); + + it("has singleQuote", () => { + assert.strictEqual(typeof config.singleQuote, "boolean"); + assert.strictEqual(config.singleQuote, false); + }); + + it("has trailingComma", () => { + assert.strictEqual(typeof config.trailingComma, "string"); + assert.strictEqual(config.trailingComma, "all"); + }); + + it("has semi", () => { + assert.strictEqual(typeof config.semi, "boolean"); + assert.strictEqual(config.semi, true); + }); + + it("has endOfLine lf", () => { + assert.strictEqual(config.endOfLine, "lf"); + }); +}); + +describe("@acamarata/prettier-config — overrides", () => { + it("exports an overrides array", () => { + assert.ok(Array.isArray(config.overrides)); + assert.ok(config.overrides.length >= 3); + }); + + it("has markdown override with proseWrap always", () => { + const md = config.overrides.find((o) => + (Array.isArray(o.files) ? o.files : [o.files]).some((f) => + f.includes("*.md"), + ), + ); + assert.ok(md, "markdown override not found"); + assert.strictEqual(md.options.proseWrap, "always"); + }); + + it("has JSON override with no trailing comma", () => { + const json = config.overrides.find((o) => + (Array.isArray(o.files) ? o.files : [o.files]).some((f) => + f.includes("*.json"), + ), + ); + assert.ok(json, "JSON override not found"); + assert.strictEqual(json.options.trailingComma, "none"); + }); + + it("has YAML override with no trailing comma", () => { + const yaml = config.overrides.find((o) => + (Array.isArray(o.files) ? o.files : [o.files]).some((f) => + f.includes("*.yaml"), + ), + ); + assert.ok(yaml, "YAML override not found"); + assert.strictEqual(yaml.options.trailingComma, "none"); + }); +});