CodeVetter · Repo Unpack · Behavior traces
postcss/postcss
The investigation followed initialization, plugin transformation, no-plugin processing, source-map loading/output, and JSON round-tripping through their implementation files. Plugin setup and parsing occur before deferred transformation, so LazyResult is only partly lazy. Sync and async traversal share event semantics but use separate execution loops. Branch conditions matter: no-plugin output, Document hooks, custom stringifiers, and inline maps have different behavior from the ordinary Root transformation path.
- Initialization: the ESM entry imports postcss.js → postcss.js loads classes/functions and calls LazyResult.registerPostcss → postcss(plugins) constructs Processor → Processor.normalize resolves creators, wrappers, plugin packs, objects, or legacy functions.
- Parse flow: postcss.parse(css, opts) → new Input → new Parser → createTokenizer → Parser.parse dispatches token kinds → other distinguishes rules/declarations → init attaches parent/source → endFile closes parsing or reports an unclosed block.
- Async transformation: Processor.process → LazyResult constructor parses and runs prepare(result) → then/async → runAsync → runOnRoot for each plugin, awaiting promises → prepareVisitors → visitTick passes until clean → OnceExit → stringify.
- Sync transformation: reading css → stringify → sync → runOnRoot → prepareVisitors → walkSync until clean → OnceExit → CSS generation; promise-returning root hooks or visitors trigger getAsyncError.
- Insertion during traversal: a visitor calls rule.after(child) → Container.insertAfter normalizes/reparents the child and adjusts live iterator slots → visitTick/walkSync advance only after the current subtree finishes; regression tests specify inserted siblings appearing before exit events.
- No-plugin flow: Processor.process selects NoWorkResult → constructor keeps the CSS string and generates or clears map annotations → async/sync returns Result → accessing root invokes parse once and caches either the AST or its error.
- Source-map flow: Input → PreviousMap.loadAnnotation → loadMap chooses explicit prev, inline data, or an annotation file → guarded loadFile/consumer → MapGenerator.generateString → setSourcesContent/applyPrevMaps/addAnnotation → inline CSS or external map returned to the caller.
- JSON round-trip: root.toJSON builds node objects and an input table → caller serializes/transports them → fromJSON hydrates Inputs and constructs descendants before parents → root.toResult creates an empty Processor/LazyResult and serializes; tests cover both V8 transport and JSON formatting preservation.