MonacoPrettierFormatterService (libraries/tools/src/services/prettier/monaco-prettier-formatter.service.ts) is ~200 lines covering Prettier 3 module interop, lazy loading, the per-language idempotent register(), and the dual error-channel between provider hot path and the panel-safe path. There is no spec file for it.
Concrete fragility surfaces that would silently break on a Prettier upgrade with no test signal:
Lazy-load interop (loadModules()): reads standaloneAny.format ?? standaloneAny.default?.format. One of those paths is always dead; if a Prettier 4 narrows the export shape, the dead path is the only surviving one and we get format === undefined at runtime.
Plugins-array shape: passes the full module imports as plugins. Prettier 3 detects parser metadata on each item; Prettier 4 may narrow that to .default only.
register() idempotency (just added in JRS-1): a registeredLanguages Set guard prevents double-registration when two shells share the root-provided service. No test asserts this.
Error channel separation: computeFormattingEdits (provider hot path) collapses to [] on parse error; computeFormattingEditsSafe (panel path) returns { error }. Easy to accidentally invert.
Suggested test plan
A new monaco-prettier-formatter.service.spec.ts with at minimum:
lazy load smoke: after one formatModelInPlace call, the resolved Prettier format is callable and produces a string.
register idempotency: two register(monaco, ["javascript"]) calls register exactly one provider; first disposer’s dispose releases the slot so a subsequent register works again.
error channel: invalid JS source returns { ok: false, error: '...' } from the panel-safe path AND [] from the Monaco provider path (so Monaco doesn’t complain about an unexpected shape).
format-no-op short-circuit: when input already matches Prettier output, formatModelInPlace returns { ok: true } without calling pushEditOperations/executeEdits.
cursor preservation: with an editor arg, the post-format cursor stays within ±1 line of where it started (covers MPF-3 fix).
Mock Monaco surface: monaco.languages.registerDocumentFormattingEditProvider, monaco.editor.createModel, editor.executeEdits. The existing monaco-editor.component.spec.ts (if any) can be a pattern reference for lazy-Monaco mocking.
Related
Found during code review of the Prettier integration + JS formatting options panel feature wave.
## Problem
`MonacoPrettierFormatterService` (`libraries/tools/src/services/prettier/monaco-prettier-formatter.service.ts`) is ~200 lines covering Prettier 3 module interop, lazy loading, the per-language idempotent `register()`, and the dual error-channel between provider hot path and the panel-safe path. There is no spec file for it.
Concrete fragility surfaces that would silently break on a Prettier upgrade with no test signal:
1. **Lazy-load interop** (`loadModules()`): reads `standaloneAny.format ?? standaloneAny.default?.format`. One of those paths is always dead; if a Prettier 4 narrows the export shape, the dead path is the only surviving one and we get `format === undefined` at runtime.
2. **Plugins-array shape**: passes the full module imports as plugins. Prettier 3 detects parser metadata on each item; Prettier 4 may narrow that to `.default` only.
3. **`register()` idempotency** (just added in JRS-1): a `registeredLanguages` Set guard prevents double-registration when two shells share the root-provided service. No test asserts this.
4. **Error channel separation**: `computeFormattingEdits` (provider hot path) collapses to `[]` on parse error; `computeFormattingEditsSafe` (panel path) returns `{ error }`. Easy to accidentally invert.
## Suggested test plan
A new `monaco-prettier-formatter.service.spec.ts` with at minimum:
- **lazy load smoke**: after one `formatModelInPlace` call, the resolved Prettier `format` is callable and produces a string.
- **register idempotency**: two `register(monaco, ["javascript"])` calls register exactly one provider; first disposer’s `dispose` releases the slot so a subsequent register works again.
- **error channel**: invalid JS source returns `{ ok: false, error: '...' }` from the panel-safe path AND `[]` from the Monaco provider path (so Monaco doesn’t complain about an unexpected shape).
- **format-no-op short-circuit**: when input already matches Prettier output, `formatModelInPlace` returns `{ ok: true }` without calling `pushEditOperations`/`executeEdits`.
- **cursor preservation**: with an `editor` arg, the post-format cursor stays within ±1 line of where it started (covers MPF-3 fix).
## Owner pointers
- `libraries/tools/src/services/prettier/monaco-prettier-formatter.service.ts`
- Mock Monaco surface: `monaco.languages.registerDocumentFormattingEditProvider`, `monaco.editor.createModel`, `editor.executeEdits`. The existing `monaco-editor.component.spec.ts` (if any) can be a pattern reference for lazy-Monaco mocking.
## Related
Found during code review of the Prettier integration + JS formatting options panel feature wave.
Added monaco-prettier-formatter.service.spec.ts in spikersoft-angular PR #57 — 11 tests covering all four seams from the suggested test plan: lazy-load interop (against REAL Prettier, to catch an export-shape change), register() per-language idempotency + slot release on dispose + throw-safe disposal, the dual error channel (panel-safe { error } vs provider-path []), and the no-op short-circuit + editor-aware/model-direct/no-editor edit application. Deterministic tests inject a fake modulesPromise; only the interop smoke test loads real Prettier. nx test feature-dev-tools-javascript-runner → 40 pass. Will close once PR #57 merges.
Added `monaco-prettier-formatter.service.spec.ts` in `spikersoft-angular` PR #57 — 11 tests covering all four seams from the suggested test plan: lazy-load interop (against REAL Prettier, to catch an export-shape change), `register()` per-language idempotency + slot release on dispose + throw-safe disposal, the dual error channel (panel-safe `{ error }` vs provider-path `[]`), and the no-op short-circuit + editor-aware/model-direct/no-editor edit application. Deterministic tests inject a fake `modulesPromise`; only the interop smoke test loads real Prettier. `nx test feature-dev-tools-javascript-runner` → 40 pass. Will close once PR #57 merges.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Problem
MonacoPrettierFormatterService(libraries/tools/src/services/prettier/monaco-prettier-formatter.service.ts) is ~200 lines covering Prettier 3 module interop, lazy loading, the per-language idempotentregister(), and the dual error-channel between provider hot path and the panel-safe path. There is no spec file for it.Concrete fragility surfaces that would silently break on a Prettier upgrade with no test signal:
loadModules()): readsstandaloneAny.format ?? standaloneAny.default?.format. One of those paths is always dead; if a Prettier 4 narrows the export shape, the dead path is the only surviving one and we getformat === undefinedat runtime..defaultonly.register()idempotency (just added in JRS-1): aregisteredLanguagesSet guard prevents double-registration when two shells share the root-provided service. No test asserts this.computeFormattingEdits(provider hot path) collapses to[]on parse error;computeFormattingEditsSafe(panel path) returns{ error }. Easy to accidentally invert.Suggested test plan
A new
monaco-prettier-formatter.service.spec.tswith at minimum:formatModelInPlacecall, the resolved Prettierformatis callable and produces a string.register(monaco, ["javascript"])calls register exactly one provider; first disposer’sdisposereleases the slot so a subsequent register works again.{ ok: false, error: '...' }from the panel-safe path AND[]from the Monaco provider path (so Monaco doesn’t complain about an unexpected shape).formatModelInPlacereturns{ ok: true }without callingpushEditOperations/executeEdits.editorarg, the post-format cursor stays within ±1 line of where it started (covers MPF-3 fix).Owner pointers
libraries/tools/src/services/prettier/monaco-prettier-formatter.service.tsmonaco.languages.registerDocumentFormattingEditProvider,monaco.editor.createModel,editor.executeEdits. The existingmonaco-editor.component.spec.ts(if any) can be a pattern reference for lazy-Monaco mocking.Related
Found during code review of the Prettier integration + JS formatting options panel feature wave.
Added
monaco-prettier-formatter.service.spec.tsinspikersoft-angularPR #57 — 11 tests covering all four seams from the suggested test plan: lazy-load interop (against REAL Prettier, to catch an export-shape change),register()per-language idempotency + slot release on dispose + throw-safe disposal, the dual error channel (panel-safe{ error }vs provider-path[]), and the no-op short-circuit + editor-aware/model-direct/no-editor edit application. Deterministic tests inject a fakemodulesPromise; only the interop smoke test loads real Prettier.nx test feature-dev-tools-javascript-runner→ 40 pass. Will close once PR #57 merges.