refactor(edit): removed unsupported ignore-case and multiline sed flags
- Removed `i` and `m` from the Atom sed schema and docs, so sed now accepts only `pat`, `rep`, `g`, and `F` options. - Updated `SedSpec` parsing and serialization to drop ignore-case and multiline handling. - Adjusted regex construction to apply sed replacements using only global and literal flags.
This commit is contained in:
@@ -12,7 +12,7 @@
|
||||
* { path, loc: "5th", pre: [...], splice: [...], post: [...] }
|
||||
* { path, loc: "$", pre: [...] } // prepend to file
|
||||
* { path, loc: "$", post: [...] } // append to file
|
||||
* { path, loc: "$", sed: { pat, rep, g?, F?, i?, m? } } // sed on every line
|
||||
* { path, loc: "$", sed: { pat, rep, g?, F? } } // sed on every line
|
||||
*
|
||||
* `splice: []` on a single-anchor locator deletes that line. `splice:[""]` preserves
|
||||
* a blank line. Line ranges are not supported.
|
||||
@@ -72,8 +72,6 @@ export const atomEditSchema = Type.Object(
|
||||
rep: Type.String({ description: "replacement text" }),
|
||||
g: Type.Optional(Type.Boolean({ description: "global replace", default: false })),
|
||||
F: Type.Optional(Type.Boolean({ description: "literal replace", default: false })),
|
||||
i: Type.Optional(Type.Boolean({ description: "ignore case", default: false })),
|
||||
m: Type.Optional(Type.Boolean({ description: "multiline mode (^ and $ match line boundaries)", default: false })),
|
||||
},
|
||||
{
|
||||
additionalProperties: false,
|
||||
@@ -110,11 +108,9 @@ export type AtomEdit =
|
||||
| { op: "sed_file"; spec: SedSpec; expression: string };
|
||||
|
||||
export interface SedSpec {
|
||||
multiline: boolean;
|
||||
pattern: string;
|
||||
replacement: string;
|
||||
global: boolean;
|
||||
ignoreCase: boolean;
|
||||
literal: boolean;
|
||||
}
|
||||
|
||||
@@ -270,7 +266,7 @@ function extractAnchorContentHint(raw: string): string | undefined {
|
||||
|
||||
function parseSedSpec(input: unknown, editIndex: number): SedSpec {
|
||||
if (input === null || typeof input !== "object" || Array.isArray(input)) {
|
||||
throw new Error(`Edit ${editIndex}: sed must be an object with shape {pat, rep, g?, F?, i?, m?}.`);
|
||||
throw new Error(`Edit ${editIndex}: sed must be an object with shape {pat, rep, g?, F?}.`);
|
||||
}
|
||||
const obj = input as Record<string, unknown>;
|
||||
const pat = obj.pat;
|
||||
@@ -286,7 +282,7 @@ function parseSedSpec(input: unknown, editIndex: number): SedSpec {
|
||||
if (typeof rep !== "string") {
|
||||
throw new Error(`Edit ${editIndex}: sed.rep must be a string.`);
|
||||
}
|
||||
const readBool = (key: "g" | "F" | "i" | "m", defaultValue: boolean): boolean => {
|
||||
const readBool = (key: "g" | "F", defaultValue: boolean): boolean => {
|
||||
const v = obj[key];
|
||||
if (v === undefined) return defaultValue;
|
||||
if (typeof v !== "boolean") {
|
||||
@@ -296,21 +292,17 @@ function parseSedSpec(input: unknown, editIndex: number): SedSpec {
|
||||
};
|
||||
const global = readBool("g", false);
|
||||
const literal = readBool("F", false);
|
||||
const ignoreCase = readBool("i", false);
|
||||
const multiline = readBool("m", false);
|
||||
return { pattern: pat, replacement: rep, global, literal, ignoreCase, multiline };
|
||||
return { pattern: pat, replacement: rep, global, literal };
|
||||
}
|
||||
|
||||
function formatSedExpression(spec: SedSpec): string {
|
||||
const obj: { pat: string; rep: string; g?: boolean; F?: boolean; i?: boolean; m?: boolean } = {
|
||||
const obj: { pat: string; rep: string; g?: boolean; F?: boolean } = {
|
||||
pat: spec.pattern,
|
||||
rep: spec.replacement,
|
||||
};
|
||||
// Only emit non-default flags so error messages stay compact (g defaults false).
|
||||
if (spec.global) obj.g = true;
|
||||
if (spec.literal) obj.F = true;
|
||||
if (spec.ignoreCase) obj.i = true;
|
||||
if (spec.multiline) obj.m = true;
|
||||
return JSON.stringify(obj);
|
||||
}
|
||||
|
||||
@@ -335,8 +327,6 @@ function applySedToLine(
|
||||
}
|
||||
let flags = "";
|
||||
if (spec.global) flags += "g";
|
||||
if (spec.ignoreCase) flags += "i";
|
||||
if (spec.multiline) flags += "m";
|
||||
let re: RegExp | undefined;
|
||||
let compileError: string | undefined;
|
||||
try {
|
||||
|
||||
@@ -14,13 +14,11 @@ Verbs:
|
||||
- `splice: […]`: lines are spliced in at the anchor.
|
||||
- `pre: […]`: prepend before the anchor (or at BOF if `loc=$`)
|
||||
- `post: […]`: append after the anchor (or at EOF if `loc=$`)
|
||||
- `sed: { pat, rep, g?, F?, i?, m? }` — structured find/replace on the anchor line. **Prefer this over `splice` for token-level changes**
|
||||
- `sed: { pat, rep, g?, F? }` — structured find/replace on the anchor line. **Prefer this over `splice` for token-level changes**
|
||||
- `pat`: pattern to find (regex by default)
|
||||
- `rep`: replacement (regex back-refs like `$1`, `$&` available)
|
||||
- `g`: global — replace every occurrence (default `false`; pass `true` to replace all)
|
||||
- `F`: literal — treat `pat` as a literal substring (no regex). Use this whenever `pat` contains `||`, `.`, `(`, `?`, `\`, etc. you mean literally.
|
||||
- `i`: ignore case
|
||||
- `m`: multiline — `^` and `$` match line boundaries
|
||||
You **MUST** keep `pat` as short as possible.
|
||||
|
||||
Combination rules:
|
||||
|
||||
Reference in New Issue
Block a user