The finale is the whole point of the project - compile a realistic .gitignore and get the exact ignore-or-keep verdict for every candidate path. Comments, an anchored rule, a directory rule, a broad ignore, and a negation all fire at once, and precedence decides the close calls.
Decide the exact ignore-or-keep verdict for a set of paths against a realistic gitignore.
This is the deliverable the whole project was built for: a real .gitignore,
compiled once, answering the exact question git answers - is this path ignored?
Every layer fires at once. The # build artifacts comment is dropped at compile
time. /dist is anchored, so it ignores dist at the base and everything inside it
by the ancestor rule, but not src/dist deeper in the tree. node_modules/ is a
directory rule that floats to any depth, ignoring node_modules and a/node_modules
as directories. *.log ignores every log by basename, and !keep.log carves the
exception back out - and because it is the last matching rule, keep.log and even
logs/keep.log are kept.
Nine paths, nine exact verdicts, and each one lands only because anchoring, directory typing, basename floating, ancestor exclusion, and last-match-wins precedence all agree. From a single-line literal comparison you have built a complete glob pattern language - wildcards, classes, escapes, path segments, the double-star - and the gitignore engine that git itself implements, minus a couple of corners the caveats name. That is a real glob and gitignore matcher, and it is yours.
g := Compile("# build artifacts\n/dist\nnode_modules/\n*.log\n!keep.log")g.Ignored("dist", true) // true - anchored, at baseg.Ignored("dist/bundle.js", false) // true - inside an ignored directoryg.Ignored("src/dist", true) // false - /dist is anchored to the baseg.Ignored("keep.log", false) // false - *.log then !keep.log re-includesg.Ignored("logs/keep.log", false) // false - the bang floats to any depth