MemberJunction's engineering standards, as runnable checks — plus the scaffolding that gets a repository actually enforcing them.
npx mj-standards adopt --ci github --declare-compliant # set a repo up
npx mj-standards check # run what it adopted
npx mj-standards list # what exists, and this repo's stance
Inside a repo that has the MJ CLI, the same commands are mj standards adopt / check / list.
MJ has two kinds of standards and they need opposite distribution mechanisms.
Judgment standards are prose that has to be read — the guides in the MJ repo. They are distributed as documentation.
Executable standards are the ones a machine can settle. Those are here, versioned like code, because copy-pasting a check script into each repo stops scaling at about five repos and guarantees that half of them are running a version from eight months ago.
Adding a standard to this package never changes an existing repository's result.
Three mechanisms, together:
.mj-standards.json names it.
Registration makes a check available, not active.Since).
Each repo records the version it adopted against (StandardsVersion). Checks newer than that
are reported as available and are not run — upgrading this package cannot activate them.DefaultSeverity is what adopt writes for a
new adopter. Changing it here never changes a repo that has already adopted. Severity can
decay forward — warn → error on a major, by the repo's own choice — and never backward into
something already shipped.The result: this package can ship new standards continuously, and a repo pinned on an older MJ never wakes up to a red build it did not ask for. Adopting a new standard is always a visible, reviewable commit.
.mj-standards.json{
"$schema": "./node_modules/@memberjunction/standards/schema/mj-standards.schema.json",
"StandardsVersion": "6.0.0", // what this repo adopted against
"Checks": {
"ui-layers": {
"Severity": "error", // off | warn | error
"Roots": ["packages"],
"Options": {
// Locked subtrees: an undeclared package HERE is a failure. Everywhere else it is
// skipped. This is the shape a real migration takes — one tree cleaned and held, the
// rest still being worked through.
"requireDeclaredIn": ["packages/Angular"]
}
}
}
}
A check absent from Checks does not run. A check present but off does not run and is not
nagged about — the repo has seen it and said no.
adoptWrites the config, and optionally a CI workflow, an npm script, and the per-package declarations.
Idempotent and additive: it never lowers a severity you raised, never overwrites a CI file you
edited, and never bumps StandardsVersion without --upgrade.
| Flag | |
|---|---|
--ci github |
write .github/workflows/mj-standards.yml |
--declare-compliant |
declare mjUILayer on packages that already pass |
--upgrade |
enable standards newer than the recorded version, and bump it |
--dry-run |
report, write nothing |
--declare-compliant matters more than it looks. Without it, a fresh adoption produces a
config that enforces nothing: every package is undeclared, so every package is skipped, and the
repo gets a green check that means nothing.
It takes the strictest layer each package honestly qualifies for and never assigns shell.
shell checks nothing, so every package passes as shell — assigning it would hand a permanent
exemption to exactly the packages that need work. (An earlier version did assign it; a two-package
test repo caught it in the first run, with the deliberately-broken package coming back declared
shell and passing.) A package that qualifies for nothing is reported, not declared.
checkRuns the adopted standards. Exit 1 on error violations only; --strict also fails on warnings —
the flag to turn on once a newly adopted check is clean.
listEvery registered standard, when it was introduced, and what this repo does with it.
| Id | Since | What it enforces |
|---|---|---|
ui-layers |
6.0.0 | The four-layer UI architecture — guide. Widgets may not import @angular/router or MJ Explorer, and may not construct a global-provider RunView/Metadata. Packages opt in with "mjUILayer" in their own package.json. |
StandardCheck in src/checks/.Since to the MJ version it will ship in. Never backdate it — that would silently
activate the check in repos that adopted before it existed.src/registry.ts.DocsUrl. Every failure prints it; a rule whose reasoning is one click away gets
followed, and one that just says "no" gets worked around.DefaultSeverity: 'warn' first if it is likely to have a long tail.No runtime dependencies. This gets installed into client repos and run in CI; every dependency is one more thing that can conflict with their tree. The only non-trivial thing it needed was semver comparison, which is twenty lines.
Comments are stripped before matching. MJ source documents itself heavily — a JSDoc block
explaining "this calls new RunView() on the global provider" is a comment about a violation, not
a violation. A gate that cannot tell the difference gets switched off.
Only zero-argument constructors are flagged. new RunView(provider) passes a provider
explicitly and is correct. An earlier, blunter pattern flagged it; false positives are how a gate
loses its authority.
Reviewed exceptions use a marker in a comment on the offending line, or the line directly
above it — one line, so a marker cannot drift away from what it excuses. For ui-layers the marker
is mj-ui-layers-allow.
@memberjunction/standards— MemberJunction's engineering standards, as runnable checks.What this is for
MJ's standards live in two forms. Judgment standards are prose that has to be read — the guides in the MJ repo. Executable standards are the ones a machine can settle, and those are here. Shipping them as a versioned package rather than a file to copy is what lets a dozen repos — first-party, client, and external — stay aligned as the standards evolve.
The property that makes it safe
A new standard never changes an existing repo's result. A check is registered here as available; it does not run until a repo's
.mj-standards.jsonnames it. Checks whoseSincepostdates the repo's recordedStandardsVersionare reported as available and stay inert until a human runsmj standards adopt --upgrade.That means this package can ship new standards continuously, and a repo pinned on an older MJ never wakes up to a red build it did not ask for.
Usage