Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Editor configuration, see https://editorconfig.org
root = true

[*]
charset = utf-8
indent_style = space
indent_size = 2
insert_final_newline = true
trim_trailing_whitespace = true

[*.ts]
quote_type = single
ij_typescript_use_double_quotes = false

[*.md]
max_line_length = off
trim_trailing_whitespace = false
40 changes: 35 additions & 5 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ name: 🚀 Build & Publish
on:
push:
tags:
- "v*"
- 'v*'

permissions:
id-token: write
Expand All @@ -12,11 +12,16 @@ permissions:

jobs:
publish:
name: 📦 Validate & Publish
name: 📦 Validate, publish & deploy
runs-on: ubuntu-latest
steps:
- name: 🗜️ Checkout
uses: actions/checkout@v7
with:
fetch-depth: 0

- name: 🔎 Verify tag targets master
run: test "$GITHUB_SHA" = "$(git rev-parse origin/master)"

- name: 🗜️ Setup Node
uses: actions/setup-node@v6
Expand Down Expand Up @@ -47,15 +52,23 @@ jobs:
- name: 🧪 Smoke-test npm package
run: yarn package:smoke

- name: 🔎 Verify artifact layout
run: |
test -f dist/portal/browser/index.html
test -x dist/quick-commitlint/bin/quick-commitlint
test -f dist/quick-commitlint/package.json

- name: 🚀 Publish npm
if: startsWith(github.ref, 'refs/tags/v') && contains(github.ref, 'beta') == false
run: cd dist && npm publish
working-directory: dist/quick-commitlint
run: npm publish
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_AUTH_TOKEN }}

- name: 🚀 Publish npm beta
if: startsWith(github.ref, 'refs/tags/v') && contains(github.ref, 'beta') == true
run: cd dist && npm publish --tag beta
working-directory: dist/quick-commitlint
run: npm publish --tag beta
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_AUTH_TOKEN }}

Expand All @@ -73,6 +86,23 @@ jobs:

- name: 🚀 Publish GitHub Packages
if: startsWith(github.ref, 'refs/tags/v') && contains(github.ref, 'beta') == false
run: cd dist && npm publish
working-directory: dist/quick-commitlint
run: npm publish
env:
NODE_AUTH_TOKEN: ${{ github.token }}

- name: 📦 Build portal app
run: yarn portal:build:pages

- name: 🔎 Verify prerendered pages
run: yarn portal:ssg:verify

- name: 🛠️ Copy index.html to 404.html
run: cp ./dist/portal/browser/index.html ./dist/portal/browser/404.html

- name: 🚀 Deploy Github Pages
uses: peaceiris/actions-gh-pages@v4
with:
deploy_key: ${{ secrets.ACTIONS_DEPLOY_KEY }}
publish_branch: gh-pages
publish_dir: ./dist/portal/browser
8 changes: 7 additions & 1 deletion .github/workflows/pull-request.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name: 🧪 Test PR

"on": pull_request
'on': pull_request

permissions:
contents: read
Expand Down Expand Up @@ -68,5 +68,11 @@ jobs:
- name: 🧪 Smoke-test npm package
run: yarn package:smoke

- name: 🔎 Verify artifact layout
run: |
test -f dist/portal/browser/index.html
test -x dist/quick-commitlint/bin/quick-commitlint
test -f dist/quick-commitlint/package.json

- name: 🏁 Benchmark performance gate
run: yarn benchmark
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ zig-cache/
zig-out/

