Skip to content

Adopt declscope, and align the file boundaries with the units - #24

Merged
mpyw merged 11 commits into
mainfrom
feat/declscope
Sep 15, 2026
Merged

mpyw merged 11 commits into
mainfrom
feat/declscope

Conversation

@mpyw

@mpyw mpyw commented Sep 15, 2026

Copy link
Copy Markdown
Owner

declscope holds each declaration to the file that declares it, which is the private Go has no word for.

rules:
  naming:
    qualify: ondemand
    exported: true

No baseline

The first pass recorded 170 violations, 43 boundary and 127 naming. All of them are gone, and no baseline file is in this PR.

Where the boundary entries were

Package What was crossing What it turned out to be
internal/server baseHandler reached from three files One type split by concern. The three share a handler namespace now
internal/js Transformer's compile and apply halves One type again, joined in the core
internal/mock Nine source-format entry points A dispatcher with nine implementations, each entry declared with //declscope:package
e2e Five helpers used by every test Shared on purpose, declared at file level

closeQuietly was used from two namespaces and is now internal.CloseQuietly, since it belongs to neither.

Files renamed to match what they hold

statements.go became query.go, exec.go and bind.go. transform.go became compile.go, and Transforms became CompiledTransforms, which the doc comment already said. errors.go became error.go, because most of its declarations carry the singular.

Splitting statements.go cleared its entries without renaming a single declaration. The file name was the thing that was wrong.

Core, and what is left checked

One file per package, except internal/config where config.go and types.go are both the API and error.go remains a unit of its own with 16 declarations. No package is entirely core.

internal/cli/commands is the one place where core was the only option: Version is named by goreleaser's ldflags and cannot be renamed, and commands.App is the public entry.

Two vocabulary entries

handler: [handle] and responder: [response]. Both are word-form pairs the matcher cannot derive, which is declscope#64.

ファイル単位のスコープを静的に検査する。設定は declscope 自身が自分に
課しているものと同じで、qualify は ondemand、exported は true。

既存の違反 170 件は baseline に記録した。新しい違反だけが報告される。
baseline は編集せず再生成するもので、直した分は再生成時に消える。

版は 0.2.0 に固定する。
@codecov

codecov Bot commented Sep 15, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 90.00000% with 8 lines in your changes missing coverage. Please review.
✅ Project coverage is 82.90%. Comparing base (4b5ebf5) to head (e3402f8).

Files with missing lines Patch % Lines
internal/db/exec.go 70.00% 3 Missing ⚠️
internal/config/error.go 93.75% 1 Missing ⚠️
internal/db/bind.go 75.00% 1 Missing ⚠️
internal/helpers.go 50.00% 1 Missing ⚠️
internal/js/timeout.go 95.23% 1 Missing ⚠️
internal/server/handler.go 66.66% 1 Missing ⚠️
Additional details and impacted files

Impacted file tree graph

@@           Coverage Diff           @@
##             main      #24   +/-   ##
=======================================
  Coverage   82.90%   82.90%           
=======================================
  Files          35       38    +3     
  Lines        1685     1685           
=======================================
  Hits         1397     1397           
  Misses        288      288           
Files with missing lines Coverage Δ
internal/cli/commands/app.go 0.00% <ø> (ø)
internal/config/config.go 86.66% <ø> (ø)
internal/config/types.go 90.19% <100.00%> (+0.19%) ⬆️
internal/db/db.go 75.00% <ø> (ø)
internal/db/query.go 75.00% <ø> (ø)
internal/executor/compile.go 100.00% <100.00%> (ø)
internal/executor/executor.go 81.35% <ø> (ø)
internal/js/apply.go 90.36% <ø> (ø)
internal/js/error.go 88.46% <100.00%> (ø)
internal/js/helpers.go 90.90% <ø> (ø)
... and 21 more
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

mpyw and others added 10 commits September 15, 2026 15:09
e2e の boundary 違反 5 件(setupTestDB / loadConfig / createHandler /
createMutationHandler / decodeJSON)はすべて common_test.go 発で、全テスト
ファイルから使われる意図的な共有部品。ファイル全体が共有ヘルパ置き場なので、
宣言ごとではなくファイルレベルの //declscope:package 1 つで宣言した。

