
Security News
PHP Foundation Says Chainguard Broke Security Embargo Ahead of Emergency Patches
The PHP Foundation says Chainguard broke a security embargo ahead of critical RCE patches, as leaks disrupted the coordinated release.
@claudiu-ceia/spatch
Advanced tools
Structural patcher for TS/JS using a patch-document template format.
Deterministic structural rewrites for TypeScript/JavaScript using a compact patch-document format.
spatch lets you describe a code change once and apply it safely across a scoped project.
npm install --save-dev @claudiu-ceia/spatch
Or run directly:
npx @claudiu-ceia/spatch --help
Create a patch file:
-const :[name] = :[value];
+let :[name] = :[value];
Preview:
spatch rules/const-to-let.spatch src --dry-run
Apply:
spatch rules/const-to-let.spatch src
CI guardrail:
spatch rules/const-to-let.spatch src --check
A patch document is line-based:
-... deletion line: belongs to the match pattern only+... addition line: belongs to the replacement only ... context line: shared by both pattern and replacement\-... and \+... escaped markers: literal context starting with - or +At least one - or + line is required.
If the patch document ends with a trailing newline, generated pattern and replacement preserve that newline.
Patch input can be:
- to read from stdinExamples:
# file input
spatch rules/rename.spatch src
# stdin input
cat rules/rename.spatch | spatch - src
# inline input (bash/zsh)
spatch $'-foo(:[x])\n+bar(:[x])' src
Supported placeholders:
:[name] named capture:[_] anonymous wildcard (not captured):[name~regex] named capture constrained by regex... variadic wildcard, reusable in replacementExamples:
-const :[name~[a-zA-Z_$][\w$]*] = :[value];
+let :[name] = :[value];
-transform(:[input], :[config], ...);
+normalize(:[input], :[config], ...);
Repeated names enforce equality:
-:[x] + :[x]
+double(:[x])
Regex constraint safety limits:
256 characters256 cumulative ambiguity expansions across alternatives,
sequences, and bounded repetitions; overlapping variable sibling repetitions; unbounded repetition
of nullable or ambiguous alternatives; and compounding nested quantifiers2048 cumulative work units; deterministic non-nullable ranges
do not consume ambiguity expansions2048 characters are rejected during matchingspatch matches structurally, not by raw text equality.
... captures variadic middle segmentsFormatting behavior:
Example rewrite:
-transform(:[input], :[config], ...);
+normalize(:[input], :[config], ...);
// source
const call = transform(source /* keep comment */, cfg, optA, optB);
// after spatch
const call = normalize(source /* keep comment */, cfg, optA, optB);
spatch \
[--interactive] \
[--json] \
[--no-color] \
[--dry-run] \
[--check] \
[--cwd <path>] \
[--concurrency <n>] \
[--verbose <level>] \
<patch-input> [scope]
# through umbrella CLI
astkit patch \
[--interactive] \
[--json] \
[--no-color] \
[--dry-run] \
[--check] \
[--cwd <path>] \
[--concurrency <n>] \
[--verbose <level>] \
<patch-input> [scope]
Flags:
--dry-run: preview changes without writing files--check: fail with non-zero exit if replacements would be made (implies dry-run)--interactive: confirm each change (y/n/a/q)--json: emit structured JSON result--no-color: disable colored output--cwd <path>: working directory used to resolve patch input and scope--concurrency <n>: max files processed in parallel (default 8)--verbose <level>: perf tracing (1=summary, 2=includes slow files)Notes:
--interactive cannot be combined with --dry-run or --checkspatch --help for generated stricli help text--json returns the full SpatchResult object.Scope boundary:
cwd is inside a git repository, scope must stay within the nearest repo rootcwdWrite safety:
Compact output escapes control characters in paths and preview text.
import {
DEFAULT_EXCLUDED_DIRECTORIES,
DEFAULT_PATCHABLE_EXTENSIONS,
patchProject,
type SpatchOptions,
type SpatchResult,
} from "@claudiu-ceia/spatch";
Example:
const result = await patchProject("rules/const-to-let.spatch", {
cwd: "/repo",
scope: "src",
dryRun: true,
encoding: "utf8",
concurrency: 8,
verbose: 1,
logger: console.error,
});
console.log(result.totalReplacements);
patchInput can be patch text or a patch file path.
--dry-run (and optionally --interactive) firstFrom monorepo root:
bun run spatch -- --help
bun run test:spatch
bun run test:spatch:coverage
bun run typecheck
FAQs
Structural patcher for TS/JS using a patch-document template format.
We found that @claudiu-ceia/spatch demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.

Security News
The PHP Foundation says Chainguard broke a security embargo ahead of critical RCE patches, as leaks disrupted the coordinated release.

Security News
PHP releases emergency patches for two critical RCE vulnerabilities as agencies urge organizations to take unpatched sites offline.

Threat Research
/Security News
A supply chain attack compromised LiteLLM 1.107.0 on PyPI and Docker, spreading malware that steals cloud credentials, developer secrets, and AI provider keys.