@systemfsoftware/stryker-framework-interface
v0.0.0
Published
The framework interface for StrykerJS-style mutation tooling — the plain framework object a plugin exports, its format claim, the embedded document and script regions it produces, and the toolkit context its hooks receive. Types only, with no runtime expo
Maintainers
Readme
@systemfsoftware/stryker-framework-interface
The framework interface: the plain object a plugin exports to teach the instrumenter a file format, and everything that object declares, produces, and receives — as types only. The package ships no runtime code.
A framework plugin claims one format and owns everything about it: which
extensions select it, how the file parses into script regions, how those regions
print back into the raw document, and which report language the file carries.
The plugin module exports strykerFrameworks, an array of plain objects the host
loads in-process and calls synchronously. This package carries the shapes of that
contract and nothing that runs. It has no Effect dependency, runtime or
development: the declaration re-exports the AST vocabulary from
@systemfsoftware/stryker-ignorer-interface (declared as a runtime dependency,
so the emitted declaration keeps one physical copy of the recursive Node), and
the lint preset bans Effect imports outright.
| Export | What it is |
| -------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| Framework | The object a plugin exports: { kind: 'Framework', name, claim, parse, transform, print, disableTypeChecks } — every hook synchronous |
| FrameworkRefusal | What a plugin exports instead when the peer it needs cannot serve: { kind: 'FrameworkRefusal', name, reason, peer, detail } with reason PeerMissing (the peer is not installed), PeerVersionUnsupported (it is outside the supported range), or PeerUnrecognized (it resolved but does not export what the plugin needs); the host refuses the run |
| FrameworkContribution | Framework \| FrameworkRefusal — the element type of strykerFrameworks |
| FrameworkClaim | { formatId, extensions, language, ownerVersion, contractVersion } — the extensions the plugin owns, the report language its files carry, the framework runtime it resolved, and the contract it targets |
| FrameworkContractVersion | The contract version this package describes ('1'); the host refuses a claim that names any other |
| FrameworkParseResult<A> | { kind: 'Parsed', value } \| { kind: 'ParseFailed', message } — how parse and disableTypeChecks report a claimed file that does not parse |
| FormatId | The claimed format's identity — a plain string the plugin picks once, where it declares the claim |
| ScriptFormat | The script vocabulary an embedded region may carry — js, ts, or tsx |
| EmbeddedDocument | A parsed framework file: { formatId, rawContent, regions } — the untouched document plus the script regions the core instruments |
| ScriptRegion | One located script inside that document: { start, end, isExpression, scriptAst }, offsets into the document, never the slice — scriptAst is the region's slice parsed to a Program, handed over by the core, so a hook never re-parses or re-checks it |
| FrameworkContext | The toolkit the core hands a hook: parseScript, printScript, instrumentationHeader — the core constructs it at hook invocation, the plugin only calls it |
| FrameworkPackageManifest | The package.json shape of a plugin package: a top-level "strykerFramework": { "extensions": [...] } naming the extensions the plugin's framework claims. The host reads it from installed packages to name a plugin in a skip reason without importing the module |
| vocabulary | the AST vocabulary, re-exported from @systemfsoftware/stryker-ignorer-interface — Node, Program, Statement, and every node |
Everything the package publishes is a type.
Install
pnpm add -D @systemfsoftware/stryker-framework-interfaceWrite a framework plugin
A plugin exports its framework from its entry module, typed against this package:
import type { FormatId, Framework, FrameworkContribution } from '@systemfsoftware/stryker-framework-interface'
const html: Framework = {
kind: 'Framework',
name: 'html',
claim: {
formatId: 'html',
extensions: ['.html', '.htm', '.vue'],
language: 'html',
ownerVersion: '10.12.0',
contractVersion: '1',
},
parse: (rawContent, context) => parseDocument(rawContent, context),
transform: (document, context) => transformRegions(document, context),
print: (document, context) => printRegions(document, context),
disableTypeChecks: (rawContent) => disableInRegions(rawContent),
}
export const strykerFrameworks: readonly FrameworkContribution[] = [html]Users add the plugin package to plugins in their StrykerJS config — as a bare
package name resolved from the project ('@systemfsoftware/stryker-js-angular')
or as an explicit file: URL. Plugins are never auto-discovered.
Declare the same extensions in the package's package.json under a top-level
"strykerFramework": { "extensions": [...] } field: the host reads that
manifest from installed packages to name the package in a skip reason without
importing the module.
A plugin that needs a peer resolves it when its module is evaluated (top-level
await import(...)). When the peer is absent, outside the supported range, or
does not export what the plugin needs, it exports a FrameworkRefusal in place
of its framework, and the host refuses the run with that reason before
instrumenting anything. Any other failure while importing the peer is left to
propagate: the host reports it as a plugin that crashed on import.
FormatId is a plain string: a plugin picks its own id once, where it declares
the claim, and keeps it stable across releases — incremental state keys a file's
format identity on it.
The claim's ownerVersion names the framework runtime the plugin resolved and
owns — the compiler or parser a mutant's printed form has to survive. The host
stamps it into incremental state, so upgrading that runtime invalidates the
mutants an earlier run remembered instead of reusing results the new runtime
never produced.
Boundaries
This package is the tier both sides depend on and neither side owns:
- the plugin imports it to type its framework, its claim, its document, and its hook argument;
- the instrumenter imports it to adapt a framework into a registry entry and to construct the
FrameworkContextit passes at hook invocation; - the host (
@systemfsoftware/stryker-js) imports it to validate what a plugin module exports understrykerFrameworks.
Contributing
Development setup and workflow: AGENTS.md.
