Skip to content

No way to add a prettier plugin, so any fence language beyond yaml is left unformatted #660

Description

@Jamie-BitFlight

Problem

The set of languages this tool will format inside a README's fenced code blocks is a hardcoded array in src/prettier.ts:

export const plugins: Plugin[] = [markdown, yaml];

It is not exported for configuration, not reachable from action.yml, and not reachable from .ghadocs.json. A project whose README contains a fence in any other language has no way to have it formatted, and no way to find out that it will not be.

That default is deliberate — a survey of 18 published action READMEs found yaml/yml in 17, one javascript fence, and nothing else prettier formats, so bundling the rest cost 3.6 MB of binary to reformat code nobody had written. But "we picked a good default" and "you cannot change the default" are separate things, and only the first is currently true.

The author of that one javascript-fence README has no route forward.

Observed

  • plugins is a module-level array in src/prettier.ts, referenced by formatMarkdown and wrapDescription. No configuration path reads it.
  • A ts or json fence run through the built binary comes back byte-for-byte as written. Nothing is logged about the fence being skipped.

Resolution mechanics that have been checked

Local plugins resolve. Verified against a scratch project with prettier installed:

createRequire(`${process.cwd()}/`) -> require.resolve('prettier/plugins/typescript')
  -> import(pathToFileURL(resolved))

resolved to the user's node_modules/prettier/plugins/typescript.js and imported cleanly. A bare import(spec) from the binary resolves relative to the binary's own location instead, so the createRequire-from-cwd step is the part that matters.

URL plugins do not resolve via import(). import('https://…') returned ERR_UNSUPPORTED_ESM_URL_SCHEME on the Node 22 the check ran under. Node 24 is untested. Supporting a URL therefore means fetch → write to a temp file → import from disk, which is fetching and executing remote code inside a CI job. The decision on this issue is that URL support is wanted, opt-in and documented as such — it should not be reachable by accident, and the documentation needs to say plainly what it does.

Scope

  • A configuration key accepting module specifiers, file paths, and (opt-in) URLs.
  • Resolution from the consuming project rather than from the binary's location.
  • A failure mode a user can act on: naming a plugin that cannot be resolved should say so, rather than silently formatting less.
  • README section documenting how to add a language, and what the URL option actually does.

Out of scope

Changing the bundled default. That set is pinned by a test asserting the exact parser list, so growing it stays a deliberate decision.

Related

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions