appease 0.0.1 → 0.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,99 @@
1
+ import picomatch from "picomatch";
2
+ /**
3
+ * Parse `.editorconfig` content into ordered sections. Pure.
4
+ * Throws on a structurally malformed line (case 3); properties we do not manage
5
+ * (indent_*, max_line_length, ...) are ignored (case 1).
6
+ */
7
+ export function parseEditorconfig(content) {
8
+ let root = false;
9
+ const sections = [];
10
+ let current; // undefined = preamble (before any section)
11
+ content.split(/\r\n|\r|\n/).forEach((rawLine, index) => {
12
+ const line = rawLine.trim();
13
+ if (line === "" || line.startsWith("#") || line.startsWith(";"))
14
+ return;
15
+ if (line.startsWith("[")) {
16
+ if (!line.endsWith("]"))
17
+ throw new Error(`Malformed .editorconfig line ${index + 1}: "${rawLine}"`);
18
+ current = { matches: makeMatcher(line.slice(1, -1)), charset: undefined, trim: undefined, finalNewline: undefined };
19
+ sections.push(current);
20
+ return;
21
+ }
22
+ const eq = line.indexOf("=");
23
+ if (eq === -1)
24
+ throw new Error(`Malformed .editorconfig line ${index + 1}: "${rawLine}"`);
25
+ const key = line.slice(0, eq).trim().toLowerCase();
26
+ const value = line.slice(eq + 1).trim().toLowerCase();
27
+ if (current === undefined) {
28
+ if (key === "root")
29
+ root = value === "true";
30
+ return; // other preamble keys are not standard — ignored
31
+ }
32
+ applyProperty(current, key, value);
33
+ });
34
+ return { root, sections };
35
+ }
36
+ /** Resolve the effective stance for `path` (last matching section wins per property). */
37
+ export function resolveEditorconfig(ec, path) {
38
+ let charset;
39
+ let trim;
40
+ let finalNewline;
41
+ for (const section of ec.sections) {
42
+ if (!section.matches(path))
43
+ continue;
44
+ if (section.charset !== undefined)
45
+ charset = section.charset;
46
+ if (section.trim !== undefined)
47
+ trim = section.trim;
48
+ if (section.finalNewline !== undefined)
49
+ finalNewline = section.finalNewline;
50
+ }
51
+ const unresolved = [];
52
+ let outCharset = "keep";
53
+ if (charset === "utf-8")
54
+ outCharset = "utf-8";
55
+ else if (charset === "utf-8-bom")
56
+ outCharset = "utf-8-bom";
57
+ else if (charset === "unrecognized")
58
+ unresolved.push("bom");
59
+ let outTrailing = "keep";
60
+ if (trim === true)
61
+ outTrailing = "trim";
62
+ else if (trim === "unrecognized")
63
+ unresolved.push("trailing");
64
+ let outFinalNewline = "keep";
65
+ if (finalNewline === true)
66
+ outFinalNewline = "ensure";
67
+ else if (finalNewline === "unrecognized")
68
+ unresolved.push("finalNewline");
69
+ return { charset: outCharset, trailing: outTrailing, finalNewline: outFinalNewline, unresolved };
70
+ }
71
+ function applyProperty(section, key, value) {
72
+ if (key === "charset") {
73
+ section.charset =
74
+ value === "utf-8" ? "utf-8" : value === "utf-8-bom" ? "utf-8-bom" : value === "unset" ? "unset" : "unrecognized";
75
+ }
76
+ else if (key === "trim_trailing_whitespace") {
77
+ section.trim = parseBool(value);
78
+ }
79
+ else if (key === "insert_final_newline") {
80
+ section.finalNewline = parseBool(value);
81
+ }
82
+ // else: a property we do not manage (indent_*, max_line_length, ...) — ignored (case 1)
83
+ }
84
+ function parseBool(value) {
85
+ if (value === "true")
86
+ return true;
87
+ if (value === "false")
88
+ return false;
89
+ if (value === "unset")
90
+ return "unset";
91
+ return "unrecognized";
92
+ }
93
+ /** Build an editorconfig glob matcher: a slashless glob matches the basename at any depth; any `/` (even leading) anchors it. */
94
+ function makeMatcher(glob) {
95
+ const basename = !glob.includes("/");
96
+ const pat = glob.startsWith("/") ? glob.slice(1) : glob;
97
+ return picomatch(pat, { dot: true, basename });
98
+ }
99
+ //# sourceMappingURL=editorconfig.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"editorconfig.js","sourceRoot":"","sources":["../../src/core/editorconfig.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,26 @@
1
+ /**
2
+ * EOL stance for a path as declared by `.gitattributes`.
3
+ * - `auto` : text, native EOL (the `* text=auto` default).
4
+ * - `lf` / `crlf`: a fixed EOL via `eol=`.
5
+ * - `binary` : `-text` / `binary` — not normalized.
6
+ * - `unresolved` : a recognized key with an unrecognized value (case 2: skip + report).
7
+ */
8
+ export type GitEol = "lf" | "crlf" | "auto" | "binary" | "unresolved";
9
+ interface GitRule {
10
+ matches: (path: string) => boolean;
11
+ /** `text` attribute state; `binary` and `-text` both map to `unset`. */
12
+ text: "set" | "unset" | "auto" | "unrecognized" | undefined;
13
+ eol: "lf" | "crlf" | "unrecognized" | undefined;
14
+ }
15
+ export interface Gitattributes {
16
+ rules: GitRule[];
17
+ }
18
+ /**
19
+ * Parse `.gitattributes` content into ordered rules. Pure.
20
+ * Throws on a structurally malformed line (case 3); attributes we do not manage
21
+ * (filter, diff, linguist-*, ...) are ignored (case 1).
22
+ */
23
+ export declare function parseGitattributes(content: string): Gitattributes;
24
+ /** Resolve the effective EOL stance for `path` (last matching rule wins per attribute). */
25
+ export declare function resolveGitEol(ga: Gitattributes, path: string): GitEol;
26
+ export {};
@@ -0,0 +1,70 @@
1
+ import picomatch from "picomatch";
2
+ /**
3
+ * Parse `.gitattributes` content into ordered rules. Pure.
4
+ * Throws on a structurally malformed line (case 3); attributes we do not manage
5
+ * (filter, diff, linguist-*, ...) are ignored (case 1).
6
+ */
7
+ export function parseGitattributes(content) {
8
+ const rules = [];
9
+ content.split(/\r\n|\r|\n/).forEach((rawLine, index) => {
10
+ const line = rawLine.trim();
11
+ if (line === "" || line.startsWith("#"))
12
+ return;
13
+ const [pattern, ...attrs] = line.split(/\s+/);
14
+ let text;
15
+ let eol;
16
+ for (const attr of attrs) {
17
+ if (attr.startsWith("="))
18
+ throw new Error(`Malformed .gitattributes line ${index + 1}: "${rawLine}"`);
19
+ if (attr === "text")
20
+ text = "set";
21
+ else if (attr === "-text" || attr === "binary")
22
+ text = "unset"; // binary macro = -text -diff
23
+ else if (attr === "!text")
24
+ text = undefined; // unset the attribute: no effect
25
+ else if (attr === "text=auto")
26
+ text = "auto";
27
+ else if (attr.startsWith("text="))
28
+ text = "unrecognized";
29
+ else if (attr === "eol=lf")
30
+ eol = "lf";
31
+ else if (attr === "eol=crlf")
32
+ eol = "crlf";
33
+ else if (attr.startsWith("eol="))
34
+ eol = "unrecognized";
35
+ // else: an attribute we do not manage — ignored (case 1)
36
+ }
37
+ rules.push({ matches: makeMatcher(pattern), text, eol });
38
+ });
39
+ return { rules };
40
+ }
41
+ /** Resolve the effective EOL stance for `path` (last matching rule wins per attribute). */
42
+ export function resolveGitEol(ga, path) {
43
+ let text;
44
+ let eol;
45
+ for (const rule of ga.rules) {
46
+ if (!rule.matches(path))
47
+ continue;
48
+ if (rule.text !== undefined)
49
+ text = rule.text;
50
+ if (rule.eol !== undefined)
51
+ eol = rule.eol;
52
+ }
53
+ if (text === "unset")
54
+ return "binary";
55
+ if (text === "unrecognized" || eol === "unrecognized")
56
+ return "unresolved";
57
+ if (eol === "lf")
58
+ return "lf";
59
+ if (eol === "crlf")
60
+ return "crlf";
61
+ return "auto";
62
+ }
63
+ /** Build a gitignore-style matcher: leading `/` anchors to root; a slashless pattern matches the basename. */
64
+ function makeMatcher(pattern) {
65
+ const anchored = pattern.startsWith("/");
66
+ const pat = anchored ? pattern.slice(1) : pattern;
67
+ const basename = !anchored && !pat.includes("/");
68
+ return picomatch(pat, { dot: true, basename });
69
+ }
70
+ //# sourceMappingURL=gitattributes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gitattributes.js","sourceRoot":"","sources":["../../src/core/gitattributes.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,39 @@
1
+ import type { DeviationAxis, FormatReport } from "./types.js";
2
+ /** One audited file with findings, ready to turn into config exceptions. */
3
+ export interface AuditedFile {
4
+ path: string;
5
+ report: FormatReport;
6
+ deviations: DeviationAxis[];
7
+ }
8
+ /** A `.editorconfig` exception: a section locking some axes to "don't enforce". */
9
+ export interface EditorconfigException {
10
+ pattern: string;
11
+ properties: string[];
12
+ }
13
+ /** A `.gitattributes` exception: a rule line fixing or locking the EOL. */
14
+ export interface GitattributesException {
15
+ pattern: string;
16
+ attrs: string;
17
+ }
18
+ export interface ConfigExceptions {
19
+ editorconfig: EditorconfigException[];
20
+ gitattributes: GitattributesException[];
21
+ }
22
+ /**
23
+ * Turn audited deviations into the concrete config exceptions that `--adapt-configs`
24
+ * records, so a later `--fix-format` changes nothing. EOL is routed to `.gitattributes`
25
+ * using the file's actual ending; a mixed/lone-CR file goes `-text` (byte-for-byte) and
26
+ * is therefore protected whole, so it gets no `.editorconfig` exception.
27
+ */
28
+ export declare function buildExceptions(files: AuditedFile[]): ConfigExceptions;
29
+ /**
30
+ * Append `.editorconfig` exception sections to the existing content, preserving
31
+ * everything already there. Idempotent: a pattern that already has a section is
32
+ * skipped. New sections use the file's own EOL.
33
+ */
34
+ export declare function mergeEditorconfig(existing: string, exceptions: EditorconfigException[]): string;
35
+ /**
36
+ * Append `.gitattributes` exception lines to the existing content, preserving
37
+ * everything already there. Idempotent: a pattern that already has a rule is skipped.
38
+ */
39
+ export declare function mergeGitattributes(existing: string, exceptions: GitattributesException[]): string;
@@ -0,0 +1,98 @@
1
+ /** The "don't enforce" value written for each editorconfig-owned axis. */
2
+ const EDITORCONFIG_PROPERTY = {
3
+ bom: "charset = unset",
4
+ trailing: "trim_trailing_whitespace = false",
5
+ finalNewline: "insert_final_newline = false",
6
+ };
7
+ /**
8
+ * Turn audited deviations into the concrete config exceptions that `--adapt-configs`
9
+ * records, so a later `--fix-format` changes nothing. EOL is routed to `.gitattributes`
10
+ * using the file's actual ending; a mixed/lone-CR file goes `-text` (byte-for-byte) and
11
+ * is therefore protected whole, so it gets no `.editorconfig` exception.
12
+ */
13
+ export function buildExceptions(files) {
14
+ const editorconfig = [];
15
+ const gitattributes = [];
16
+ for (const file of files) {
17
+ let binary = false;
18
+ if (file.deviations.includes("eol")) {
19
+ const attrs = eolAttrs(file.report);
20
+ gitattributes.push({ pattern: file.path, attrs });
21
+ binary = attrs === "-text";
22
+ }
23
+ if (!binary) {
24
+ const properties = file.deviations.filter(isEditorconfigAxis).map((axis) => EDITORCONFIG_PROPERTY[axis]);
25
+ if (properties.length > 0)
26
+ editorconfig.push({ pattern: file.path, properties });
27
+ }
28
+ }
29
+ return { editorconfig, gitattributes };
30
+ }
31
+ /** The `.gitattributes` attributes that lock a file's current EOL. */
32
+ function eolAttrs(report) {
33
+ if (report.hasLf && !report.hasCrlf && !report.hasCr)
34
+ return "text eol=lf";
35
+ if (report.hasCrlf && !report.hasLf && !report.hasCr)
36
+ return "text eol=crlf";
37
+ return "-text"; // mixed or lone CR: no clean eol=, lock byte-for-byte
38
+ }
39
+ function isEditorconfigAxis(axis) {
40
+ return axis !== "eol";
41
+ }
42
+ /**
43
+ * Append `.editorconfig` exception sections to the existing content, preserving
44
+ * everything already there. Idempotent: a pattern that already has a section is
45
+ * skipped. New sections use the file's own EOL.
46
+ */
47
+ export function mergeEditorconfig(existing, exceptions) {
48
+ const present = sectionPatterns(existing);
49
+ const toAdd = exceptions.filter((exception) => !present.has(exception.pattern));
50
+ if (toAdd.length === 0)
51
+ return existing;
52
+ const eol = detectEol(existing);
53
+ const sections = toAdd.map((exception) => [`[${exception.pattern}]`, ...exception.properties].join(eol));
54
+ return append(existing, sections.join(eol + eol), eol);
55
+ }
56
+ /**
57
+ * Append `.gitattributes` exception lines to the existing content, preserving
58
+ * everything already there. Idempotent: a pattern that already has a rule is skipped.
59
+ */
60
+ export function mergeGitattributes(existing, exceptions) {
61
+ const present = gitattributesPatterns(existing);
62
+ const toAdd = exceptions.filter((exception) => !present.has(exception.pattern));
63
+ if (toAdd.length === 0)
64
+ return existing;
65
+ const eol = detectEol(existing);
66
+ const lines = toAdd.map((exception) => `${exception.pattern} ${exception.attrs}`);
67
+ return append(existing, lines.join(eol), eol);
68
+ }
69
+ /** Patterns of existing `[glob]` sections. */
70
+ function sectionPatterns(content) {
71
+ const patterns = new Set();
72
+ for (const raw of content.split(/\r\n|\r|\n/)) {
73
+ const line = raw.trim();
74
+ if (line.startsWith("[") && line.endsWith("]"))
75
+ patterns.add(line.slice(1, -1));
76
+ }
77
+ return patterns;
78
+ }
79
+ /** Patterns (first token) of existing `.gitattributes` rules. */
80
+ function gitattributesPatterns(content) {
81
+ const patterns = new Set();
82
+ for (const raw of content.split(/\r\n|\r|\n/)) {
83
+ const line = raw.trim();
84
+ if (line !== "" && !line.startsWith("#"))
85
+ patterns.add(line.split(/\s+/)[0]);
86
+ }
87
+ return patterns;
88
+ }
89
+ /** The file's existing EOL (LF/CRLF), defaulting to LF. */
90
+ function detectEol(content) {
91
+ return content.match(/\r\n|\n/)?.[0] ?? "\n";
92
+ }
93
+ /** Append `addition` after the existing content, separated by a blank line, ending with one EOL. */
94
+ function append(existing, addition, eol) {
95
+ const base = existing.replace(/(?:\r\n|\r|\n)*$/, "");
96
+ return (base === "" ? "" : base + eol + eol) + addition + eol;
97
+ }
98
+ //# sourceMappingURL=merge.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"merge.js","sourceRoot":"","sources":["../../src/core/merge.ts"],"names":[],"mappings":"AA0BA,0EAA0E;AAC1E,MAAM,qBAAqB,GAAwD;IACjF,GAAG,EAAE,iBAAiB;IACtB,QAAQ,EAAE,kCAAkC;IAC5C,YAAY,EAAE,8BAA8B;CAC7C,CAAC;AAEF;;;;;GAKG;AACH,MAAM,UAAU,eAAe,CAAC,KAAoB;IAClD,MAAM,YAAY,GAA4B,EAAE,CAAC;IACjD,MAAM,aAAa,GAA6B,EAAE,CAAC;IACnD,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,MAAM,GAAG,KAAK,CAAC;QACnB,IAAI,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;YACpC,MAAM,KAAK,GAAG,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YACpC,aAAa,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;YAClD,MAAM,GAAG,KAAK,KAAK,OAAO,CAAC;QAC7B,CAAC;QACD,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,MAAM,UAAU,GAAG,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,kBAAkB,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,qBAAqB,CAAC,IAAI,CAAC,CAAC,CAAC;YACzG,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC;gBAAE,YAAY,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,IAAI,CAAC,IAAI,EAAE,UAAU,EAAE,CAAC,CAAC;QACnF,CAAC;IACH,CAAC;IACD,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,CAAC;AACzC,CAAC;AAED,sEAAsE;AACtE,SAAS,QAAQ,CAAC,MAAoB;IACpC,IAAI,MAAM,CAAC,KAAK,IAAI,CAAC,MAAM,CAAC,OAAO,IAAI,CAAC,MAAM,CAAC,KAAK;QAAE,OAAO,aAAa,CAAC;IAC3E,IAAI,MAAM,CAAC,OAAO,IAAI,CAAC,MAAM,CAAC,KAAK,IAAI,CAAC,MAAM,CAAC,KAAK;QAAE,OAAO,eAAe,CAAC;IAC7E,OAAO,OAAO,CAAC,CAAC,sDAAsD;AACxE,CAAC;AAED,SAAS,kBAAkB,CAAC,IAAmB;IAC7C,OAAO,IAAI,KAAK,KAAK,CAAC;AACxB,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,iBAAiB,CAAC,QAAgB,EAAE,UAAmC;IACrF,MAAM,OAAO,GAAG,eAAe,CAAC,QAAQ,CAAC,CAAC;IAC1C,MAAM,KAAK,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC;IAChF,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,QAAQ,CAAC;IACxC,MAAM,GAAG,GAAG,SAAS,CAAC,QAAQ,CAAC,CAAC;IAChC,MAAM,QAAQ,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC,IAAI,SAAS,CAAC,OAAO,GAAG,EAAE,GAAG,SAAS,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;IACzG,OAAO,MAAM,CAAC,QAAQ,EAAE,QAAQ,CAAC,IAAI,CAAC,GAAG,GAAG,GAAG,CAAC,EAAE,GAAG,CAAC,CAAC;AACzD,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,kBAAkB,CAAC,QAAgB,EAAE,UAAoC;IACvF,MAAM,OAAO,GAAG,qBAAqB,CAAC,QAAQ,CAAC,CAAC;IAChD,MAAM,KAAK,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC;IAChF,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,QAAQ,CAAC;IACxC,MAAM,GAAG,GAAG,SAAS,CAAC,QAAQ,CAAC,CAAC;IAChC,MAAM,KAAK,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,GAAG,SAAS,CAAC,OAAO,IAAI,SAAS,CAAC,KAAK,EAAE,CAAC,CAAC;IAClF,OAAO,MAAM,CAAC,QAAQ,EAAE,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,GAAG,CAAC,CAAC;AAChD,CAAC;AAED,8CAA8C;AAC9C,SAAS,eAAe,CAAC,OAAe;IACtC,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAU,CAAC;IACnC,KAAK,MAAM,GAAG,IAAI,OAAO,CAAC,KAAK,CAAC,YAAY,CAAC,EAAE,CAAC;QAC9C,MAAM,IAAI,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC;QACxB,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC;YAAE,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;IAClF,CAAC;IACD,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,iEAAiE;AACjE,SAAS,qBAAqB,CAAC,OAAe;IAC5C,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAU,CAAC;IACnC,KAAK,MAAM,GAAG,IAAI,OAAO,CAAC,KAAK,CAAC,YAAY,CAAC,EAAE,CAAC;QAC9C,MAAM,IAAI,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC;QACxB,IAAI,IAAI,KAAK,EAAE,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC;YAAE,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC/E,CAAC;IACD,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,2DAA2D;AAC3D,SAAS,SAAS,CAAC,OAAe;IAChC,OAAO,OAAO,CAAC,KAAK,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC;AAC/C,CAAC;AAED,oGAAoG;AACpG,SAAS,MAAM,CAAC,QAAgB,EAAE,QAAgB,EAAE,GAAW;IAC7D,MAAM,IAAI,GAAG,QAAQ,CAAC,OAAO,CAAC,kBAAkB,EAAE,EAAE,CAAC,CAAC;IACtD,OAAO,CAAC,IAAI,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,GAAG,GAAG,GAAG,GAAG,CAAC,GAAG,QAAQ,GAAG,GAAG,CAAC;AAChE,CAAC"}
@@ -0,0 +1,13 @@
1
+ import type { NormalizeOptions } from "./types.js";
2
+ /**
3
+ * Normalization core: take a file's already-decoded content plus the options
4
+ * resolved for that file, and return the normalized content. Pure and side-effect free.
5
+ *
6
+ * Normalizes BOM, EOL (e.g. fixing a mixed file), trailing whitespace and the
7
+ * final newline. EOL is included so the workflow is complete: when the audit
8
+ * finds an EOL anomaly, the normalizer can fix it.
9
+ *
10
+ * Returns the normalized content; the caller detects whether it changed by
11
+ * comparing against the input. Idempotent: running twice produces the same result.
12
+ */
13
+ export declare function normalizeText(content: string, options: NormalizeOptions): string;
@@ -0,0 +1,58 @@
1
+ /** UTF-8 BOM code point. */
2
+ const BOM = String.fromCharCode(0xfeff);
3
+ /**
4
+ * Normalization core: take a file's already-decoded content plus the options
5
+ * resolved for that file, and return the normalized content. Pure and side-effect free.
6
+ *
7
+ * Normalizes BOM, EOL (e.g. fixing a mixed file), trailing whitespace and the
8
+ * final newline. EOL is included so the workflow is complete: when the audit
9
+ * finds an EOL anomaly, the normalizer can fix it.
10
+ *
11
+ * Returns the normalized content; the caller detects whether it changed by
12
+ * comparing against the input. Idempotent: running twice produces the same result.
13
+ */
14
+ export function normalizeText(content, options) {
15
+ let result = applyEol(content, options.eol);
16
+ if (options.trailing === "trim")
17
+ result = trimTrailing(result);
18
+ if (options.finalNewline === "ensure")
19
+ result = ensureFinalNewline(result, options.eol);
20
+ result = applyBom(result, options.bom);
21
+ return result;
22
+ }
23
+ /** Normalize every line ending to a single style (CRLF and lone CR both collapse to LF first). */
24
+ function applyEol(content, eol) {
25
+ if (eol === "keep")
26
+ return content;
27
+ const lf = content.replace(/\r\n?/g, "\n");
28
+ return eol === "crlf" ? lf.replace(/\n/g, "\r\n") : lf;
29
+ }
30
+ /** Remove horizontal whitespace at the end of every line (and at end of file). */
31
+ function trimTrailing(content) {
32
+ return content.replace(/[ \t]+(?=\r|\n|$)/g, "");
33
+ }
34
+ /** Collapse the trailing newlines to exactly one (leaving a truly empty file empty). */
35
+ function ensureFinalNewline(content, eol) {
36
+ if (content === "")
37
+ return content;
38
+ const trailing = content.match(/(\r\n|\r|\n)+$/);
39
+ const body = trailing ? content.slice(0, content.length - trailing[0].length) : content;
40
+ const newline = eol === "crlf"
41
+ ? "\r\n"
42
+ : eol === "lf"
43
+ ? "\n"
44
+ : trailing
45
+ ? trailing[1] // keep: reuse the file's existing final ending
46
+ : (content.match(/\r\n|\r|\n/)?.[0] ?? "\n"); // keep with no trailing newline: infer
47
+ return body + newline;
48
+ }
49
+ /** Add, remove or keep the leading UTF-8 BOM. */
50
+ function applyBom(content, bom) {
51
+ const hasBom = content.charCodeAt(0) === 0xfeff;
52
+ if (bom === "add")
53
+ return hasBom ? content : BOM + content;
54
+ if (bom === "remove")
55
+ return hasBom ? content.slice(1) : content;
56
+ return content;
57
+ }
58
+ //# sourceMappingURL=normalize.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"normalize.js","sourceRoot":"","sources":["../../src/core/normalize.ts"],"names":[],"mappings":"AAEA,4BAA4B;AAC5B,MAAM,GAAG,GAAG,MAAM,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC;AAExC;;;;;;;;;;GAUG;AACH,MAAM,UAAU,aAAa,CAAC,OAAe,EAAE,OAAyB;IACtE,IAAI,MAAM,GAAG,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC;IAC5C,IAAI,OAAO,CAAC,QAAQ,KAAK,MAAM;QAAE,MAAM,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC;IAC/D,IAAI,OAAO,CAAC,YAAY,KAAK,QAAQ;QAAE,MAAM,GAAG,kBAAkB,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC;IACxF,MAAM,GAAG,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC;IACvC,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,kGAAkG;AAClG,SAAS,QAAQ,CAAC,OAAe,EAAE,GAA4B;IAC7D,IAAI,GAAG,KAAK,MAAM;QAAE,OAAO,OAAO,CAAC;IACnC,MAAM,EAAE,GAAG,OAAO,CAAC,OAAO,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;IAC3C,OAAO,GAAG,KAAK,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;AACzD,CAAC;AAED,kFAAkF;AAClF,SAAS,YAAY,CAAC,OAAe;IACnC,OAAO,OAAO,CAAC,OAAO,CAAC,oBAAoB,EAAE,EAAE,CAAC,CAAC;AACnD,CAAC;AAED,wFAAwF;AACxF,SAAS,kBAAkB,CAAC,OAAe,EAAE,GAA4B;IACvE,IAAI,OAAO,KAAK,EAAE;QAAE,OAAO,OAAO,CAAC;IACnC,MAAM,QAAQ,GAAG,OAAO,CAAC,KAAK,CAAC,gBAAgB,CAAC,CAAC;IACjD,MAAM,IAAI,GAAG,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,OAAO,CAAC,MAAM,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC;IACxF,MAAM,OAAO,GACX,GAAG,KAAK,MAAM;QACZ,CAAC,CAAC,MAAM;QACR,CAAC,CAAC,GAAG,KAAK,IAAI;YACZ,CAAC,CAAC,IAAI;YACN,CAAC,CAAC,QAAQ;gBACR,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,+CAA+C;gBAC7D,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,YAAY,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,uCAAuC;IAC7F,OAAO,IAAI,GAAG,OAAO,CAAC;AACxB,CAAC;AAED,iDAAiD;AACjD,SAAS,QAAQ,CAAC,OAAe,EAAE,GAA4B;IAC7D,MAAM,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,KAAK,MAAM,CAAC;IAChD,IAAI,GAAG,KAAK,KAAK;QAAE,OAAO,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,GAAG,OAAO,CAAC;IAC3D,IAAI,GAAG,KAAK,QAAQ;QAAE,OAAO,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC;IACjE,OAAO,OAAO,CAAC;AACjB,CAAC"}
@@ -0,0 +1,102 @@
1
+ /** Final-newline state of a file. */
2
+ export type FinalNewline = "present" | "missing" | "multiple";
3
+ /** Result of analyzing one file's already-decoded text. Pure, side-effect free. */
4
+ export interface FormatReport {
5
+ /** File has no content at all. */
6
+ empty: boolean;
7
+ /** UTF-8 BOM present at the start of the content. */
8
+ hasBom: boolean;
9
+ /** At least one CRLF line ending. */
10
+ hasCrlf: boolean;
11
+ /** At least one lone-LF line ending (LF not preceded by CR). */
12
+ hasLf: boolean;
13
+ /** At least one lone-CR line ending (CR not followed by LF; classic pre-OSX Mac). */
14
+ hasCr: boolean;
15
+ /** At least one line with trailing whitespace. */
16
+ hasTrailingSpaces: boolean;
17
+ /** Final-newline state. */
18
+ finalNewline: FinalNewline;
19
+ }
20
+ /** Resolved per-file options driving the pure normalizer. */
21
+ export interface NormalizeOptions {
22
+ /** Add, remove, or leave the UTF-8 BOM. */
23
+ bom: "add" | "remove" | "keep";
24
+ /** Normalize line endings to a single style, or leave as-is. */
25
+ eol: "lf" | "crlf" | "keep";
26
+ /** Trim trailing whitespace, or leave it. */
27
+ trailing: "trim" | "keep";
28
+ /** Ensure exactly one final newline, or leave as-is. */
29
+ finalNewline: "ensure" | "keep";
30
+ }
31
+ /**
32
+ * Options resolved for a single file from the project config. Aligned with the
33
+ * normalizer's actions, so `--fix-format` can drive `normalizeText` directly.
34
+ */
35
+ export interface ResolvedFileConfig {
36
+ /** From `.editorconfig` charset: `utf-8-bom`->add, `utf-8`->remove, unset/keep->keep. */
37
+ bom: "add" | "remove" | "keep";
38
+ /** From `.gitattributes` (or `auto` for the `text=auto` default; `binary` = not normalized). */
39
+ eol: "lf" | "crlf" | "auto" | "binary";
40
+ trailing: "trim" | "keep";
41
+ finalNewline: "ensure" | "keep";
42
+ /** Axes governed by an unrecognized config value (case 2): skip + report, never normalize. */
43
+ unresolved: DeviationAxis[];
44
+ }
45
+ /** Raw, unparsed contents of the three config sources. `null` = file absent (vs `""` = present but empty). */
46
+ export interface RawConfigs {
47
+ editorconfig: string | null;
48
+ gitattributes: string | null;
49
+ vscodeSettings: string | null;
50
+ }
51
+ /** Parsed, not-yet-resolved project configuration. */
52
+ export interface ProjectConfig {
53
+ /** Whether each config source was found on disk. */
54
+ present: {
55
+ editorconfig: boolean;
56
+ gitattributes: boolean;
57
+ vscodeSettings: boolean;
58
+ };
59
+ /** Resolve the effective options for a given repo-relative path. */
60
+ resolve(path: string): ResolvedFileConfig;
61
+ }
62
+ /** Axis along which a file deviates from its resolved config. */
63
+ export type DeviationAxis = "bom" | "eol" | "trailing" | "finalNewline";
64
+ /** A single file's findings against the resolved config (only files with findings are listed). */
65
+ export interface FileAudit {
66
+ path: string;
67
+ /** Axes where the file differs from what the config asks for. */
68
+ deviations: DeviationAxis[];
69
+ /** Axes governed by an unrecognized config value (case 2): not evaluated, reported as-is. */
70
+ unresolved: DeviationAxis[];
71
+ }
72
+ /** Full audit result. `--audit` prints this as canonical JSON. */
73
+ export interface AuditResult {
74
+ /** Analyzed files that deviate from their resolved config (conforming files are omitted). */
75
+ findings: FileAudit[];
76
+ /** Files not analyzed (binary / `-text` / non-UTF-8), with the reason. */
77
+ notAnalyzed: {
78
+ path: string;
79
+ reason: "binary-extension" | "binary-content" | "gitattributes-notext" | "non-utf8";
80
+ }[];
81
+ }
82
+ export type RunMode = "audit" | "add-config-defaults" | "adapt-configs" | "fix-format";
83
+ /** Options for a full appease run (CLI -> public API). */
84
+ export interface RunOptions {
85
+ mode: RunMode;
86
+ /** Repository root to operate on. */
87
+ cwd: string;
88
+ /** Simulate writes; report what would change but touch nothing. */
89
+ dryRun: boolean;
90
+ }
91
+ /** Outcome of a run: which files were created/modified, plus mode-specific payload. */
92
+ export interface RunReport {
93
+ mode: RunMode;
94
+ /** Whether disk was actually touched (false under `--dry-run`). */
95
+ dryRun: boolean;
96
+ created: string[];
97
+ modified: string[];
98
+ /** Files considered but left untouched (e.g. a config that already existed). */
99
+ unchanged: string[];
100
+ /** Present for `--audit`. */
101
+ audit?: AuditResult;
102
+ }
@@ -0,0 +1,4 @@
1
+ // Strongly-typed contracts for appease (brand: "normalificador").
2
+ // No `any`. Every type here is shared between the pure core and the orchestration (CLI).
3
+ export {};
4
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/core/types.ts"],"names":[],"mappings":"AAAA,kEAAkE;AAClE,yFAAyF"}
@@ -0,0 +1,17 @@
1
+ import type { RunOptions, RunReport } from "./core/types.js";
2
+ export * from "./core/types.js";
3
+ export { analyzeContent } from "./core/analyze.js";
4
+ export { normalizeText } from "./core/normalize.js";
5
+ export { interpretConfigs, defaultEditorconfig, defaultGitattributes } from "./core/configs.js";
6
+ export { readRawConfigs, writeEditorconfig, writeGitattributes } from "./io/configs.js";
7
+ export { audit } from "./core/audit.js";
8
+ /**
9
+ * Run a full appease operation according to `options.mode`:
10
+ * - `audit` : report deviations only (no writes).
11
+ * - `add-config-defaults` : write pure-default configs (no inspection).
12
+ * - `adapt-configs` : write/adapt configs to reflect the repo's reality.
13
+ * - `fix-format` : normalize files (BOM/trailing/newline; EOL via Git).
14
+ *
15
+ * Orchestrates the effects (git ls-files, file I/O) around the pure core.
16
+ */
17
+ export declare function runAppease(options: RunOptions): Promise<RunReport>;