Skip to content

fix(docker-parser): parse flag values and keep comments through a deparse - #103

Merged
pyramation merged 1 commit into
mainfrom
feat/docker-parser-mounts-comments
Aug 3, 2026
Merged

fix(docker-parser): parse flag values and keep comments through a deparse#103
pyramation merged 1 commit into
mainfrom
feat/docker-parser-mounts-comments

Conversation

@pyramation

Copy link
Copy Markdown
Contributor

Summary

Two bugs that a Dockerfile generator runs straight into. Found while replacing constructive-db's string-template Dockerfiles with docker-parser — the templates use --mount=type=cache and are heavily commented, and both were destroyed by a round-trip.

1. A flag lost its value. readWord() stops at =, so the FLAG token was just --mount and the rest stayed in the stream, where parseRun read it as the beginning of the command:

  RUN --mount=type=cache,id=pnpm-store,target=/store pnpm install
- → { command: '=type=cache,id=pnpm-store,target=/store pnpm install', mount: [{ type: 'bind' }] }
- → deparse: RUN --mount=type=bind =type=cache,id=pnpm-store,target=/store pnpm install
+ → { command: 'pnpm install', mount: [{ type: 'cache', id: 'pnpm-store', target: '/store' }] }

parseMountFlag was already correct — it never received the value. Fixed with a readFlag() that reads through = to whitespace, so --mount, --from, --platform, --network and --security all keep theirs. (Only --mount was corrupted in output; the others survived because their =value re-lexed into the same string.)

2. Every comment vanished. Comments parsed into a flat Dockerfile.comments array that deparseDockerfile never emitted. They now attach to the node they lead:

BaseNode.leadingComments?: Comment[]   // comment lines immediately above this node
BaseNode.blankBefore?: boolean         // one blank line above it (and above its comments)
Dockerfile.trailingComments?           // comments below the last instruction

Dockerfile.comments still holds every comment, so existing consumers are unaffected. A comment takes the blank line above itself, which keeps # header / blank / COPY distinct from # header / COPY — and consecutive comments stay siblings of one block rather than a chain where each leads the next. The deparser no longer inserts a blank line the AST didn't ask for (it used to add one after the directives), since an invented blank comes back as blankBefore on the next parse and breaks the round-trip.

Together this makes parse → deparse lossless over constructive-db's four Dockerfiles apart from cosmetics: mount options come back in canonical order, and a RUN continued with \ deparses onto one line (noted in the README; not addressed here).

The point of (2) beyond fidelity: a generated Dockerfile can now carry the reasoning for its layers, which is what a hand-written template gave us for free and the main thing lost by generating one.

Tests

96 (was 78). New: 5 round-trips for RUN mount/network/security flags, 6 for comment placement, and exact-output assertions in deparser.test.ts — including one building leadingComments/blankBefore by hand with no parse, which is the generator's path.

Link to Devin session: https://app.devin.ai/sessions/f1a21b66c33d45d099297808a227cd3e
Requested by: @pyramation

…arse

A flag's token stopped at the first '=' , so RUN --mount=type=cache,id=...
lexed as '--mount' and left '=type=cache,...' to be read as the start of the
command: the mount lost its id and target, defaulted to type=bind, and
deparsed as a corrupt 'RUN --mount=type=bind =type=cache,... '.

Comments parsed into a flat Dockerfile.comments array that the deparser never
emitted, so every comment vanished on a round-trip. They now attach to the node
below them as leadingComments, with a blank line above a node as blankBefore,
and the deparser emits both — which is also what lets a generated Dockerfile
carry the reasoning for its layers.
@pyramation pyramation self-assigned this Aug 3, 2026
@devin-ai-integration

Copy link
Copy Markdown

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR. Add '(aside)' to your comment to have me ignore it.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment, CI, and merge conflict monitoring

@pyramation
pyramation merged commit 33a7e5d into main Aug 3, 2026
55 checks passed
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