e2e はテスト専用名前空間しか持たないため qualify は発動せず、これで
declscope ./e2e/ は 0 件(naming の追加違反が出ないことも実測済み)。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012T28FtGHj8psiBJE1btZHR
パッケージ内の宣言はすべて app.go にあり(drivers_*.go はビルドタグ用の
import シム)、commands.App / commands.MakeApp / commands.Version として
パッケージ名で読まれる公開 API。接頭辞を付けると commands.AppVersion の
ように吃るうえ、Version は goreleaser の ldflags
(-X ...commands.Version) が名前で参照するため改名できない。よって
qualify 6 件は改名ではなく core 指定で解消した。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012T28FtGHj8psiBJE1btZHR
db.go(Connect と接続ライフサイクル)はパッケージ名そのものの単位なので
core にした。statements.go の qualify 5 件は db.QueryOne / db.Exec のように
パッケージ名で読まれる API で、"statements" を名前に含めると
db.StatementsQueryOne と吃る。名前空間はファイル名から来るため、宣言は
一切改名せずファイルを凝集単位で分割した:

- query.go: QueryOne / QueryMany("query" を自然に含む)
- exec.go:  Exec / ExecResult
- bind.go:  BindParams("bind" を自然に含む)

分割後 declscope ./internal/db/ は 0 件、go test も通過を実測。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012T28FtGHj8psiBJE1btZHR
config.go(Config と Parse)と types.go(config.Query 等の公開語彙)は
どちらもパッケージ名で読まれる API で、接頭辞は config.TypesQuery のように
吃るため core にした。errors.go は Parse の検証エラーを整形する私的な
下請けなので core に入れず、次のように直した:

- errors.go → error.go に改名。単数形なら findMockSourceError /
  errorWithPath / collectErrors など大半の宣言が語頭一致(右端自由)で
  名前空間を運ぶ。
- 運ばない宣言は自然な語順で改名: formatPath → formatErrorPath、
  getParentPath → parentErrorPath、isMockPath → isMockErrorPath、
  findTypeValue → findTypeValueInErrors、isNumeric → isErrorPathIndex
  (数値判定の実態は「エラーパス中の配列インデックスか」)など。
- objectSources / arraySources は Mock の排他ソースフィールドを鏡写しに
  した YAML キー表なので types.go の Mock 隣へ移し、キー表と分かる名前
  (objectSourceKeys / isObjectSourceKey 等) にした。error.go からの利用は
  判定関数 2 つの //declscope:package で共有を明示。
- config.go からの唯一の入口 formatValidationError も
  //declscope:package で明示。

core 率は 2/3 ファイル。declscope ./internal/config/ 0 件・テスト通過を実測
(キー表側の directive は surplus 報告が出たため判定関数側だけに絞った)。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012T28FtGHj8psiBJE1btZHR
qualify 18 件 + boundary 4 件の大半は「Transformer 1 型を transformer.go
(コンパイル側)と apply.go(実行側)が分担している」ことに由来する。
両者はパッケージ名の由来である単位そのものなので、両ファイルを core に
した。これで CompilePre / PreTransformResult 等の公開 API は無接頭辞の
まま、Transformer.program / helpers フィールドの越境も同一名前空間に
収まって消える。

周辺は衛星単位として残した:

- timeout.go を新設し JSTimeout / ErrJSTimeout / runWithTimeout を移動。
  3 宣言とも "timeout" を自然に含み、watchdog の runWithTimeout は
  pool と apply の双方から使うため //declscope:package で共有を明示。
- error.go: apply からの入口 parseJSError を //declscope:package で明示、
  toHTTPStatus → errorToHTTPStatus に改名。
- global_helpers.go → helpers.go に改名。CompiledHelpers / CompileHelpers
  が "helpers" を自然に含むため、宣言の改名は不要。

core 率 2/9 ファイル。declscope ./internal/js/ 0 件・テスト通過を実測
(テストファイルが対象ファイルの core 指定に追随することも確認)。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012T28FtGHj8psiBJE1btZHR
mock.Compile は csv / json / js / filter の各ソース形式ファイルへ振り分ける
ディスパッチャで、パッケージ名の単位そのもの。mock.go を core にして
Source / Compile / CompileOptions の qualify を解消し(mock.MockCompile と
吃らせない)、Compile が呼ぶ各形式の入口だけを //declscope:package で
明示した: parseCSVOptions / parseCSV(File)WithOptions / compileJS /
newJSON / parseJSONString / parseJSONFile / parseJSONL(File) /
newJSFilteredSource。

