Bounded source formatting
Experimental: flog format formats complete JavaScript and TypeScript
files that Stick can parse and print safely. Syntax coverage and layout rules
may change; unsupported or unsafe files are refused without edits. Command
status is tracked in experimental-commands.json at the repository root.
File, directory, and workspace selection#
Pass one or more explicit files or directories, or select exactly one declared workspace:
flog format src/config.js scripts/check.ts
flog format src packages/shared
flog format --check --workspace @example/shared
Explicit files must be regular files no larger than 8 MiB; shell-expanded paths remain explicit files. Directories are scanned recursively in lexical order within the project root. Symlinks are not followed: an unexcluded symlink, overlapping or hard-linked input, traversal error, empty selection, or path outside the root causes a refusal.
--workspace uses Flog's name, path, owned-file, or glob selectors but must
resolve to exactly one declared workspace. It cannot be repeated or combined
with path arguments; only the selected package directory is scanned.
Recursive selection always excludes dependency, VCS, vendored, generated, and
common build-output directory names: .git, .hg, .svn, .rp,
node_modules, vendor, generated, dist, build, coverage, out,
target, .next, .nuxt, and .svelte-kit. Explicit file arguments are not
affected by recursive exclusions.
The filename selects JavaScript or TypeScript syntax:
.js,.mjs, and.jsxselect JavaScript ESM;.ts,.mts,.tsx,.d.ts, and.d.mtsselect TypeScript ESM;.cjs,.cts, and.d.ctsare explicitly CommonJS-only and are refused.
These extensions select ESM grammar, not JSX support. Ordinary .js needs no
package.json; a nearest manifest declaring "type": "commonjs" refuses
ambiguous extensions (.js, .jsx, .ts, .tsx, .d.ts) but not explicit ESM
extensions. An unreadable or invalid nearest manifest also causes refusal.
Contextual top-level await requires independent ESM proof, such as a static
import/export or import.meta, to avoid reinterpreting script syntax.
Canonical style#
There are no style options. Flog uses two-space indentation, semicolons for supported statements, safe double-quoted strings, spaces around supported operators and delimiters, LF structural lines, and one final newline. Literal, regular-expression, template raw-chunk, and comment bytes are preserved where changing them could alter meaning. Safe string-quote conversion is limited to equivalent spelling; other escapes are retained.
Where the printer owns width, comment-free lists and other layouts target 80 columns using syntax-safe breaks and trailing commas on multiline lists. Short forms stay compact when the complete rendered line fits; source line breaks alone do not choose a different layout. Flog does not reflow arbitrary expressions, strings, or comments to meet the target. It preserves ownership-sensitive section breaks and separates top-level module declarations from ordinary statements. If a safe canonical layout cannot be proven, it refuses the file instead of partly formatting it.
Supported syntax and current limits#
Stick formats complete ESM JavaScript or TypeScript files only when every
construct fits its bounded grammar. That grammar covers selected ESM module,
declaration, statement, expression, literal, comment, JSDoc, and TypeScript type
forms, but coverage is intentionally incomplete within each category. Stick
preserves literal spelling, comment ownership, and syntax semantics when
printing. The reliable way to test a file against the current grammar is to run
flog format --check.
Notable current limits include JSX syntax (even in .jsx or .tsx files),
CommonJS, dynamic import expressions, many class bodies and advanced TypeScript
declarations, and other lexical or grammar forms outside Stick's bounded
coverage. These examples are not exhaustive: unsupported or ambiguous syntax
and unsafe comment or module ownership are refused without edits. flog format
is not a general JS/TS formatter or a Prettier-compatible printer. ESLint
Stylistic guides style where the bounded printer owns a choice; it does not
extend the supported grammar. Existing formatters should remain in place for
files Flog cannot safely handle.
Project configuration#
No configuration is required. Flog discovers one optional committed flog.json
at the project, workspace, or standalone package root, not a nested file below
that root. Without package metadata, the nearest ancestor flog.json defines
the standalone project root.
Canonical style has no options. The optional format.exclude array adds
project-root-relative slash-separated path globs to recursive selection:
{
"format": {
"exclude": ["fixtures/**", "packages/legacy/*.js"]
}
}
** matches zero or more path segments. A pattern that matches a directory
prunes that tree; otherwise matching files are omitted. Patterns must be
non-empty, unique, remain within the project root, and use forward slashes.
The file must be regular JSON no larger than 1 MiB, with one object, unique
keys, and no unknown fields. Reserved lint and check sections are rejected.
Safety and refusals#
A file is eligible only when Stick reports no lexical, malformed, unsupported, or context diagnostic. The complete output must reparse in the same language and ESM context and print idempotently. Comments and syntax ownership are verified by Stick's reference printer.
All requested files are planned before any write. If one is refused, none are modified. Before replacement, Flog verifies that each file is still the same regular file with identical contents and permissions. Changed files are staged beside their targets and replaced transactionally; an ordinary multi-file replacement failure rolls back earlier replacements. Original permission bits are preserved. Rollback restores a target only while it still has the exact identity, permissions, and bytes staged by this formatter. If another process edits an already formatted target, Flog preserves those current bytes, reports the conflict, and retains the original backup path for manual recovery.
Successful formatting prints one line per selected file. Explicit files retain argument order; recursive results use deterministic lexical traversal order:
formatted src/config.js
unchanged scripts/check.ts
Check mode and exit status#
--check performs complete discovery and parse/print verification but never
stages or modifies files. It prints every safely planned file whose bytes differ:
src/config.js: needs formatting
When drift is the only finding, standard error also receives the usual concise
Flog diagnostic (flog: error: 1 file needs formatting, or the plural count).
Every refusal discovered while scanning or planning is reported as well.
Refusal, incomplete-discovery, and operational failures take exit precedence
over formatting drift, while the drift lines remain available on standard
output.
Exit statuses are:
| Status | Meaning |
|---|---|
| 0 | every file is already formatted, or formatting succeeded |
| 1 | a file was refused or an operational error occurred |
| 2 | command usage was invalid |
| 3 | --check found one or more files needing formatting |
Diagnostics identify the refused path and, for Stick diagnostics, the first one-based line and UTF-16 column. Refusal and check modes never emit partial formatted source.