# Node.js and packaging artifacts
.angular/
node_modules/
dist/
coverage/
Expand Down
12 changes: 12 additions & 0 deletions .prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"printWidth": 100,
"singleQuote": true,
"overrides": [
{
"files": "*.html",
"options": {
"parser": "angular"
}
}
]
}
50 changes: 43 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
[![Zig 0.16.0](https://img.shields.io/badge/Zig-0.16.0-F7A41D?logo=zig&logoColor=white)](https://ziglang.org/)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)

[Documentation](https://celtian.github.io/quick-commitlint/) · [Source](https://github.com/Celtian/quick-commitlint)

<img
src="https://raw.githubusercontent.com/Celtian/quick-commitlint/master/docs/assets/terminal-demo.gif"
alt="Quick Commitlint terminal demo"
Expand All @@ -20,13 +22,13 @@

## ✨ Why use it?

| Feature | Details |
| --- | --- |
| ⚡ **Fast native executable** | Starts in about one millisecond without loading a JavaScript runtime. |
| 📦 **Zero runtime dependencies** | npm installs a standalone, statically linked Zig binary. |
| 🧩 **Familiar configuration** | Uses commitlint-style rule tuples with built-in conventional and Angular presets. |
| 🔒 **Strict and predictable** | Rejects malformed JSON, unknown options, duplicate keys, and invalid UTF-8. |
| 🌍 **International subjects** | Counts Unicode code points while keeping syntax checks fast and ASCII-based. |
| Feature | Details |
| -------------------------------- | --------------------------------------------------------------------------------- |
| ⚡ **Fast native executable** | Starts in about one millisecond without loading a JavaScript runtime. |
| 📦 **Zero runtime dependencies** | npm installs a standalone, statically linked Zig binary. |
| 🧩 **Familiar configuration** | Uses commitlint-style rule tuples with built-in conventional and Angular presets. |
| 🔒 **Strict and predictable** | Rejects malformed JSON, unknown options, duplicate keys, and invalid UTF-8. |
| 🌍 **International subjects** | Counts Unicode code points while keeping syntax checks fast and ASCII-based. |

## 🚀 Install

Expand Down Expand Up @@ -97,6 +99,25 @@ quick-commitlint [options] [commit-message-file]

Input must be UTF-8 and may use LF or CRLF line endings. Length rules count Unicode code points. Case rules use ASCII semantics so international subjects remain valid.

## 📚 Documentation portal

The documentation site is an English-only Angular 22 static application in `projects/portal`. It uses Angular Material/CDK, plain CSS with Material 3 system tokens, Tailwind CSS v4 helpers, and build-time Markdown rendering.

Run it locally:

```bash
yarn portal:start
```

Validate or build the prerendered site:

```bash
yarn portal:validate
yarn portal:build:pages
```

Every public route is prerendered for SEO. Pushing a `v*` tag that points at the current `master` commit runs `.github/workflows/main.yml`, publishes the native packages, and then deploys `dist/portal/browser` to the `gh-pages` branch as the workflow's final step. The repository must provide the `ACTIONS_DEPLOY_KEY` secret and configure GitHub Pages to publish from `gh-pages`.

## 🏗️ Development

Requirements:
Expand All @@ -121,6 +142,21 @@ yarn copy-files
yarn package:smoke
```

Build artifacts are kept as sibling outputs with no overlap between the website and published native package:

```text
dist/
├── portal/
│ └── browser/ # Angular SSG output for GitHub Pages
└── quick-commitlint/
├── bin/quick-commitlint # Native Zig executable
├── LICENSE
├── README.md
└── package.json # Publishable npm manifest
```

`yarn clean` removes the complete `dist` tree. Portal builds recreate only `dist/portal`; the release packaging scripts recreate only `dist/quick-commitlint`.

Run the cold-process benchmark against `@commitlint/cli`:

```bash
Expand Down
99 changes: 99 additions & 0 deletions angular.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
{
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
"version": 1,
"cli": {
"packageManager": "yarn",
"schematicCollections": ["angular-eslint"],
"analytics": false
},
"newProjectRoot": "projects",
"projects": {
"portal": {
"projectType": "application",
"schematics": {
"@schematics/angular:component": {
"style": "css"
}
},
"root": "projects/portal",
"sourceRoot": "projects/portal/src",
"prefix": "app",
"architect": {
"build": {
"builder": "@angular/build:application",
"options": {
"outputPath": "dist/portal",
"browser": "projects/portal/src/main.ts",
"tsConfig": "projects/portal/tsconfig.app.json",
"inlineStyleLanguage": "css",
"assets": [
{
"glob": "**/*",
"input": "projects/portal/public"
},
{
"glob": "terminal-demo.gif",
"input": "docs/assets",
"output": "assets"
}
],
"styles": ["projects/portal/src/tailwind.css", "projects/portal/src/styles.css"],
"server": "projects/portal/src/main.server.ts",
"outputMode": "static",
"loader": {
".md": "text"
},
"security": {
"allowedHosts": []
}
},
"configurations": {
"production": {
"budgets": [
{
"type": "initial",
"maximumWarning": "750kB",
"maximumError": "1MB"
},
{
"type": "anyComponentStyle",
"maximumWarning": "8kB",
"maximumError": "12kB"
}
],
"outputHashing": "all"
},
"development": {
"optimization": false,
"extractLicenses": false,
"sourceMap": true
}
},
"defaultConfiguration": "production"
},
"serve": {
"builder": "@angular/build:dev-server",
"configurations": {
"production": {
"buildTarget": "portal:build:production"
},
"development": {
"buildTarget": "portal:build:development"
}
},
"defaultConfiguration": "development"
},
"test": {
"builder": "@angular/build:unit-test"
},
"lint": {
"builder": "@angular-eslint/builder:lint",
"options": {
"lintFilePatterns": ["projects/portal/src/**/*.ts", "projects/portal/src/**/*.html"],
"eslintConfig": "projects/portal/eslint.config.js"
}
}
}
}
}
}
44 changes: 44 additions & 0 deletions eslint.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
// @ts-check
const eslint = require('@eslint/js');
const { defineConfig } = require('eslint/config');
const tseslint = require('typescript-eslint');
const angular = require('angular-eslint');

module.exports = defineConfig([
{
ignores: ['**/dist/**', '**/.angular/**'],
},
{
files: ['**/*.ts'],
extends: [
eslint.configs.recommended,
tseslint.configs.recommended,
tseslint.configs.stylistic,
angular.configs.tsRecommended,
],
processor: angular.processInlineTemplates,
rules: {
'@angular-eslint/directive-selector': [
'error',
{
type: 'attribute',
prefix: 'app',
style: 'camelCase',
},
],
'@angular-eslint/component-selector': [
'error',
{
type: 'element',
prefix: 'app',
style: 'kebab-case',
},
],
},
},
{
files: ['**/*.html'],
extends: [angular.configs.templateRecommended, angular.configs.templateAccessibility],
rules: {},
},
]);
Loading
Loading