個別の名前も直した:

- csv_value.go: parseValue → parseCSVValue(csv.go から使う既定のセル
  パーサなので共有も明示)、isNumeric → isNumericCSVValue、
  parseBool → boolFromCSVValue。いずれも "csvValue" を自然な語順で含む。
- json.go: deepCopy → deepCopyJSON。
- closeQuietly は csv と json の 2 名前空間から使う汎用ユーティリティ
  なので internal.CloseQuietly として internal パッケージへ昇格した。
- パッケージ doc コメントを csv_value.go から mock.go へ移動。

core 率 1/7 ファイル。declscope 0 件・テスト通過を実測。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012T28FtGHj8psiBJE1btZHR
executor.go は BaseExecutor を軸にした実行パイプラインでパッケージ名の
単位そのもの。executor.Options / executor.ErrNotFound として読まれる API
なので core にして qualify 12 件を解消した。query.go / mutation.go は
既に名前空間を運んでいて無傷。

transform.go は CompileTransforms / CompileMock / CompileTransformOptions
というコンパイル入口の集まりなので compile.go に改名し、唯一運ばない
Transforms 型を CompiledTransforms に改名した(doc も
"holds pre-compiled transforms" でありむしろ正確になる)。

core 率 1/4 ファイル。declscope 0 件・テスト通過を実測。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012T28FtGHj8psiBJE1btZHR
parser.go は Content-Type を見て form.go / json.go へ振り分ける、
パッケージ名(body parsing)の単位そのもの。core にして body.MaxBodySize /
body.Err* / readBody の qualify を解消した。

層をまたぐ入口は //declscope:package で明示:

- readBody: 全形式パーサが通るサイズ・charset 検査済みリーダ
- parseJSON / parseJSONBytes: Parse からのディスパッチ先
- form.go 側は改名も兼ねる: parseURLEncoded → parseFormURLEncoded、
  parseMultipart → parseMultipartForm("form" を自然な語順で含む)

parser_test.go の errorReader は core に追随して免除。core 率 1/3。
declscope 0 件・テスト通過を実測。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012T28FtGHj8psiBJE1btZHR
boundary 22 件の主因は baseHandler 1 型の分担だった: handler.go が汎用
機構を持ち、mutation_handler.go / query_handler.go がそのフィールドを
丸ごと埋めて特殊化する。3 ファイルを //declscope:namespace handler で
1 単位に統合し、フィールド越境をすべて解消した。

- server.go は NewServeMux を持つ組み立て役で core。そこから handler 単位
  への入口 4 つ(handlerOptions / createNotFoundHandler /
  newQueryHandlerWithOptions / newMutationHandlerWithOptions)だけを
  //declscope:package で明示。
- responder.go は独立単位のまま、handler 側から使う responder 型(と w
  フィールド)を型への //declscope:package 1 つで共有宣言。
- naming は自然な語順を優先して改名:
  Executor → HandlerExecutor、ResultProcessor → HandlerResultProcessor、
  mutationResultProcessor → mutationHandlerProcessor、
  queryResultProcessor → queryHandlerProcessor、
  extractPathParams → handlerPathParams、
  queryRecord(er) → handledQueryRecord(er)、
  marshalOptions → responseMarshalOptions、
  validateStatus → validateResponseStatus。
- defaultStatusForPhase / extractNamedParams は baseHandler の判断・処理
  そのものなのでメソッド化(レシーバで所属が読めるため naming の対象外)。
- handler/handle(d)、responder/response は語形変化をマッチャが導出できない
  ため .declscope.yaml の vocabulary に登録した。

core 率 1/5 ファイル。declscope 0 件・テスト通過を実測。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012T28FtGHj8psiBJE1btZHR
170 件(boundary 43 / qualify 127)あった違反を構造の修正で 0 件にした
ため、baseline は不要になった。最終確認として次を実測:

- go build ./... && go test ./... 全通過
- gofmt -l .(go1.27 toolchain の gofmt)が空
- baseline 無しで declscope ./... が exit 0

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012T28FtGHj8psiBJE1btZHR
@mpyw mpyw changed the title Adopt declscope Adopt declscope, and align the file boundaries with the units Sep 15, 2026
@mpyw
mpyw merged commit 96dec0d into main Sep 15, 2026
8 checks passed
@mpyw
mpyw deleted the feat/declscope branch September 15, 2026 06:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant