diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 0000000..2735669 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,52 @@ +--- +name: Bug Report +about: Report a bug or unexpected behavior +title: '[Bug]: ' +labels: bug +assignees: '' +--- + +## Bug Description + + + +## Steps to Reproduce + + + +1. Run command: `patternfly-cli ...` or `pf ...` +2. +3. +4. See error + +## Expected Behavior + + + +## Actual Behavior + + + +## Error Output + + + +``` +Paste error output here +``` + +## Environment + +- **OS**: +- **Node version**: +- **npm version**: +- **PatternFly CLI version**: +- **Shell**: + +## Additional Context + + + +## Possible Solution + + diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 0000000..a7f045c --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,8 @@ +blank_issues_enabled: true +contact_links: + - name: PatternFly Documentation + url: https://www.patternfly.org/ + about: Visit the official PatternFly documentation + - name: PatternFly Community + url: https://github.com/patternfly + about: Explore other PatternFly projects and resources diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 0000000..0463b93 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,44 @@ +--- +name: Feature Request +about: Suggest a new feature or enhancement +title: '[Feature]: ' +labels: enhancement +assignees: '' +--- + +## Feature Description + + + +## Problem Statement + + + +## Proposed Solution + + + +## Example Usage + + + +```bash +# Example command or usage +pf new-command --option value +``` + +## Alternatives Considered + + + +## Additional Context + + + +## Benefits + + + +- +- +- diff --git a/.github/LINTING.md b/.github/LINTING.md new file mode 100644 index 0000000..b6e6b00 --- /dev/null +++ b/.github/LINTING.md @@ -0,0 +1,59 @@ +# Linting Guide + +This project uses multiple linters to maintain code and documentation quality. + +## Available Linters + +### ESLint (JavaScript/TypeScript) + +Lints TypeScript source code in the `src/` directory. + +```bash +npm run lint:js # Check for issues +npm run lint:js:fix # Auto-fix issues +``` + +### Markdownlint (Documentation) + +Validates all markdown files (`.md`) for consistency and best practices. + +```bash +npm run lint:md # Check markdown files +npm run lint:md:fix # Auto-fix markdown issues +``` + +Configuration: [.markdownlint.json](../.markdownlint.json) + +### Actionlint (GitHub Actions) + +Validates GitHub Actions workflow files automatically on pull requests and pushes to main. + +This runs automatically in CI when workflow files are modified. + +## Run All Linters + +```bash +npm run lint # Run all linters +npm run lint:fix # Auto-fix all issues +``` + +## CI/CD Integration + +- **Lint workflow** (`.github/workflows/lint.yml`) - Runs all linters after successful build +- **Markdownlint workflow** (`.github/workflows/markdownlint.yml`) - Runs on markdown file changes +- **Actionlint workflow** (`.github/workflows/actionlint.yml`) - Runs on workflow file changes + +## Configuration Files + +- [.eslintrc](../.eslintrc) - ESLint configuration (if exists) +- [.markdownlint.json](../.markdownlint.json) - Markdownlint rules +- [.markdownlintignore](../.markdownlintignore) - Files to exclude from markdown linting + +## Ignored Paths + +The following are automatically ignored by linters: + +- `node_modules/` - Dependencies +- `dist/` - Build output +- `.agentready/` - Agent reports +- `CHANGELOG.md` - Auto-generated by semantic-release diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 0000000..03cc7ae --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,64 @@ +## Description + + + +## Type of Change + + + +- [ ] Bug fix (non-breaking change which fixes an issue) +- [ ] New feature (non-breaking change which adds functionality) +- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) +- [ ] Documentation update +- [ ] Refactoring (no functional changes) +- [ ] Dependency update +- [ ] Other (please describe): + +## Related Issues + + + +Fixes # +Relates to # + +## Changes Made + + + +- +- +- + +## Testing + + + +- [ ] Existing tests pass (`npm test`) +- [ ] Added new tests for changes +- [ ] Manually tested locally (`npm run build && npm install -g`) +- [ ] Linting passes (`npm run lint`) + +### Test Instructions + + + +1. +2. +3. + +## Checklist + +- [ ] My code follows the code style of this project +- [ ] I have added/updated tests as appropriate +- [ ] I have updated the documentation (if applicable) +- [ ] My commit messages follow the [Conventional Commits](https://www.conventionalcommits.org/) specification +- [ ] All imports use `.js` extensions (ESM requirement) +- [ ] TypeScript compilation succeeds (`npm run build`) + +## Screenshots (if applicable) + + + +## Additional Notes + + diff --git a/.github/workflows/actionlint.yml b/.github/workflows/actionlint.yml new file mode 100644 index 0000000..95bab83 --- /dev/null +++ b/.github/workflows/actionlint.yml @@ -0,0 +1,28 @@ +name: Actionlint + +on: + pull_request: + paths: + - '.github/workflows/*.yml' + - '.github/workflows/*.yaml' + push: + branches: + - main + paths: + - '.github/workflows/*.yml' + - '.github/workflows/*.yaml' + +jobs: + actionlint: + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Run actionlint + uses: reviewdog/action-actionlint@v1 + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + reporter: github-pr-review + filter_mode: nofilter + fail_on_error: true diff --git a/.github/workflows/markdownlint.yml b/.github/workflows/markdownlint.yml new file mode 100644 index 0000000..728a8f9 --- /dev/null +++ b/.github/workflows/markdownlint.yml @@ -0,0 +1,29 @@ +name: Markdownlint + +on: + pull_request: + paths: + - '**.md' + push: + branches: + - main + paths: + - '**.md' + +jobs: + markdownlint: + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: '20' + + - name: Install dependencies + run: npm ci + + - name: Run markdownlint + run: npm run lint:md diff --git a/.gitignore b/.gitignore index 9a5aced..730950c 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,9 @@ yarn-debug.log* yarn-error.log* lerna-debug.log* +# AI analysis +.agentready + # Diagnostic reports (https://nodejs.org/api/report.html) report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json diff --git a/.markdownlint.json b/.markdownlint.json new file mode 100644 index 0000000..e9ba631 --- /dev/null +++ b/.markdownlint.json @@ -0,0 +1,19 @@ +{ + "default": true, + "MD003": { + "style": "atx" + }, + "MD007": { + "indent": 2 + }, + "MD013": { + "line_length": 120, + "code_blocks": false, + "tables": false + }, + "MD024": { + "siblings_only": true + }, + "MD033": false, + "MD041": false +} diff --git a/.markdownlintignore b/.markdownlintignore new file mode 100644 index 0000000..33d7710 --- /dev/null +++ b/.markdownlintignore @@ -0,0 +1,4 @@ +node_modules/ +dist/ +.agentready/ +CHANGELOG.md diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..d26c0e5 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,165 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## Project Overview + +PatternFly CLI (`@patternfly/patternfly-cli`) is a command-line tool for scaffolding PatternFly projects, running +codemods, and managing git/GitHub workflows. It can be invoked as `patternfly-cli` or the shorter alias `pf`. + +**Key capabilities:** + +- Scaffold new projects from git templates (built-in or custom) +- Run PatternFly codemods to update existing code +- Manage git/GitHub workflows (init, save, load, deploy to GitHub Pages) +- Self-upgrade to the latest npm release + +## Development Commands + +### Build and Test + +```bash +npm install # Install dependencies +npm run build # Compile TypeScript to dist/ +npm test # Run all Jest tests +npm run lint # Lint with ESLint +npm run lint:fix # Auto-fix linting issues +``` + +### Run a Single Test + +```bash +npx jest +# Example: +npx jest create.test.ts +npx jest tests/github.test.ts +``` + +### Local Development + +After building, install the CLI globally to test changes: + +```bash +npm run build +npm install -g +# Now 'patternfly-cli' or 'pf' runs your local build +``` + +## Architecture + +### Module System + +- **TypeScript with ESM modules** using `"type": "module"` and `"module": "NodeNext"` +- **Import paths must include `.js` extensions** even for `.ts` files (e.g., `import { foo } from './bar.js'`). + This is required by NodeNext module resolution. +- **Tests use ts-jest** with custom `moduleNameMapper` to handle ESM imports + +### Command Structure + +The entry point ([src/cli.ts](src/cli.ts)) defines all CLI commands using Commander.js. Each command delegates to a +dedicated module: + +- `create` → [src/create.ts](src/create.ts) - Clone git template, customize package.json, install deps +- `init` → [src/github.ts](src/github.ts) - Initialize git repo and optionally create GitHub repo +- `update` → [src/cli.ts](src/cli.ts) - Run `@patternfly/pf-codemods` and `@patternfly/class-name-updater` via npx +- `save` → [src/save.ts](src/save.ts) - Commit and push changes +- `load` → [src/load.ts](src/load.ts) - Pull latest from remote +- `deploy` → [src/gh-pages.ts](src/gh-pages.ts) - Build and deploy to GitHub Pages + +### Template System + +- **Built-in templates** are defined in [src/templates.ts](src/templates.ts) as an array of `Template` objects +- **Custom templates** can be loaded from JSON files via `--template-file` / `-t` option +- **Template merging** ([src/template-loader.ts](src/template-loader.ts)) allows custom templates to override + built-in ones by name +- Each `Template` specifies: + - `name`, `description` (required) + - `repo` (HTTPS URL) and optional `repoSSH` (SSH URL) + - `options` (git clone flags like `["--single-branch", "--branch", "main"]`) + - `packageManager` (`npm`, `yarn`, or `pnpm`) + +### Git/GitHub Integration + +- [src/github.ts](src/github.ts) handles GitHub repo creation via `gh` CLI +- [src/git-user-config.ts](src/git-user-config.ts) prompts for local git user.name/user.email +- Commands use `execa` to run git and gh commands with proper error handling + +## TypeScript Configuration + +The project uses **strict TypeScript settings** ([tsconfig.json](tsconfig.json)): + +- `strict: true` with additional strictness (`noUncheckedIndexedAccess`, `exactOptionalPropertyTypes`) +- `noImplicitAny: false` to allow some implicit any (only exception to strict mode) +- `verbatimModuleSyntax: true` requires explicit `type` imports for type-only imports +- `isolatedModules: true` ensures each file can be transpiled independently + +## Testing + +- Tests live in [tests/](tests/) at the project root with `.test.ts` suffix +- Uses **ts-jest** with custom configuration for ESM compatibility +- Test files import from `../src/` (e.g., `import { runCreate } from '../src/create.js'`) +- Mock setup for `execa` is in [**mocks**/execa.js](__mocks__/execa.js) +- Test fixtures (sample package.json files, etc.) are in [tests/fixtures/](tests/fixtures/) + +## Release Process + +Uses **semantic-release** with conventional commits: + +- Pushing to `main` triggers automated release workflow (GitHub Actions) +- Commit message prefixes determine version bump: + - `feat:` → minor version bump + - `fix:` → patch version bump + - `BREAKING CHANGE:` → major version bump +- Updates `CHANGELOG.md`, creates GitHub release, bumps `package.json` version +- npm publishing is controlled by `.releaserc.json` (requires `NPM_TOKEN` secret) + +## Code Style Guidelines + +- Use **async/await** for asynchronous operations +- **Error handling**: catch errors, log with `console.error()`, and `throw` (or `process.exit(1)` for CLI commands) +- **User feedback**: use emoji prefixes for console output (✅ success, ❌ error, 📦 info, etc.) +- **Inquirer prompts** for interactive user input (project name, template selection, etc.) +- **Type safety**: prefer explicit types over `any`, use `unknown` for truly unknown data + +## Important Patterns + +### ESM Import Extensions + +Always use `.js` extensions in imports, even when importing from `.ts` files: + +```typescript +import { runCreate } from './create.js'; // Correct +import { runCreate } from './create'; // Will not work +``` + +### Template Validation + +Custom template files must be validated ([src/template-loader.ts](src/template-loader.ts:6-72)): + +- Must be valid JSON array +- Each template must have `name`, `description`, and `repo` as non-empty strings +- Optional fields (`repoSSH`, `options`, `packageManager`) have specific type requirements + +### Git Clone with Options + +Templates can specify git clone options (e.g., for specific branches): + +```typescript +const cloneArgs = ['clone']; +if (template.options && Array.isArray(template.options)) { + cloneArgs.push(...template.options); +} +cloneArgs.push(templateRepoUrl, projectPath); +await execa('git', cloneArgs, { stdio: 'inherit' }); +``` + +### Cleanup on Failure + +When operations fail mid-execution (e.g., during `create`), clean up partial state: + +```typescript +if (await fs.pathExists(projectPath)) { + await fs.remove(projectPath); + console.log('🧹 Cleaned up failed project directory.'); +} +``` diff --git a/README.md b/README.md index 5676aa8..55690a4 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,7 @@ # Patternfly CLI -Patternfly CLI is a command-line tool designed for scaffolding projects, performing code modifications, and running project-related tasks. It aims to streamline development workflows and improve productivity. +Patternfly CLI is a command-line tool designed for scaffolding projects, performing code modifications, and +running project-related tasks. It aims to streamline development workflows and improve productivity. ## Features @@ -12,7 +13,9 @@ Patternfly CLI is a command-line tool designed for scaffolding projects, perform ### Install script (macOS and Linux) -You can pipe the repository install script into `bash`. It installs Node.js with [nvm](https://github.com/nvm-sh/nvm) when `node` is not available, enables Corepack, installs the [GitHub CLI](https://cli.github.com/) when it is missing, then installs the CLI globally from npm: +You can pipe the repository install script into `bash`. It installs Node.js with +[nvm](https://github.com/nvm-sh/nvm) when `node` is not available, enables Corepack, installs the +[GitHub CLI](https://cli.github.com/) when it is missing, then installs the CLI globally from npm: ```sh curl -fsSL https://raw.githubusercontent.com/patternfly/patternfly-cli/main/scripts/install.sh | bash @@ -21,7 +24,8 @@ curl -fsSL https://raw.githubusercontent.com/patternfly/patternfly-cli/main/scri Swap `main` for another branch or tag if you need a specific revision. To save the script and inspect it before running: ```sh -curl -fsSL https://raw.githubusercontent.com/patternfly/patternfly-cli/main/scripts/install.sh -o install-patternfly-cli.sh +curl -fsSL https://raw.githubusercontent.com/patternfly/patternfly-cli/main/scripts/install.sh \ + -o install-patternfly-cli.sh bash install-patternfly-cli.sh ``` @@ -39,7 +43,8 @@ npm install -g @patternfly/patternfly-cli ### Uninstall script (macOS and Linux) -You can pipe the repository uninstall script into `bash`. It removes the globally installed `@patternfly/patternfly-cli` package with npm. It does **not** remove Node.js, nvm, Corepack, or GitHub CLI. +You can pipe the repository uninstall script into `bash`. It removes the globally installed +`@patternfly/patternfly-cli` package with npm. It does **not** remove Node.js, nvm, Corepack, or GitHub CLI. ```sh curl -fsSL https://raw.githubusercontent.com/patternfly/patternfly-cli/main/scripts/uninstall.sh | bash @@ -48,7 +53,8 @@ curl -fsSL https://raw.githubusercontent.com/patternfly/patternfly-cli/main/scri Swap `main` for another branch or tag if you need a specific revision. To save the script and inspect it before running: ```sh -curl -fsSL https://raw.githubusercontent.com/patternfly/patternfly-cli/main/scripts/uninstall.sh -o uninstall-patternfly-cli.sh +curl -fsSL https://raw.githubusercontent.com/patternfly/patternfly-cli/main/scripts/uninstall.sh \ + -o uninstall-patternfly-cli.sh bash uninstall-patternfly-cli.sh ``` @@ -62,7 +68,9 @@ npm uninstall -g @patternfly/patternfly-cli ## Prerequisites -If you use the [install script](#install-script-macos-and-linux) on macOS or Linux, it covers the items below (you may still need administrator access for system packages). Otherwise, install the following yourself before using the CLI: +If you use the [install script](#install-script-macos-and-linux) on macOS or Linux, it covers the items below +(you may still need administrator access for system packages). Otherwise, install the following yourself before using +the CLI: - **Node.js and npm** (v20–24) — [npm](https://www.npmjs.com/) · [Node.js downloads](https://nodejs.org/) - **Corepack** — enable with `corepack enable` (included with Node.js). Run the command after installing npm. @@ -81,7 +89,9 @@ patternfly-cli [command] - **`create`**: Create a new project from the available templates. - **`list`**: List all available templates (built-in and optional custom). - **`update`**: Update your project to a newer version. -- **`cli-upgrade`**: Upgrade the globally installed CLI to the latest npm release. It runs `npm install -g @patternfly/patternfly-cli@latest`; use your package manager’s equivalent if you did not install with npm. +- **`cli-upgrade`**: Upgrade the globally installed CLI to the latest npm release. It runs + `npm install -g @patternfly/patternfly-cli@latest`; use your package manager’s equivalent if you did not install + with npm. - **`init`**: Initialize a git repository and optionally create a GitHub repository. - **`save`**: Commit and push changes to the current branch. - **`load`**: Pull the latest updates from GitHub. @@ -89,7 +99,9 @@ patternfly-cli [command] ### Custom templates -You can add your own templates in addition to the built-in ones by passing a JSON file with the `--template-file` (or `-t`) option. Custom templates are merged with the built-in list; if a custom template has the same `name` as a built-in one, the custom definition is used. +You can add your own templates in addition to the built-in ones by passing a JSON file with the `--template-file` +(or `-t`) option. Custom templates are merged with the built-in list; if a custom template has the same `name` as a +built-in one, the custom definition is used. **Create with custom templates:** @@ -123,7 +135,6 @@ patternfly-cli list --template-file ./my-templates.json - **`options`** (optional): Array of extra arguments for `git clone` (e.g. `["--single-branch", "--branch", "main"]`). - **`packageManager`** (optional): `npm`, `yarn`, or `pnpm`; defaults to `npm` if omitted. - ## Development / Installation ### Install Dependencies @@ -152,8 +163,12 @@ After that you can now execute the cli via ```patternfly-cli``` command in the t ### Releasing -This project uses [semantic-release](https://semantic-release.gitbook.io/) to automate versioning and releases based on [Conventional Commits](https://www.conventionalcommits.org/). +This project uses [semantic-release](https://semantic-release.gitbook.io/) to automate versioning and releases +based on [Conventional Commits](https://www.conventionalcommits.org/). -- **CI**: Pushing to `main` runs the release workflow. If there are commits that warrant a release (e.g. `feat:`, `fix:`, `BREAKING CHANGE:`), it will create a GitHub release, update `CHANGELOG.md`, and bump the version in `package.json`. +- **CI**: Pushing to `main` runs the release workflow. If there are commits that warrant a release (e.g. `feat:`, + `fix:`, `BREAKING CHANGE:`), it will create a GitHub release, update `CHANGELOG.md`, and bump the version in + `package.json`. - **Local dry run**: `npx semantic-release --dry-run` (no push or publish). -- **npm publish**: By default only GitHub releases are created. To publish to npm, set the `NPM_TOKEN` secret in the repo and set `"npmPublish": true` for the `@semantic-release/npm` plugin in `.releaserc.json`. +- **npm publish**: By default only GitHub releases are created. To publish to npm, set the `NPM_TOKEN` secret in the + repo and set `"npmPublish": true` for the `@semantic-release/npm` plugin in `.releaserc.json`. diff --git a/package-lock.json b/package-lock.json index 5cb1a43..612ef70 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16,7 +16,8 @@ "inquirer": "^9.3.5" }, "bin": { - "patternfly-cli": "dist/cli.js" + "patternfly-cli": "dist/cli.js", + "pf": "dist/cli.js" }, "devDependencies": { "@eslint/js": "^10.0.1", @@ -34,6 +35,7 @@ "@types/node": "^24.10.1", "eslint": "^10.0.2", "jest": "^29.7.0", + "markdownlint-cli": "^0.43.0", "semantic-release": "^24.2.0", "ts-jest": "^29.4.5", "typescript": "^5.9.3", @@ -845,6 +847,39 @@ "node": ">=18" } }, + "node_modules/@isaacs/balanced-match": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@isaacs/balanced-match/-/balanced-match-4.0.1.tgz", + "integrity": "sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/@isaacs/brace-expansion": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@isaacs/brace-expansion/-/brace-expansion-5.0.1.tgz", + "integrity": "sha512-WMz71T1JS624nWj2n2fnYAuPovhv7EUhk69R6i9dsVyzxt5eM3bjwvgk9L+APE1TRscGysAVMANkB0jh0LQZrQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@isaacs/balanced-match": "^4.0.1" + }, + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/@isaacs/cliui": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-9.0.0.tgz", + "integrity": "sha512-AokJm4tuBHillT+FpMtxQ60n8ObyXBatq7jD2/JA9dxbDDokKQm8KMht5ibGzLVU9IJDIKK4TPKgMHEYMn3lMg==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=18" + } + }, "node_modules/@istanbuljs/load-nyc-config": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", @@ -4319,6 +4354,19 @@ "dev": true, "license": "MIT" }, + "node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, "node_modules/env-ci": { "version": "11.2.0", "resolved": "https://registry.npmjs.org/env-ci/-/env-ci-11.2.0.tgz", @@ -5084,6 +5132,23 @@ "dev": true, "license": "ISC" }, + "node_modules/foreground-child": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", + "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", + "dev": true, + "license": "ISC", + "dependencies": { + "cross-spawn": "^7.0.6", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/from2": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz", @@ -5927,6 +5992,22 @@ "node": ">=8" } }, + "node_modules/jackspeak": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-4.2.3.tgz", + "integrity": "sha512-ykkVRwrYvFm1nb2AJfKKYPr0emF6IiXDYUaFx4Zn9ZuIH7MrzEZ3sD5RlqGXNRpHtvUHJyOnCEFxOlNDtGo7wg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/cliui": "^9.0.0" + }, + "engines": { + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/java-properties": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/java-properties/-/java-properties-1.0.2.tgz", @@ -7524,6 +7605,13 @@ "node": ">=6" } }, + "node_modules/jsonc-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.3.1.tgz", + "integrity": "sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ==", + "dev": true, + "license": "MIT" + }, "node_modules/jsonfile": { "version": "6.2.0", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.0.tgz", @@ -7536,6 +7624,16 @@ "graceful-fs": "^4.1.6" } }, + "node_modules/jsonpointer": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-5.0.1.tgz", + "integrity": "sha512-p/nXbhSEcu3pZRdkW1OfJhpsVtW1gd4Wa1fnQc9YLiTfAjn0312eMKimbdIQzuZl9aa9xUGaRlP9T/CJE/ditQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/keyv": { "version": "4.5.4", "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", @@ -7587,6 +7685,16 @@ "dev": true, "license": "MIT" }, + "node_modules/linkify-it": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.0.tgz", + "integrity": "sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "uc.micro": "^2.0.0" + } + }, "node_modules/load-json-file": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", @@ -7810,6 +7918,157 @@ "tmpl": "1.0.5" } }, + "node_modules/markdown-it": { + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.1.0.tgz", + "integrity": "sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1", + "entities": "^4.4.0", + "linkify-it": "^5.0.0", + "mdurl": "^2.0.0", + "punycode.js": "^2.3.1", + "uc.micro": "^2.1.0" + }, + "bin": { + "markdown-it": "bin/markdown-it.mjs" + } + }, + "node_modules/markdown-it/node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/markdownlint": { + "version": "0.36.1", + "resolved": "https://registry.npmjs.org/markdownlint/-/markdownlint-0.36.1.tgz", + "integrity": "sha512-s73fU2CQN7WCgjhaQUQ8wYESQNzGRNOKDd+3xgVqu8kuTEhmwepd/mxOv1LR2oV046ONrTLBFsM7IoKWNvmy5g==", + "dev": true, + "license": "MIT", + "dependencies": { + "markdown-it": "14.1.0", + "markdownlint-micromark": "0.1.12" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/DavidAnson" + } + }, + "node_modules/markdownlint-cli": { + "version": "0.43.0", + "resolved": "https://registry.npmjs.org/markdownlint-cli/-/markdownlint-cli-0.43.0.tgz", + "integrity": "sha512-6vwurKK4B21eyYzwgX6ph13cZS7hE6LZfcS8QyD722CyxVD2RtAvbZK2p7k+FZbbKORulEuwl+hJaEq1l6/hoQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "commander": "~12.1.0", + "glob": "~11.0.0", + "ignore": "~6.0.2", + "js-yaml": "^4.1.0", + "jsonc-parser": "~3.3.1", + "jsonpointer": "5.0.1", + "markdownlint": "~0.36.1", + "minimatch": "~10.0.1", + "run-con": "~1.3.2", + "smol-toml": "~1.3.1" + }, + "bin": { + "markdownlint": "markdownlint.js" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/markdownlint-cli/node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/markdownlint-cli/node_modules/glob": { + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-11.0.3.tgz", + "integrity": "sha512-2Nim7dha1KVkaiF4q6Dj+ngPPMdfvLJEOpZk/jKiUAkqKebpGAWQXAq9z1xu9HKu5lWfqw/FASuccEjyznjPaA==", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", + "dev": true, + "license": "ISC", + "dependencies": { + "foreground-child": "^3.3.1", + "jackspeak": "^4.1.1", + "minimatch": "^10.0.3", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^2.0.0" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "engines": { + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/markdownlint-cli/node_modules/ignore": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-6.0.2.tgz", + "integrity": "sha512-InwqeHHN2XpumIkMvpl/DCJVrAHgCsG5+cn1XlnLWGwtZBm8QJfSusItfrwx81CTp5agNZqpKU2J/ccC5nGT4A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/markdownlint-cli/node_modules/js-yaml": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", + "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/markdownlint-cli/node_modules/minimatch": { + "version": "10.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.0.3.tgz", + "integrity": "sha512-IPZ167aShDZZUMdRk66cyQAW3qr0WzbHkPdMYa8bzZhlHhO3jALbKdxcaak7W9FfT2rZNpQuUu4Od7ILEpXSaw==", + "dev": true, + "license": "ISC", + "dependencies": { + "@isaacs/brace-expansion": "^5.0.0" + }, + "engines": { + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/markdownlint-micromark": { + "version": "0.1.12", + "resolved": "https://registry.npmjs.org/markdownlint-micromark/-/markdownlint-micromark-0.1.12.tgz", + "integrity": "sha512-RlB6EwMGgc0sxcIhOQ2+aq7Zw1V2fBnzbXKGgYK/mVWdT7cz34fteKSwfYeo4rL6+L/q2tyC9QtD/PgZbkdyJQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/DavidAnson" + } + }, "node_modules/marked": { "version": "15.0.12", "resolved": "https://registry.npmjs.org/marked/-/marked-15.0.12.tgz", @@ -7887,6 +8146,13 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, + "node_modules/mdurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-2.0.0.tgz", + "integrity": "sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==", + "dev": true, + "license": "MIT" + }, "node_modules/meow": { "version": "13.2.0", "resolved": "https://registry.npmjs.org/meow/-/meow-13.2.0.tgz", @@ -7977,6 +8243,16 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/minipass": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz", + "integrity": "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, "node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", @@ -10375,6 +10651,13 @@ "node": ">=6" } }, + "node_modules/package-json-from-dist": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", + "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", + "dev": true, + "license": "BlueOak-1.0.0" + }, "node_modules/parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", @@ -10478,6 +10761,33 @@ "dev": true, "license": "MIT" }, + "node_modules/path-scurry": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.2.tgz", + "integrity": "sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^11.0.0", + "minipass": "^7.1.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/path-scurry/node_modules/lru-cache": { + "version": "11.3.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.3.5.tgz", + "integrity": "sha512-NxVFwLAnrd9i7KUBxC4DrUhmgjzOs+1Qm50D3oF1/oL+r1NpZ4gA7xvG0/zJ8evR7zIKn4vLf7qTNduWFtCrRw==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": "20 || >=22" + } + }, "node_modules/path-type": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", @@ -10736,6 +11046,16 @@ "node": ">=6" } }, + "node_modules/punycode.js": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode.js/-/punycode.js-2.3.1.tgz", + "integrity": "sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/pure-rand": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.1.0.tgz", @@ -11030,6 +11350,32 @@ "node": ">=0.12.0" } }, + "node_modules/run-con": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/run-con/-/run-con-1.3.2.tgz", + "integrity": "sha512-CcfE+mYiTcKEzg0IqS08+efdnH0oJ3zV0wSUFBNrMHMuxCtXvBCLzCJHatwuXDcu/RlhjTziTo/a1ruQik6/Yg==", + "dev": true, + "license": "(BSD-2-Clause OR MIT OR Apache-2.0)", + "dependencies": { + "deep-extend": "^0.6.0", + "ini": "~4.1.0", + "minimist": "^1.2.8", + "strip-json-comments": "~3.1.1" + }, + "bin": { + "run-con": "cli.js" + } + }, + "node_modules/run-con/node_modules/ini": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/ini/-/ini-4.1.3.tgz", + "integrity": "sha512-X7rqawQBvfdjS10YU1y1YVreA3SsLrW9dX2CewP2EbBJM4ypVNLDkO5y04gejPwKIY9lR+7r9gn3rFPt/kmWFg==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, "node_modules/run-parallel": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", @@ -14086,6 +14432,19 @@ "node": ">=8" } }, + "node_modules/smol-toml": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/smol-toml/-/smol-toml-1.3.4.tgz", + "integrity": "sha512-UOPtVuYkzYGee0Bd2Szz8d2G3RfMfJ2t3qVdZUAozZyAk+a0Sxa+QKix0YCwjL/A1RR0ar44nCxaoN9FxdJGwA==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">= 18" + }, + "funding": { + "url": "https://github.com/sponsors/cyyynthia" + } + }, "node_modules/source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", @@ -14837,6 +15196,13 @@ "typescript": ">=4.8.4 <6.0.0" } }, + "node_modules/uc.micro": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-2.1.0.tgz", + "integrity": "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==", + "dev": true, + "license": "MIT" + }, "node_modules/uglify-js": { "version": "3.19.3", "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.19.3.tgz", diff --git a/package.json b/package.json index 93da584..c5c3fed 100644 --- a/package.json +++ b/package.json @@ -18,14 +18,18 @@ "start": "node dist/cli.js", "test": "jest", "semantic-release": "semantic-release", - "lint": "eslint src", - "lint:fix": "eslint src --fix" + "lint": "npm run lint:js && npm run lint:md", + "lint:js": "eslint src", + "lint:js:fix": "eslint src --fix", + "lint:md": "markdownlint '**/*.md' --ignore node_modules --ignore .agentready", + "lint:md:fix": "markdownlint '**/*.md' --ignore node_modules --ignore .agentready --fix", + "lint:fix": "npm run lint:js:fix && npm run lint:md:fix" }, "jest": { "preset": "ts-jest", "testEnvironment": "node", "testMatch": [ - "**/__tests__/**/*.test.ts" + "**/tests/**/*.test.ts" ], "moduleFileExtensions": [ "ts", @@ -73,6 +77,7 @@ "@types/node": "^24.10.1", "eslint": "^10.0.2", "jest": "^29.7.0", + "markdownlint-cli": "^0.43.0", "semantic-release": "^24.2.0", "ts-jest": "^29.4.5", "typescript": "^5.9.3", diff --git a/src/__tests__/cli.test.ts b/tests/cli.test.ts similarity index 96% rename from src/__tests__/cli.test.ts rename to tests/cli.test.ts index 97f45e0..ecbc207 100644 --- a/src/__tests__/cli.test.ts +++ b/tests/cli.test.ts @@ -1,9 +1,9 @@ import path from 'path'; import fs from 'fs-extra'; -import { loadCustomTemplates, mergeTemplates } from '../template-loader.js'; -import templates from '../templates.js'; +import { loadCustomTemplates, mergeTemplates } from '../src/template-loader.js'; +import templates from '../src/templates.js'; -const fixturesDir = path.join(process.cwd(), 'src', '__tests__', 'fixtures'); +const fixturesDir = path.join(process.cwd(), 'tests', 'fixtures'); describe('loadCustomTemplates', () => { const exitSpy = jest.spyOn(process, 'exit').mockImplementation(((code?: number) => { diff --git a/src/__tests__/create.test.ts b/tests/create.test.ts similarity index 96% rename from src/__tests__/create.test.ts rename to tests/create.test.ts index db19eff..4442263 100644 --- a/src/__tests__/create.test.ts +++ b/tests/create.test.ts @@ -23,8 +23,8 @@ jest.mock('execa', () => ({ execa: jest.fn(), })); -jest.mock('../github.js', () => ({ - ...jest.requireActual('../github.js'), +jest.mock('../src/github.js', () => ({ + ...jest.requireActual('../src/github.js'), offerAndCreateGitHubRepo: jest.fn(), })); @@ -32,9 +32,9 @@ import path from 'path'; import fs from 'fs-extra'; import { execa } from 'execa'; import inquirer from 'inquirer'; -import { sanitizeRepoName, offerAndCreateGitHubRepo } from '../github.js'; -import { runCreate } from '../create.js'; -import { defaultTemplates } from '../templates.js'; +import { sanitizeRepoName, offerAndCreateGitHubRepo } from '../src/github.js'; +import { runCreate } from '../src/create.js'; +import { defaultTemplates } from '../src/templates.js'; /** Partial `fs-extra` mock: use `jest.Mock` for `mockResolvedValue` (typed mocks infer `never` here). */ const mockPathExists = fs.pathExists as jest.MockedFunction & jest.Mock; @@ -290,7 +290,7 @@ describe('runCreate', () => { }); it('uses custom templates when templateFile option is provided', async () => { - const fixturesDir = path.join(process.cwd(), 'src', '__tests__', 'fixtures'); + const fixturesDir = path.join(process.cwd(), 'tests', 'fixtures'); const customPath = path.join(fixturesDir, 'valid-templates.json'); setupHappyPathMocks(); mockPrompt.mockResolvedValueOnce(projectData); diff --git a/src/__tests__/fixtures/invalid-template-bad-options.json b/tests/fixtures/invalid-template-bad-options.json similarity index 100% rename from src/__tests__/fixtures/invalid-template-bad-options.json rename to tests/fixtures/invalid-template-bad-options.json diff --git a/src/__tests__/fixtures/invalid-template-missing-name.json b/tests/fixtures/invalid-template-missing-name.json similarity index 100% rename from src/__tests__/fixtures/invalid-template-missing-name.json rename to tests/fixtures/invalid-template-missing-name.json diff --git a/src/__tests__/fixtures/not-array.json b/tests/fixtures/not-array.json similarity index 100% rename from src/__tests__/fixtures/not-array.json rename to tests/fixtures/not-array.json diff --git a/src/__tests__/fixtures/valid-templates.json b/tests/fixtures/valid-templates.json similarity index 100% rename from src/__tests__/fixtures/valid-templates.json rename to tests/fixtures/valid-templates.json diff --git a/src/__tests__/gh-pages.test.ts b/tests/gh-pages.test.ts similarity index 99% rename from src/__tests__/gh-pages.test.ts rename to tests/gh-pages.test.ts index 276cc26..5797b5b 100644 --- a/src/__tests__/gh-pages.test.ts +++ b/tests/gh-pages.test.ts @@ -19,7 +19,7 @@ jest.mock('gh-pages', () => ({ }, })); -jest.mock('../github.js', () => ({ +jest.mock('../src/github.js', () => ({ checkGhAuth: jest.fn().mockResolvedValue({ ok: false }), })); @@ -32,7 +32,7 @@ import { getGitHubPagesSiteUrl, normalizeDeployBasePath, runDeployToGitHubPages, -} from '../gh-pages.js'; +} from '../src/gh-pages.js'; const mockPathExists = fs.pathExists as jest.MockedFunction; const mockReadJson = fs.readJson as jest.MockedFunction; diff --git a/src/__tests__/git-user-config.test.ts b/tests/git-user-config.test.ts similarity index 97% rename from src/__tests__/git-user-config.test.ts rename to tests/git-user-config.test.ts index dacb3cc..9f0ccee 100644 --- a/src/__tests__/git-user-config.test.ts +++ b/tests/git-user-config.test.ts @@ -10,7 +10,7 @@ jest.mock('execa', () => ({ import inquirer from 'inquirer'; import { execa } from 'execa'; -import { promptAndSetLocalGitUser } from '../git-user-config.js'; +import { promptAndSetLocalGitUser } from '../src/git-user-config.js'; const mockPrompt = inquirer.prompt as jest.MockedFunction; const mockExeca = execa as jest.MockedFunction; diff --git a/src/__tests__/github.test.ts b/tests/github.test.ts similarity index 99% rename from src/__tests__/github.test.ts rename to tests/github.test.ts index d030825..531618b 100644 --- a/src/__tests__/github.test.ts +++ b/tests/github.test.ts @@ -13,7 +13,7 @@ import { checkGhAuth, repoExists, createRepo, -} from '../github.js'; +} from '../src/github.js'; import { execa as mockExeca } from 'execa'; describe('sanitizeRepoName', () => { diff --git a/src/__tests__/load.test.ts b/tests/load.test.ts similarity index 98% rename from src/__tests__/load.test.ts rename to tests/load.test.ts index d4e880c..fc783e2 100644 --- a/src/__tests__/load.test.ts +++ b/tests/load.test.ts @@ -12,7 +12,7 @@ jest.mock('execa', () => ({ import fs from 'fs-extra'; import { execa } from 'execa'; -import { runLoad } from '../load.js'; +import { runLoad } from '../src/load.js'; const mockPathExists = fs.pathExists as jest.MockedFunction; const mockExeca = execa as jest.MockedFunction; diff --git a/src/__tests__/read-package-version.test.ts b/tests/read-package-version.test.ts similarity index 85% rename from src/__tests__/read-package-version.test.ts rename to tests/read-package-version.test.ts index 1d6fea8..0b80d98 100644 --- a/src/__tests__/read-package-version.test.ts +++ b/tests/read-package-version.test.ts @@ -1,9 +1,9 @@ import path from 'path'; import fs from 'fs-extra'; -import { readPackageVersion } from '../read-package-version.js'; +import { readPackageVersion } from '../src/read-package-version.js'; /** Repo root package.json (stable under Jest + ts-jest CommonJS emit; avoids cwd brittleness). */ -const repoPackageJson = path.join(__dirname, '../../package.json'); +const repoPackageJson = path.join(__dirname, '../package.json'); describe('readPackageVersion', () => { it('returns the version from the repo package.json', () => { diff --git a/src/__tests__/save.test.ts b/tests/save.test.ts similarity index 98% rename from src/__tests__/save.test.ts rename to tests/save.test.ts index fa90aa7..8d03690 100644 --- a/src/__tests__/save.test.ts +++ b/tests/save.test.ts @@ -17,15 +17,15 @@ jest.mock('inquirer', () => ({ }, })); -jest.mock('../github.js', () => ({ +jest.mock('../src/github.js', () => ({ offerAndCreateGitHubRepo: jest.fn(), })); import fs from 'fs-extra'; import { execa } from 'execa'; import inquirer from 'inquirer'; -import { offerAndCreateGitHubRepo } from '../github.js'; -import { runSave } from '../save.js'; +import { offerAndCreateGitHubRepo } from '../src/github.js'; +import { runSave } from '../src/save.js'; const mockPathExists = fs.pathExists as jest.MockedFunction; const mockExeca = execa as jest.MockedFunction; diff --git a/tsconfig.json b/tsconfig.json index f814415..31036b8 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,13 +1,9 @@ { - // Visit https://aka.ms/tsconfig to read more about this file "compilerOptions": { "module": "NodeNext", "moduleResolution": "nodenext", - // File Layout "rootDir": "./src", "outDir": "./dist", - // Environment Settings - // See also https://aka.ms/tsconfig/module "target": "esnext", "lib": [ "esnext" @@ -16,21 +12,17 @@ "node", "jest" ], - // Other Outputs "sourceMap": true, "declaration": true, "declarationMap": true, - // Stricter Typechecking Options "noUncheckedIndexedAccess": true, "exactOptionalPropertyTypes": true, - // Style Options "noImplicitReturns": true, "noImplicitOverride": true, "noUnusedLocals": true, "noUnusedParameters": true, "noFallthroughCasesInSwitch": true, "noPropertyAccessFromIndexSignature": true, - // Recommended Options "strict": true, "jsx": "react-jsx", "verbatimModuleSyntax": true, @@ -45,6 +37,6 @@ "src/**/*" ], "exclude": [ - "src/__tests__/**/*.test.ts" + "tests/**/*.test.ts" ] } \ No newline at end of file