# node:22-slim (22.x LTS), 2026-02-24 FROM node@sha256:5373f1906319b3a1f291da5d102f4ce5c77ccbe29eb637f072b6c7b70443fc36 AS base WORKDIR /app # Marks "already inside the lint container" for script/lint, which otherwise # shells out to docker to build the lint stage below. Nothing outside this # image sets it. ENV AUTISTMASK_LINT_NATIVE=1 # script/bootstrap installs all prerequisites (make via apt here; node # is already in the base image, yarn comes via corepack) and runs # yarn install --frozen-lockfile. Dependency manifests are copied first # so the bootstrap layer is cached until they change. COPY script/ script/ COPY package.json yarn.lock ./ RUN script/bootstrap COPY . . # Lint stage — fail fast on static analysis and formatting, before the tests # and the build. This is also the stage script/lint builds from a host, which # is how linting stays on the pinned ESLint rather than the host's. FROM base AS lint RUN make lint # Full check and build. The COPY --from is a no-op file copy whose only job is # to make BuildKit finish the lint stage before this one starts; without it the # stages run in parallel and a lint failure would not fail the build early. FROM base AS check COPY --from=lint /app/package.json /dev/null RUN make check RUN make build