inclean 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- inclean-0.1.0/.github/workflows/release.yml +199 -0
- inclean-0.1.0/.github/workflows/test.yml +56 -0
- inclean-0.1.0/.gitignore +12 -0
- inclean-0.1.0/CHANGELOG.md +58 -0
- inclean-0.1.0/CLAUDE.md +97 -0
- inclean-0.1.0/CONTRIBUTING.md +93 -0
- inclean-0.1.0/Cargo.lock +536 -0
- inclean-0.1.0/Cargo.toml +36 -0
- inclean-0.1.0/LICENSE +28 -0
- inclean-0.1.0/PKG-INFO +116 -0
- inclean-0.1.0/README.md +99 -0
- inclean-0.1.0/docs/architecture.md +171 -0
- inclean-0.1.0/docs/configuration.md +442 -0
- inclean-0.1.0/pyproject.toml +26 -0
- inclean-0.1.0/src/cli/apply.rs +60 -0
- inclean-0.1.0/src/cli/check.rs +201 -0
- inclean-0.1.0/src/cli/diff.rs +17 -0
- inclean-0.1.0/src/cli/explain.rs +206 -0
- inclean-0.1.0/src/cli/init.rs +129 -0
- inclean-0.1.0/src/cli/mod.rs +100 -0
- inclean-0.1.0/src/config/constants.rs +554 -0
- inclean-0.1.0/src/config/discover.rs +397 -0
- inclean-0.1.0/src/config/inherit.rs +844 -0
- inclean-0.1.0/src/config/mod.rs +4 -0
- inclean-0.1.0/src/config/schema.rs +551 -0
- inclean-0.1.0/src/index/header_index.rs +173 -0
- inclean-0.1.0/src/index/mod.rs +1 -0
- inclean-0.1.0/src/lex/include_line.rs +530 -0
- inclean-0.1.0/src/lex/mod.rs +1 -0
- inclean-0.1.0/src/lib.rs +8 -0
- inclean-0.1.0/src/main.rs +5 -0
- inclean-0.1.0/src/pipeline/mod.rs +1 -0
- inclean-0.1.0/src/pipeline/run.rs +952 -0
- inclean-0.1.0/src/rule/action.rs +1299 -0
- inclean-0.1.0/src/rule/engine.rs +1121 -0
- inclean-0.1.0/src/rule/glob.rs +185 -0
- inclean-0.1.0/src/rule/mod.rs +4 -0
- inclean-0.1.0/src/rule/tree.rs +301 -0
- inclean-0.1.0/src/util.rs +16 -0
- inclean-0.1.0/src/validate/allowed.rs +179 -0
- inclean-0.1.0/src/validate/mod.rs +1 -0
- inclean-0.1.0/tests/fixtures/action-error/inclean.toml +17 -0
- inclean-0.1.0/tests/fixtures/action-error/src/main.c +1 -0
- inclean-0.1.0/tests/fixtures/angle-allowed/inclean.toml +23 -0
- inclean-0.1.0/tests/fixtures/angle-allowed/include/mylib/foo.h +0 -0
- inclean-0.1.0/tests/fixtures/angle-allowed/src/main.c +3 -0
- inclean-0.1.0/tests/fixtures/auto-file-dir/inclean.toml +19 -0
- inclean-0.1.0/tests/fixtures/auto-file-dir/lib/inner/core.c +1 -0
- inclean-0.1.0/tests/fixtures/auto-file-dir/lib/inner/helper.h +0 -0
- inclean-0.1.0/tests/fixtures/auto-file-dir/lib/outer.c +1 -0
- inclean-0.1.0/tests/fixtures/child-wider/inclean.toml +13 -0
- inclean-0.1.0/tests/fixtures/child-wider/main.c +1 -0
- inclean-0.1.0/tests/fixtures/cross-chain/inclean.toml +14 -0
- inclean-0.1.0/tests/fixtures/cross-chain/src/main.c +1 -0
- inclean-0.1.0/tests/fixtures/flat-library/inclean.toml +22 -0
- inclean-0.1.0/tests/fixtures/flat-library/include/mylib/internal/bar.h +4 -0
- inclean-0.1.0/tests/fixtures/flat-library/include/mylib/internal/foo.h +4 -0
- inclean-0.1.0/tests/fixtures/flat-library/src/main.c +7 -0
- inclean-0.1.0/tests/fixtures/layer5-ambiguity/inclean.toml +13 -0
- inclean-0.1.0/tests/fixtures/layer5-ambiguity/src/a/foo.h +0 -0
- inclean-0.1.0/tests/fixtures/layer5-ambiguity/src/b/foo.h +0 -0
- inclean-0.1.0/tests/fixtures/layer5-ambiguity/src/main.c +1 -0
- inclean-0.1.0/tests/fixtures/layer5-disambiguation/inclean.toml +32 -0
- inclean-0.1.0/tests/fixtures/layer5-disambiguation/include/mylib/internal/beta.h +0 -0
- inclean-0.1.0/tests/fixtures/layer5-disambiguation/include/mylib/public/alpha.h +0 -0
- inclean-0.1.0/tests/fixtures/layer5-disambiguation/src/main.c +2 -0
- inclean-0.1.0/tests/fixtures/layer5-under/inclean.toml +19 -0
- inclean-0.1.0/tests/fixtures/layer5-under/src/internal/foo.h +0 -0
- inclean-0.1.0/tests/fixtures/layer5-under/src/main.c +1 -0
- inclean-0.1.0/tests/fixtures/multi-module-library/inclean.toml +10 -0
- inclean-0.1.0/tests/fixtures/multi-module-library/include/modA/a1.h +0 -0
- inclean-0.1.0/tests/fixtures/multi-module-library/include/modA/a2.h +0 -0
- inclean-0.1.0/tests/fixtures/multi-module-library/include/modB/b1.h +0 -0
- inclean-0.1.0/tests/fixtures/multi-module-library/include/modB/b2.h +0 -0
- inclean-0.1.0/tests/fixtures/multi-module-library/src/moduleA/code.c +2 -0
- inclean-0.1.0/tests/fixtures/multi-module-library/src/moduleA/inclean.toml +5 -0
- inclean-0.1.0/tests/fixtures/multi-module-library/src/moduleB/code.c +2 -0
- inclean-0.1.0/tests/fixtures/multi-module-library/src/moduleB/inclean.toml +5 -0
- inclean-0.1.0/tests/fixtures/nested-library/inclean.toml +12 -0
- inclean-0.1.0/tests/fixtures/nested-library/include/mylib/core/api.h +0 -0
- inclean-0.1.0/tests/fixtures/nested-library/include/mylib/core/detail/alpha.h +0 -0
- inclean-0.1.0/tests/fixtures/nested-library/include/mylib/core/detail/beta.h +0 -0
- inclean-0.1.0/tests/fixtures/nested-library/src/core/impl.c +1 -0
- inclean-0.1.0/tests/fixtures/nested-library/src/core/more/deep.c +1 -0
- inclean-0.1.0/tests/fixtures/nested-library/src/main.c +2 -0
- inclean-0.1.0/tests/fixtures/trailing-comment-policies/inclean.toml +60 -0
- inclean-0.1.0/tests/fixtures/trailing-comment-policies/include/mylib/helper/qux.h +2 -0
- inclean-0.1.0/tests/fixtures/trailing-comment-policies/include/mylib/internal/foo.h +2 -0
- inclean-0.1.0/tests/fixtures/trailing-comment-policies/include/mylib/legacy/old.h +2 -0
- inclean-0.1.0/tests/fixtures/trailing-comment-policies/include/mylib/private/bar.h +2 -0
- inclean-0.1.0/tests/fixtures/trailing-comment-policies/include/mylib/private/baz.h +2 -0
- inclean-0.1.0/tests/fixtures/trailing-comment-policies/src/main.c +9 -0
- inclean-0.1.0/tests/fixtures/validation-keep/inclean.toml +13 -0
- inclean-0.1.0/tests/fixtures/validation-keep/include/.gitkeep +0 -0
- inclean-0.1.0/tests/fixtures/validation-keep/src/main.c +1 -0
- inclean-0.1.0/tests/integration/action_error.rs +34 -0
- inclean-0.1.0/tests/integration/angle_allowed.rs +28 -0
- inclean-0.1.0/tests/integration/auto_file_dir.rs +52 -0
- inclean-0.1.0/tests/integration/child_wider.rs +30 -0
- inclean-0.1.0/tests/integration/common.rs +37 -0
- inclean-0.1.0/tests/integration/cross_chain.rs +24 -0
- inclean-0.1.0/tests/integration/flat_library.rs +95 -0
- inclean-0.1.0/tests/integration/init_template.rs +30 -0
- inclean-0.1.0/tests/integration/layer5_ambiguity.rs +32 -0
- inclean-0.1.0/tests/integration/layer5_disambiguation.rs +29 -0
- inclean-0.1.0/tests/integration/layer5_under.rs +32 -0
- inclean-0.1.0/tests/integration/multi_module.rs +47 -0
- inclean-0.1.0/tests/integration/nested_library.rs +63 -0
- inclean-0.1.0/tests/integration/trailing_comment.rs +107 -0
- inclean-0.1.0/tests/integration/validation_keep.rs +30 -0
- inclean-0.1.0/tests/integration.rs +39 -0
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
name: release
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches:
|
|
6
|
+
- main
|
|
7
|
+
tags:
|
|
8
|
+
- v*.*.*
|
|
9
|
+
|
|
10
|
+
permissions:
|
|
11
|
+
contents: write
|
|
12
|
+
|
|
13
|
+
concurrency:
|
|
14
|
+
group: release-${{ github.ref }}
|
|
15
|
+
cancel-in-progress: false
|
|
16
|
+
|
|
17
|
+
env:
|
|
18
|
+
CARGO_TERM_COLOR: always
|
|
19
|
+
BIN_NAME: inclean
|
|
20
|
+
|
|
21
|
+
jobs:
|
|
22
|
+
check-tag:
|
|
23
|
+
name: validate SemVer tag
|
|
24
|
+
if: github.ref_type == 'tag'
|
|
25
|
+
runs-on: ubuntu-latest
|
|
26
|
+
steps:
|
|
27
|
+
- uses: actions/checkout@v6
|
|
28
|
+
|
|
29
|
+
- name: validate tag format and Cargo.toml version match
|
|
30
|
+
shell: bash
|
|
31
|
+
env:
|
|
32
|
+
REF_NAME: ${{ github.ref_name }}
|
|
33
|
+
run: |
|
|
34
|
+
set -euo pipefail
|
|
35
|
+
# SemVer 2.0.0 with required leading "v":
|
|
36
|
+
# vMAJOR.MINOR.PATCH[-prerelease][+build]
|
|
37
|
+
semver_re='^v(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)(-((0|[1-9][0-9]*|[0-9]*[a-zA-Z-][0-9a-zA-Z-]*)(\.(0|[1-9][0-9]*|[0-9]*[a-zA-Z-][0-9a-zA-Z-]*))*))?(\+([0-9a-zA-Z-]+(\.[0-9a-zA-Z-]+)*))?$'
|
|
38
|
+
if [[ ! "$REF_NAME" =~ $semver_re ]]; then
|
|
39
|
+
echo "::error::tag '$REF_NAME' is not valid SemVer (expected vMAJOR.MINOR.PATCH[-prerelease][+build])"
|
|
40
|
+
exit 1
|
|
41
|
+
fi
|
|
42
|
+
|
|
43
|
+
tag_version="${REF_NAME#v}"
|
|
44
|
+
cargo_version=$(awk -F'"' '/^version = "/ { print $2; exit }' Cargo.toml)
|
|
45
|
+
|
|
46
|
+
if [[ -z "$cargo_version" ]]; then
|
|
47
|
+
echo "::error::could not extract version from Cargo.toml"
|
|
48
|
+
exit 1
|
|
49
|
+
fi
|
|
50
|
+
|
|
51
|
+
if [[ "$tag_version" != "$cargo_version" ]]; then
|
|
52
|
+
echo "::error::tag version '$tag_version' does not match Cargo.toml version '$cargo_version' — bump Cargo.toml before tagging"
|
|
53
|
+
exit 1
|
|
54
|
+
fi
|
|
55
|
+
|
|
56
|
+
echo "tag '$REF_NAME' matches Cargo.toml version '$cargo_version'"
|
|
57
|
+
|
|
58
|
+
verify:
|
|
59
|
+
needs: check-tag
|
|
60
|
+
name: verify
|
|
61
|
+
uses: ./.github/workflows/test.yml
|
|
62
|
+
|
|
63
|
+
publish-crate:
|
|
64
|
+
name: publish to crates.io
|
|
65
|
+
needs: [verify, check-tag]
|
|
66
|
+
runs-on: ubuntu-latest
|
|
67
|
+
steps:
|
|
68
|
+
- uses: actions/checkout@v6
|
|
69
|
+
|
|
70
|
+
- uses: dtolnay/rust-toolchain@stable
|
|
71
|
+
|
|
72
|
+
- uses: Swatinem/rust-cache@v2
|
|
73
|
+
|
|
74
|
+
- name: cargo publish
|
|
75
|
+
run: cargo publish --token "${{ secrets.CARGO_REGISTRY_TOKEN }}"
|
|
76
|
+
|
|
77
|
+
build:
|
|
78
|
+
name: build ${{ matrix.triple }}
|
|
79
|
+
needs: [verify, check-tag]
|
|
80
|
+
runs-on: ${{ matrix.os }}
|
|
81
|
+
strategy:
|
|
82
|
+
fail-fast: false
|
|
83
|
+
matrix:
|
|
84
|
+
include:
|
|
85
|
+
- os: ubuntu-latest
|
|
86
|
+
target: x86_64
|
|
87
|
+
triple: x86_64-unknown-linux-gnu
|
|
88
|
+
archive: tar.gz
|
|
89
|
+
- os: ubuntu-latest
|
|
90
|
+
target: aarch64
|
|
91
|
+
triple: aarch64-unknown-linux-gnu
|
|
92
|
+
archive: tar.gz
|
|
93
|
+
- os: macos-latest
|
|
94
|
+
target: x86_64
|
|
95
|
+
triple: x86_64-apple-darwin
|
|
96
|
+
archive: tar.gz
|
|
97
|
+
- os: macos-latest
|
|
98
|
+
target: aarch64
|
|
99
|
+
triple: aarch64-apple-darwin
|
|
100
|
+
archive: tar.gz
|
|
101
|
+
- os: windows-latest
|
|
102
|
+
target: x64
|
|
103
|
+
triple: x86_64-pc-windows-msvc
|
|
104
|
+
archive: zip
|
|
105
|
+
steps:
|
|
106
|
+
- uses: actions/checkout@v6
|
|
107
|
+
|
|
108
|
+
- uses: PyO3/maturin-action@v1
|
|
109
|
+
with:
|
|
110
|
+
target: ${{ matrix.target }}
|
|
111
|
+
args: --release --out dist
|
|
112
|
+
manylinux: auto
|
|
113
|
+
sccache: "true"
|
|
114
|
+
|
|
115
|
+
- uses: actions/upload-artifact@v4
|
|
116
|
+
with:
|
|
117
|
+
name: wheels-${{ matrix.triple }}
|
|
118
|
+
path: dist/*.whl
|
|
119
|
+
if-no-files-found: error
|
|
120
|
+
|
|
121
|
+
- name: package binary (tar.gz)
|
|
122
|
+
if: matrix.archive == 'tar.gz'
|
|
123
|
+
shell: bash
|
|
124
|
+
run: |
|
|
125
|
+
set -euo pipefail
|
|
126
|
+
stage="${BIN_NAME}-${{ matrix.triple }}"
|
|
127
|
+
mkdir -p "bins/${stage}"
|
|
128
|
+
cp "target/${{ matrix.triple }}/release/${BIN_NAME}" "bins/${stage}/"
|
|
129
|
+
cp README.md LICENSE "bins/${stage}/"
|
|
130
|
+
tar -czf "bins/${stage}.tar.gz" -C bins "${stage}"
|
|
131
|
+
rm -rf "bins/${stage}"
|
|
132
|
+
|
|
133
|
+
- name: package binary (zip)
|
|
134
|
+
if: matrix.archive == 'zip'
|
|
135
|
+
shell: pwsh
|
|
136
|
+
run: |
|
|
137
|
+
$ErrorActionPreference = 'Stop'
|
|
138
|
+
$stage = "$env:BIN_NAME-${{ matrix.triple }}"
|
|
139
|
+
New-Item -ItemType Directory -Force -Path "bins/$stage" | Out-Null
|
|
140
|
+
Copy-Item "target/${{ matrix.triple }}/release/$env:BIN_NAME.exe" "bins/$stage/"
|
|
141
|
+
Copy-Item README.md, LICENSE "bins/$stage/"
|
|
142
|
+
Compress-Archive -Path "bins/$stage/*" -DestinationPath "bins/$stage.zip"
|
|
143
|
+
Remove-Item -Recurse -Force "bins/$stage"
|
|
144
|
+
|
|
145
|
+
- uses: actions/upload-artifact@v7
|
|
146
|
+
with:
|
|
147
|
+
name: bins-${{ matrix.triple }}
|
|
148
|
+
path: bins/*
|
|
149
|
+
if-no-files-found: error
|
|
150
|
+
|
|
151
|
+
sdist:
|
|
152
|
+
name: sdist
|
|
153
|
+
needs: [verify, check-tag]
|
|
154
|
+
runs-on: ubuntu-latest
|
|
155
|
+
steps:
|
|
156
|
+
- uses: actions/checkout@v6
|
|
157
|
+
|
|
158
|
+
- uses: PyO3/maturin-action@v1
|
|
159
|
+
with:
|
|
160
|
+
command: sdist
|
|
161
|
+
args: --out dist
|
|
162
|
+
|
|
163
|
+
- uses: actions/upload-artifact@v4
|
|
164
|
+
with:
|
|
165
|
+
name: wheels-sdist
|
|
166
|
+
path: dist/*.tar.gz
|
|
167
|
+
if-no-files-found: error
|
|
168
|
+
|
|
169
|
+
publish-pypi:
|
|
170
|
+
name: publish to PyPI
|
|
171
|
+
needs: [build, sdist]
|
|
172
|
+
runs-on: ubuntu-latest
|
|
173
|
+
permissions:
|
|
174
|
+
id-token: write
|
|
175
|
+
steps:
|
|
176
|
+
- uses: actions/download-artifact@v8
|
|
177
|
+
with:
|
|
178
|
+
pattern: wheels-*
|
|
179
|
+
path: dist
|
|
180
|
+
merge-multiple: true
|
|
181
|
+
|
|
182
|
+
- uses: pypa/gh-action-pypi-publish@release/v1
|
|
183
|
+
|
|
184
|
+
gh-release:
|
|
185
|
+
name: create GitHub Release
|
|
186
|
+
needs: [build, publish-crate]
|
|
187
|
+
runs-on: ubuntu-latest
|
|
188
|
+
steps:
|
|
189
|
+
- uses: actions/download-artifact@v8
|
|
190
|
+
with:
|
|
191
|
+
pattern: bins-*
|
|
192
|
+
path: dist
|
|
193
|
+
merge-multiple: true
|
|
194
|
+
|
|
195
|
+
- uses: softprops/action-gh-release@v2
|
|
196
|
+
with:
|
|
197
|
+
files: dist/*
|
|
198
|
+
generate_release_notes: true
|
|
199
|
+
fail_on_unmatched_files: true
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
name: test
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
workflow_call:
|
|
5
|
+
pull_request:
|
|
6
|
+
paths-ignore: &non-src-code-paths
|
|
7
|
+
- "**/*.md"
|
|
8
|
+
- "LICENSE"
|
|
9
|
+
- ".gitignore"
|
|
10
|
+
push:
|
|
11
|
+
branches: [main]
|
|
12
|
+
paths-ignore: *non-src-code-paths
|
|
13
|
+
|
|
14
|
+
concurrency:
|
|
15
|
+
group: test-${{ github.ref }}
|
|
16
|
+
cancel-in-progress: true
|
|
17
|
+
|
|
18
|
+
env:
|
|
19
|
+
CARGO_TERM_COLOR: always
|
|
20
|
+
RUSTFLAGS: -D warnings
|
|
21
|
+
|
|
22
|
+
jobs:
|
|
23
|
+
lint:
|
|
24
|
+
name: fmt + clippy
|
|
25
|
+
runs-on: ubuntu-latest
|
|
26
|
+
steps:
|
|
27
|
+
- uses: actions/checkout@v6
|
|
28
|
+
|
|
29
|
+
- uses: dtolnay/rust-toolchain@stable
|
|
30
|
+
with:
|
|
31
|
+
components: rustfmt, clippy
|
|
32
|
+
|
|
33
|
+
- uses: Swatinem/rust-cache@v2
|
|
34
|
+
|
|
35
|
+
- name: cargo fmt --check
|
|
36
|
+
run: cargo fmt --all -- --check
|
|
37
|
+
|
|
38
|
+
- name: cargo clippy
|
|
39
|
+
run: cargo clippy --all-targets --all-features
|
|
40
|
+
|
|
41
|
+
test:
|
|
42
|
+
needs: lint
|
|
43
|
+
name: test (${{ matrix.os }})
|
|
44
|
+
runs-on: ${{ matrix.os }}
|
|
45
|
+
strategy:
|
|
46
|
+
matrix:
|
|
47
|
+
os: [ubuntu-latest, macos-latest, windows-latest]
|
|
48
|
+
steps:
|
|
49
|
+
- uses: actions/checkout@v6
|
|
50
|
+
|
|
51
|
+
- uses: dtolnay/rust-toolchain@stable
|
|
52
|
+
|
|
53
|
+
- uses: Swatinem/rust-cache@v2
|
|
54
|
+
|
|
55
|
+
- name: cargo test
|
|
56
|
+
run: cargo test --all-features
|
inclean-0.1.0/.gitignore
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project are documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [Unreleased]
|
|
9
|
+
|
|
10
|
+
### Changed
|
|
11
|
+
|
|
12
|
+
- **Breaking:** `trailing_comment` schema redesigned to mirror include
|
|
13
|
+
action handling. The four `policy` values (`prepend` / `append` /
|
|
14
|
+
`replace` / `fill_if_absent`) and the `text` field are gone; the new
|
|
15
|
+
shape is `{ match, to, form, spacing }` where `match` is a regex
|
|
16
|
+
over the stripped existing comment body, `to` is the new comment
|
|
17
|
+
body template (with new `${comment.N}` / `${comment.text}`
|
|
18
|
+
placeholders), `form` switches between `"line"` / `"block"` /
|
|
19
|
+
`"preserve"`, and `spacing` controls the gutter before the
|
|
20
|
+
delimiter. `to = ""` removes the trailing comment entirely. See
|
|
21
|
+
`docs/configuration.md` for the migration table and the idempotent
|
|
22
|
+
prepend / append idioms in the Rust `regex` dialect.
|
|
23
|
+
|
|
24
|
+
## [0.1.0] — 2026-05-21
|
|
25
|
+
|
|
26
|
+
Initial release. Feature-complete for v1.
|
|
27
|
+
|
|
28
|
+
### Added
|
|
29
|
+
|
|
30
|
+
- Hierarchical `inclean.toml` configuration: one root config plus
|
|
31
|
+
optional sub-directory configs.
|
|
32
|
+
- Pure rule tree with single inheritance via `extends`; globally unique
|
|
33
|
+
rule names; AND-combined field merge at match time.
|
|
34
|
+
- Five-layer matching engine: `paths`, `extensions`, `forms`, `match`
|
|
35
|
+
(layer-4 regex on stripped include content), and `match_resolved`
|
|
36
|
+
(layer-5 constraint on the resolved physical file with ambiguity
|
|
37
|
+
detection against `original_include_dirs`).
|
|
38
|
+
- `@std.*` built-in constants for C/C++ extensions and standard
|
|
39
|
+
headers (C89–C23, C++98–C++23), with list-spread and `_or`
|
|
40
|
+
regex-alternation forms.
|
|
41
|
+
- Four action types: `auto` (resolve + relativize against
|
|
42
|
+
`allowed_include_dirs` or the source file's directory), `rewrite`,
|
|
43
|
+
`keep`, `error`. `${...}` placeholder substitution including
|
|
44
|
+
`${resolved.*}` for layer-5 matches.
|
|
45
|
+
- Rule-tree invariant enforcement at source-scan time:
|
|
46
|
+
`child ⊆ parent` and cross-chain disjointness, reported per-include.
|
|
47
|
+
- Post-action `allowed_include_dirs` validation; empty list is the
|
|
48
|
+
explicit opt-out for system-header rules.
|
|
49
|
+
- Five CLI subcommands: `init`, `check` (three-level via
|
|
50
|
+
`-l/--level config|rules|full`), `diff`, `apply`, `explain`.
|
|
51
|
+
- Per-file processing parallelized with `rayon`; deterministic output
|
|
52
|
+
via post-sort.
|
|
53
|
+
- Distinct exit codes: `0` clean, `2` user-defined `action.error`,
|
|
54
|
+
`3` for any of rule-tree conflict, layer-5 ambiguity, action
|
|
55
|
+
evaluation failure, or `allowed_include_dirs` validation failure.
|
|
56
|
+
|
|
57
|
+
[Unreleased]: https://example.com/compare/0.1.0...HEAD
|
|
58
|
+
[0.1.0]: https://example.com/releases/0.1.0
|
inclean-0.1.0/CLAUDE.md
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
# CLAUDE.md — Notes for Claude Code working in this repo
|
|
2
|
+
|
|
3
|
+
## What this project is
|
|
4
|
+
|
|
5
|
+
inclean is a Rust CLI that rewrites `#include` directives in C/C++ source
|
|
6
|
+
trees so the library can be consumed with a clean, minimal `-I` list. The
|
|
7
|
+
canonical use case: take an old library whose internal source uses
|
|
8
|
+
`#include "bar.h"` (resolving via `-Isrc/internal`) and rewrite every
|
|
9
|
+
such line so the consumer only needs `-Ipath/to/lib/include`.
|
|
10
|
+
|
|
11
|
+
For the module map and pipeline narrative, see
|
|
12
|
+
[docs/architecture.md](docs/architecture.md); for the full `inclean.toml`
|
|
13
|
+
schema (layers, actions, placeholders, `@std.*` constants), see
|
|
14
|
+
[docs/configuration.md](docs/configuration.md). This file keeps only
|
|
15
|
+
Claude-facing guidance.
|
|
16
|
+
|
|
17
|
+
## Design source of truth
|
|
18
|
+
|
|
19
|
+
The original design plan lives in
|
|
20
|
+
`/home/inaku/.claude/plans/c-c-inclean-iterative-tome.md` (local to the
|
|
21
|
+
maintainer's machine, not committed). Read it before making non-trivial
|
|
22
|
+
changes. Key design choices that drive the code shape:
|
|
23
|
+
|
|
24
|
+
- **Configuration**: TOML, hierarchical (`inclean.toml` at project root,
|
|
25
|
+
optional `inclean.toml` in any sub-directory). The root config **must**
|
|
26
|
+
declare `[project]` with `root` set; sub-configs **must not** declare
|
|
27
|
+
`[project]` at all.
|
|
28
|
+
- **Rule model**: pure rule tree with single inheritance via `extends`. Rule
|
|
29
|
+
`name` is globally unique across all configs in the project. There is
|
|
30
|
+
**no `[defaults]` block** — users write a `base` rule and others extend it.
|
|
31
|
+
- **`[project]` block is minimal**: only `root`. Everything else
|
|
32
|
+
(`allowed_include_dirs`, `original_include_dirs`) lives on rules.
|
|
33
|
+
- **Five-layer matching** (each layer has a default if unspecified):
|
|
34
|
+
1. `paths` — gitignore-style file globs
|
|
35
|
+
2. `extensions` — file extension filter (skipped if layer 1 is an exact path)
|
|
36
|
+
3. `forms` — set of `"quote"` / `"angle"` / `"macro"`; `"macro"` always errors in v1
|
|
37
|
+
4. `match` — regex on the stripped include content (no quotes/angles)
|
|
38
|
+
5. `match_resolved` — only runs when the rule sets it. Resolves the
|
|
39
|
+
include via `original_include_dirs` (must be unique — duplicate hits
|
|
40
|
+
surface as `Layer5Ambiguous` per-include, exit 3); then enforces
|
|
41
|
+
optional `under` (path-prefix) and `match` (path regex) constraints.
|
|
42
|
+
When layer 5 runs, the action gets `${resolved.path}` /
|
|
43
|
+
`${resolved.dir}` / `${resolved.basename}` placeholders.
|
|
44
|
+
- **Inheritance semantics**: runtime AND-combination merges fields; the
|
|
45
|
+
rule-tree invariants ("child's match set ⊆ parent's" + "cross-chain
|
|
46
|
+
disjoint") are enforced at source-scan time by
|
|
47
|
+
`tree::check_chain(match_all(...))`. There is no static lint module —
|
|
48
|
+
the source-level check supersedes it (also covers layer-4 regex).
|
|
49
|
+
- **Mode-dependent winner**: under `CheckMode::Full`, the action runs on
|
|
50
|
+
the deepest rule in the matched chain (the leaf), not the first-by-
|
|
51
|
+
declaration. This makes apply behavior independent of rule declaration
|
|
52
|
+
order.
|
|
53
|
+
- **Action default**: `{ type = "auto", relative_to = "allowed", form = "quote" }`.
|
|
54
|
+
- **`@std.*` built-in constants** (e.g. `@std.cpp.extensions`, `@std.cpp17.system_headers`)
|
|
55
|
+
spread in any string-list field via `@name` syntax.
|
|
56
|
+
|
|
57
|
+
## Module layout & pipeline data flow
|
|
58
|
+
|
|
59
|
+
Moved to [docs/architecture.md](docs/architecture.md). Read that doc
|
|
60
|
+
for the per-module responsibilities, the six-step pipeline walkthrough
|
|
61
|
+
inside `pipeline::run::run`, and the full list of `IncludeOutcome`
|
|
62
|
+
variants and exit-code semantics.
|
|
63
|
+
|
|
64
|
+
## Dev workflow
|
|
65
|
+
|
|
66
|
+
```sh
|
|
67
|
+
cargo check # fast type-check
|
|
68
|
+
cargo test # unit + integration tests
|
|
69
|
+
cargo clippy # lints
|
|
70
|
+
cargo fmt # format
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
Integration fixtures live under `tests/fixtures/` (small fake libraries).
|
|
74
|
+
Add a new fixture for any non-trivial behavior change.
|
|
75
|
+
|
|
76
|
+
## Conventions
|
|
77
|
+
|
|
78
|
+
- Use `anyhow::Result` for high-level error returns; `thiserror` for typed
|
|
79
|
+
errors at module boundaries.
|
|
80
|
+
- Rule-set / config errors should pinpoint the offending `inclean.toml`
|
|
81
|
+
path and rule name in the message.
|
|
82
|
+
- Keep `cli/*` files thin — they parse flags and call into `pipeline::run`.
|
|
83
|
+
- The `auto` action requires the resolved file to live under one of the
|
|
84
|
+
matched rule's `allowed_include_dirs`; failure is a hard error and aborts
|
|
85
|
+
the file's apply.
|
|
86
|
+
|
|
87
|
+
## Things to avoid
|
|
88
|
+
|
|
89
|
+
- Don't introduce a `[defaults]` block or any project-level fallback for
|
|
90
|
+
`allowed_include_dirs` / `original_include_dirs`. The deliberate design
|
|
91
|
+
is "rule tree with explicit `base`".
|
|
92
|
+
- Don't widen the rule subset invariant — child rules should never match
|
|
93
|
+
more than the parent.
|
|
94
|
+
- Don't attempt to formally check regex containment for layer 4. Runtime
|
|
95
|
+
AND-combination is the enforcement; static lint covers layers 1/2/3 only.
|
|
96
|
+
- Don't add file-moving, umbrella-header generation, or `extern "C"`
|
|
97
|
+
wrapping. Out of scope for v1.
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
# Contributing to inclean
|
|
2
|
+
|
|
3
|
+
Thanks for your interest in inclean. This is a small project — the
|
|
4
|
+
process is correspondingly light.
|
|
5
|
+
|
|
6
|
+
## Toolchain
|
|
7
|
+
|
|
8
|
+
- **Rust 1.91+** (2021 edition).
|
|
9
|
+
- **`rustfmt`** and **`clippy`** — install via
|
|
10
|
+
`rustup component add rustfmt clippy` if your toolchain doesn't
|
|
11
|
+
already have them.
|
|
12
|
+
|
|
13
|
+
No other system dependencies are required.
|
|
14
|
+
|
|
15
|
+
## Build and test
|
|
16
|
+
|
|
17
|
+
```sh
|
|
18
|
+
cargo build # debug build
|
|
19
|
+
cargo check # fast type-check
|
|
20
|
+
cargo test # unit + integration tests
|
|
21
|
+
cargo clippy --all-targets # lints
|
|
22
|
+
cargo fmt # format
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
All four of `cargo test`, `cargo clippy --all-targets`, and
|
|
26
|
+
`cargo fmt --check` should pass cleanly before a change is submitted.
|
|
27
|
+
|
|
28
|
+
## Repository layout
|
|
29
|
+
|
|
30
|
+
See [docs/architecture.md](docs/architecture.md) for the
|
|
31
|
+
module-by-module map. In short:
|
|
32
|
+
|
|
33
|
+
- `src/cli/*.rs` — clap subcommand handlers (thin).
|
|
34
|
+
- `src/pipeline/run.rs` — the orchestrator that every subcommand
|
|
35
|
+
calls into.
|
|
36
|
+
- `src/config/*`, `src/lex/*`, `src/rule/*`, `src/index/*`,
|
|
37
|
+
`src/validate/*` — the matching pipeline's building blocks.
|
|
38
|
+
- `tests/integration.rs` + `tests/fixtures/` — end-to-end tests.
|
|
39
|
+
|
|
40
|
+
## Adding a feature or fixing a bug
|
|
41
|
+
|
|
42
|
+
1. **Add (or extend) a fixture.** If the change alters observable
|
|
43
|
+
behavior, add a tiny `inclean.toml` + source-file fixture under
|
|
44
|
+
`tests/fixtures/<name>/`. Fixtures should be the smallest possible
|
|
45
|
+
reproduction of the scenario you're testing.
|
|
46
|
+
2. **Add an integration test** in `tests/integration.rs` that drives
|
|
47
|
+
the fixture and asserts on the outcome you care about (exit code,
|
|
48
|
+
conflicts, rewritten text).
|
|
49
|
+
3. **Run `cargo test` + `cargo clippy --all-targets` + `cargo fmt`**
|
|
50
|
+
clean.
|
|
51
|
+
4. **Open a PR** with a brief description of what changed and why.
|
|
52
|
+
Link the fixture/test that demonstrates the new behavior.
|
|
53
|
+
|
|
54
|
+
## Code conventions
|
|
55
|
+
|
|
56
|
+
- **Errors.** Use `anyhow::Result` for high-level errors and
|
|
57
|
+
`.with_context(…)` for I/O and parsing boundaries. `thiserror` is
|
|
58
|
+
reserved for future typed errors at internal module boundaries.
|
|
59
|
+
- **Error messages.** When a config or rule-set error references a
|
|
60
|
+
specific rule or `inclean.toml` file, the message must include the
|
|
61
|
+
rule name and the source path so the user can locate the problem.
|
|
62
|
+
- **CLI is thin.** `src/cli/*.rs` files parse flags and call
|
|
63
|
+
`pipeline::run`. Don't put pipeline logic in CLI handlers.
|
|
64
|
+
- **Comments.** Default to none. Add one when the _why_ is non-
|
|
65
|
+
obvious: a hidden constraint, a subtle invariant, a workaround. Do
|
|
66
|
+
not narrate what code already says.
|
|
67
|
+
- **No `unsafe`.** There is none today; keep it that way.
|
|
68
|
+
|
|
69
|
+
## Things outside v1 scope
|
|
70
|
+
|
|
71
|
+
These have been considered and explicitly excluded. Please discuss
|
|
72
|
+
in an issue before submitting a PR for any of them:
|
|
73
|
+
|
|
74
|
+
- A `[defaults]` block or any project-level fallback for
|
|
75
|
+
`allowed_include_dirs` / `original_include_dirs`. The deliberate
|
|
76
|
+
design is "rule tree with explicit `base`".
|
|
77
|
+
- Widening the child-subset invariant. Child rules must never match
|
|
78
|
+
more than their parent.
|
|
79
|
+
- Formally checking regex containment between layer-4 patterns.
|
|
80
|
+
Runtime AND-combination is the enforcement.
|
|
81
|
+
- File-moving, umbrella-header generation, `extern "C"` wrapping,
|
|
82
|
+
or any other source transformation beyond `#include` rewriting.
|
|
83
|
+
|
|
84
|
+
## Reporting bugs
|
|
85
|
+
|
|
86
|
+
Open an issue with the smallest possible reproduction:
|
|
87
|
+
|
|
88
|
+
- the offending `inclean.toml` (or its relevant rules),
|
|
89
|
+
- a one-or-two-file source snippet,
|
|
90
|
+
- what `inclean check` printed and what you expected.
|
|
91
|
+
|
|
92
|
+
If the bug is in `cargo test`, please also include the test name and
|
|
93
|
+
the output of `cargo test -- --nocapture <test_name>`.
|