appease 0.0.1 → 0.0.2
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.
- package/LICENSE +21 -0
- package/README.md +273 -0
- package/dist/cli.d.ts +5 -0
- package/dist/cli.js +56 -0
- package/dist/cli.js.map +1 -0
- package/dist/core/analyze.d.ts +9 -0
- package/dist/core/analyze.js +30 -0
- package/dist/core/analyze.js.map +1 -0
- package/dist/core/audit.d.ts +14 -0
- package/dist/core/audit.js +46 -0
- package/dist/core/audit.js.map +1 -0
- package/dist/core/configs.d.ts +15 -0
- package/dist/core/configs.js +61 -0
- package/dist/core/configs.js.map +1 -0
- package/dist/core/editorconfig.d.ts +30 -0
- package/dist/core/editorconfig.js +99 -0
- package/dist/core/editorconfig.js.map +1 -0
- package/dist/core/gitattributes.d.ts +26 -0
- package/dist/core/gitattributes.js +70 -0
- package/dist/core/gitattributes.js.map +1 -0
- package/dist/core/merge.d.ts +39 -0
- package/dist/core/merge.js +98 -0
- package/dist/core/merge.js.map +1 -0
- package/dist/core/normalize.d.ts +13 -0
- package/dist/core/normalize.js +58 -0
- package/dist/core/normalize.js.map +1 -0
- package/dist/core/types.d.ts +106 -0
- package/dist/core/types.js +4 -0
- package/dist/core/types.js.map +1 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.js +134 -0
- package/dist/index.js.map +1 -0
- package/dist/io/configs.d.ts +16 -0
- package/dist/io/configs.js +47 -0
- package/dist/io/configs.js.map +1 -0
- package/dist/io/files.d.ts +16 -0
- package/dist/io/files.js +43 -0
- package/dist/io/files.js.map +1 -0
- package/package.json +47 -1
package/dist/index.js
ADDED
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
// Public API for appease. Consumable from Node and exercised by the CLI and tests.
|
|
2
|
+
import { analyzeContent } from "./core/analyze.js";
|
|
3
|
+
import { audit } from "./core/audit.js";
|
|
4
|
+
import { defaultEditorconfig, defaultGitattributes, interpretConfigs } from "./core/configs.js";
|
|
5
|
+
import { buildExceptions, mergeEditorconfig, mergeGitattributes } from "./core/merge.js";
|
|
6
|
+
import { normalizeText } from "./core/normalize.js";
|
|
7
|
+
import { readRawConfigs, writeEditorconfig, writeGitattributes } from "./io/configs.js";
|
|
8
|
+
import { listTrackedFiles, readForAudit, writeText } from "./io/files.js";
|
|
9
|
+
export * from "./core/types.js";
|
|
10
|
+
export { analyzeContent } from "./core/analyze.js";
|
|
11
|
+
export { normalizeText } from "./core/normalize.js";
|
|
12
|
+
export { interpretConfigs, defaultEditorconfig, defaultGitattributes } from "./core/configs.js";
|
|
13
|
+
export { readRawConfigs, writeEditorconfig, writeGitattributes } from "./io/configs.js";
|
|
14
|
+
export { audit } from "./core/audit.js";
|
|
15
|
+
/**
|
|
16
|
+
* Run a full appease operation according to `options.mode`:
|
|
17
|
+
* - `audit` : report deviations only (no writes).
|
|
18
|
+
* - `add-config-defaults` : write pure-default configs (no inspection).
|
|
19
|
+
* - `adapt-configs` : write/adapt configs to reflect the repo's reality.
|
|
20
|
+
* - `fix-format` : normalize files (BOM/trailing/newline; EOL via Git).
|
|
21
|
+
*
|
|
22
|
+
* Orchestrates the effects (git ls-files, file I/O) around the pure core.
|
|
23
|
+
*/
|
|
24
|
+
export async function runAppease(options) {
|
|
25
|
+
if (options.mode === "audit")
|
|
26
|
+
return runAudit(options);
|
|
27
|
+
if (options.mode === "add-config-defaults")
|
|
28
|
+
return runAddConfigDefaults(options);
|
|
29
|
+
if (options.mode === "adapt-configs")
|
|
30
|
+
return runAdaptConfigs(options);
|
|
31
|
+
return runFixFormat(options);
|
|
32
|
+
}
|
|
33
|
+
/** This machine's native line ending — how `text=auto` resolves in the working tree. */
|
|
34
|
+
function nativeEol() {
|
|
35
|
+
return process.platform === "win32" ? "crlf" : "lf";
|
|
36
|
+
}
|
|
37
|
+
/** Re-end a generated (canonical LF) config in the OS-native EOL, so the written file is native. */
|
|
38
|
+
function toNativeEol(content) {
|
|
39
|
+
return normalizeText(content, { bom: "keep", eol: nativeEol(), trailing: "keep", finalNewline: "keep" });
|
|
40
|
+
}
|
|
41
|
+
/** Write the pure-default configs, creating only the ones that do not exist yet (never overwrites). */
|
|
42
|
+
async function runAddConfigDefaults(options) {
|
|
43
|
+
const raw = await readRawConfigs(options.cwd);
|
|
44
|
+
const created = [];
|
|
45
|
+
const unchanged = [];
|
|
46
|
+
if (raw.editorconfig === null)
|
|
47
|
+
created.push((await writeEditorconfig(options.cwd, toNativeEol(defaultEditorconfig()), options.dryRun)).path);
|
|
48
|
+
else
|
|
49
|
+
unchanged.push(".editorconfig");
|
|
50
|
+
if (raw.gitattributes === null)
|
|
51
|
+
created.push((await writeGitattributes(options.cwd, toNativeEol(defaultGitattributes()), options.dryRun)).path);
|
|
52
|
+
else
|
|
53
|
+
unchanged.push(".gitattributes");
|
|
54
|
+
return { mode: "add-config-defaults", dryRun: options.dryRun, created, modified: [], unchanged };
|
|
55
|
+
}
|
|
56
|
+
/** Discover tracked files, skip binaries/non-UTF-8, and analyze the rest. */
|
|
57
|
+
async function collectReports(cwd, config) {
|
|
58
|
+
const reports = [];
|
|
59
|
+
const notAnalyzed = [];
|
|
60
|
+
for (const path of await listTrackedFiles(cwd)) {
|
|
61
|
+
const read = await readForAudit(cwd, path, config.resolve(path).eol === "binary");
|
|
62
|
+
if ("skip" in read)
|
|
63
|
+
notAnalyzed.push({ path, reason: read.skip });
|
|
64
|
+
else
|
|
65
|
+
reports.push({ path, report: analyzeContent(read.content) });
|
|
66
|
+
}
|
|
67
|
+
return { reports, notAnalyzed };
|
|
68
|
+
}
|
|
69
|
+
async function runAudit(options) {
|
|
70
|
+
const config = interpretConfigs(await readRawConfigs(options.cwd));
|
|
71
|
+
const { reports, notAnalyzed } = await collectReports(options.cwd, config);
|
|
72
|
+
return { mode: "audit", dryRun: options.dryRun, created: [], modified: [], unchanged: [], audit: { findings: audit(reports, config, nativeEol()), notAnalyzed } };
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Establish the default configs as a baseline (in memory if absent), audit the repo
|
|
76
|
+
* against it, and merge an exception for every deviation so a later `--fix-format`
|
|
77
|
+
* changes nothing. Existing config content is preserved; new exceptions are appended.
|
|
78
|
+
*/
|
|
79
|
+
async function runAdaptConfigs(options) {
|
|
80
|
+
const raw = await readRawConfigs(options.cwd);
|
|
81
|
+
const editorconfigBase = raw.editorconfig ?? toNativeEol(defaultEditorconfig());
|
|
82
|
+
const gitattributesBase = raw.gitattributes ?? toNativeEol(defaultGitattributes());
|
|
83
|
+
const config = interpretConfigs({ editorconfig: editorconfigBase, gitattributes: gitattributesBase, vscodeSettings: raw.vscodeSettings });
|
|
84
|
+
const { reports } = await collectReports(options.cwd, config);
|
|
85
|
+
const deviationsByPath = new Map(audit(reports, config, nativeEol()).map((finding) => [finding.path, finding.deviations]));
|
|
86
|
+
const audited = reports.flatMap((report) => {
|
|
87
|
+
const deviations = deviationsByPath.get(report.path);
|
|
88
|
+
return deviations !== undefined ? [{ path: report.path, report: report.report, deviations }] : [];
|
|
89
|
+
});
|
|
90
|
+
const exceptions = buildExceptions(audited);
|
|
91
|
+
const results = [
|
|
92
|
+
await writeEditorconfig(options.cwd, mergeEditorconfig(editorconfigBase, exceptions.editorconfig), options.dryRun),
|
|
93
|
+
await writeGitattributes(options.cwd, mergeGitattributes(gitattributesBase, exceptions.gitattributes), options.dryRun),
|
|
94
|
+
];
|
|
95
|
+
const created = results.filter((r) => r.created).map((r) => r.path);
|
|
96
|
+
const modified = results.filter((r) => !r.created && r.modified).map((r) => r.path);
|
|
97
|
+
const unchanged = results.filter((r) => !r.created && !r.modified).map((r) => r.path);
|
|
98
|
+
return { mode: "adapt-configs", dryRun: options.dryRun, created, modified, unchanged };
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Normalize each tracked file's content (BOM / EOL / trailing / final newline) per its resolved
|
|
102
|
+
* config, skipping axes the config could not resolve (case 2). EOL is written directly into the
|
|
103
|
+
* working tree (`eol=auto` resolves to this machine's native ending), matching what `--audit` checks.
|
|
104
|
+
*/
|
|
105
|
+
async function runFixFormat(options) {
|
|
106
|
+
const config = interpretConfigs(await readRawConfigs(options.cwd));
|
|
107
|
+
const native = nativeEol();
|
|
108
|
+
const modified = [];
|
|
109
|
+
for (const path of await listTrackedFiles(options.cwd)) {
|
|
110
|
+
const resolved = config.resolve(path);
|
|
111
|
+
const read = await readForAudit(options.cwd, path, resolved.eol === "binary");
|
|
112
|
+
if ("skip" in read)
|
|
113
|
+
continue;
|
|
114
|
+
const normalized = normalizeText(read.content, fixOptions(resolved, native));
|
|
115
|
+
if (normalized !== read.content) {
|
|
116
|
+
if (!options.dryRun)
|
|
117
|
+
await writeText(options.cwd, path, normalized);
|
|
118
|
+
modified.push(path);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
return { mode: "fix-format", dryRun: options.dryRun, created: [], modified, unchanged: [] };
|
|
122
|
+
}
|
|
123
|
+
/** Map a resolved config to normalizer options: skip case-2 axes; resolve `eol=auto` to native. */
|
|
124
|
+
function fixOptions(resolved, native) {
|
|
125
|
+
const enforce = (axis) => !resolved.unresolved.includes(axis);
|
|
126
|
+
const eol = !enforce("eol") || resolved.eol === "binary" ? "keep" : resolved.eol === "auto" ? native : resolved.eol;
|
|
127
|
+
return {
|
|
128
|
+
bom: enforce("bom") ? resolved.bom : "keep",
|
|
129
|
+
eol,
|
|
130
|
+
trailing: enforce("trailing") ? resolved.trailing : "keep",
|
|
131
|
+
finalNewline: enforce("finalNewline") ? resolved.finalNewline : "keep",
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { RawConfigs } from "../core/types.js";
|
|
2
|
+
/** Outcome of a config write: whether the file was created, changed, or already up to date. */
|
|
3
|
+
export interface WriteResult {
|
|
4
|
+
path: string;
|
|
5
|
+
created: boolean;
|
|
6
|
+
modified: boolean;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Read the three config sources from `cwd` into raw contents. Thin I/O; the
|
|
10
|
+
* interpretation lives in the pure core (`interpretConfigs`).
|
|
11
|
+
*/
|
|
12
|
+
export declare function readRawConfigs(cwd: string): Promise<RawConfigs>;
|
|
13
|
+
/** Write `.editorconfig` (created or updated only if it differs). */
|
|
14
|
+
export declare function writeEditorconfig(cwd: string, content: string, dryRun: boolean): Promise<WriteResult>;
|
|
15
|
+
/** Write `.gitattributes` (created or updated only if it differs). */
|
|
16
|
+
export declare function writeGitattributes(cwd: string, content: string, dryRun: boolean): Promise<WriteResult>;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { readFile, writeFile } from "node:fs/promises";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
/** Read a UTF-8 file, returning its contents or `null` when it does not exist. */
|
|
4
|
+
async function readOrNull(path) {
|
|
5
|
+
try {
|
|
6
|
+
return await readFile(path, "utf8");
|
|
7
|
+
}
|
|
8
|
+
catch (err) {
|
|
9
|
+
if (err.code === "ENOENT")
|
|
10
|
+
return null;
|
|
11
|
+
throw err; // any other I/O error is real: do not swallow it
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Read the three config sources from `cwd` into raw contents. Thin I/O; the
|
|
16
|
+
* interpretation lives in the pure core (`interpretConfigs`).
|
|
17
|
+
*/
|
|
18
|
+
export async function readRawConfigs(cwd) {
|
|
19
|
+
const [editorconfig, gitattributes, vscodeSettings] = await Promise.all([
|
|
20
|
+
readOrNull(join(cwd, ".editorconfig")),
|
|
21
|
+
readOrNull(join(cwd, ".gitattributes")),
|
|
22
|
+
readOrNull(join(cwd, ".vscode", "settings.json")),
|
|
23
|
+
]);
|
|
24
|
+
return { editorconfig, gitattributes, vscodeSettings };
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Write `content` to a config file under `cwd`, only when it differs (idempotent).
|
|
28
|
+
* The text to write is produced by the pure core (defaults or merge); this is
|
|
29
|
+
* just the I/O. Under `dryRun` the result reflects what would change, untouched.
|
|
30
|
+
*/
|
|
31
|
+
async function writeConfig(cwd, name, content, dryRun) {
|
|
32
|
+
const existing = await readOrNull(join(cwd, name));
|
|
33
|
+
if (existing === content)
|
|
34
|
+
return { path: name, created: false, modified: false };
|
|
35
|
+
if (!dryRun)
|
|
36
|
+
await writeFile(join(cwd, name), content, "utf8");
|
|
37
|
+
return { path: name, created: existing === null, modified: existing !== null };
|
|
38
|
+
}
|
|
39
|
+
/** Write `.editorconfig` (created or updated only if it differs). */
|
|
40
|
+
export function writeEditorconfig(cwd, content, dryRun) {
|
|
41
|
+
return writeConfig(cwd, ".editorconfig", content, dryRun);
|
|
42
|
+
}
|
|
43
|
+
/** Write `.gitattributes` (created or updated only if it differs). */
|
|
44
|
+
export function writeGitattributes(cwd, content, dryRun) {
|
|
45
|
+
return writeConfig(cwd, ".gitattributes", content, dryRun);
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=configs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"configs.js","sourceRoot":"","sources":["../../src/io/configs.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AACvD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAUjC,kFAAkF;AAClF,KAAK,UAAU,UAAU,CAAC,IAAY;IACpC,IAAI,CAAC;QACH,OAAO,MAAM,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IACtC,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAK,GAA6B,CAAC,IAAI,KAAK,QAAQ;YAAE,OAAO,IAAI,CAAC;QAClE,MAAM,GAAG,CAAC,CAAC,iDAAiD;IAC9D,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,GAAW;IAC9C,MAAM,CAAC,YAAY,EAAE,aAAa,EAAE,cAAc,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;QACtE,UAAU,CAAC,IAAI,CAAC,GAAG,EAAE,eAAe,CAAC,CAAC;QACtC,UAAU,CAAC,IAAI,CAAC,GAAG,EAAE,gBAAgB,CAAC,CAAC;QACvC,UAAU,CAAC,IAAI,CAAC,GAAG,EAAE,SAAS,EAAE,eAAe,CAAC,CAAC;KAClD,CAAC,CAAC;IACH,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,cAAc,EAAE,CAAC;AACzD,CAAC;AAED;;;;GAIG;AACH,KAAK,UAAU,WAAW,CAAC,GAAW,EAAE,IAAY,EAAE,OAAe,EAAE,MAAe;IACpF,MAAM,QAAQ,GAAG,MAAM,UAAU,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC,CAAC;IACnD,IAAI,QAAQ,KAAK,OAAO;QAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC;IACjF,IAAI,CAAC,MAAM;QAAE,MAAM,SAAS,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC;IAC/D,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,QAAQ,KAAK,IAAI,EAAE,QAAQ,EAAE,QAAQ,KAAK,IAAI,EAAE,CAAC;AACjF,CAAC;AAED,qEAAqE;AACrE,MAAM,UAAU,iBAAiB,CAAC,GAAW,EAAE,OAAe,EAAE,MAAe;IAC7E,OAAO,WAAW,CAAC,GAAG,EAAE,eAAe,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC;AAC5D,CAAC;AAED,sEAAsE;AACtE,MAAM,UAAU,kBAAkB,CAAC,GAAW,EAAE,OAAe,EAAE,MAAe;IAC9E,OAAO,WAAW,CAAC,GAAG,EAAE,gBAAgB,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC;AAC7D,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { AuditResult } from "../core/types.js";
|
|
2
|
+
type SkipReason = AuditResult["notAnalyzed"][number]["reason"];
|
|
3
|
+
/** List repo-tracked files (repo-relative, forward-slash paths). */
|
|
4
|
+
export declare function listTrackedFiles(cwd: string): Promise<string[]>;
|
|
5
|
+
/**
|
|
6
|
+
* Read a file for auditing: skip binaries (declared `-text`, known extension, or
|
|
7
|
+
* NUL content) and non-UTF-8 files; otherwise decode keeping any leading BOM.
|
|
8
|
+
*/
|
|
9
|
+
export declare function readForAudit(cwd: string, path: string, isGitBinary: boolean): Promise<{
|
|
10
|
+
content: string;
|
|
11
|
+
} | {
|
|
12
|
+
skip: SkipReason;
|
|
13
|
+
}>;
|
|
14
|
+
/** Write UTF-8 `content` to a tracked file (a BOM in the string is encoded as bytes). */
|
|
15
|
+
export declare function writeText(cwd: string, path: string, content: string): Promise<void>;
|
|
16
|
+
export {};
|
package/dist/io/files.js
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { execFile } from "node:child_process";
|
|
2
|
+
import { readFile, writeFile } from "node:fs/promises";
|
|
3
|
+
import { extname, join } from "node:path";
|
|
4
|
+
import { promisify } from "node:util";
|
|
5
|
+
const execFileAsync = promisify(execFile);
|
|
6
|
+
/** Known-binary file extensions; the embedded list (a `.appease` override may come later). */
|
|
7
|
+
const BINARY_EXTENSIONS = new Set([
|
|
8
|
+
".png", ".jpg", ".jpeg", ".gif", ".webp", ".ico", ".bmp", ".tif", ".tiff",
|
|
9
|
+
".pdf", ".zip", ".gz", ".tgz", ".bz2", ".xz", ".7z", ".rar", ".tar",
|
|
10
|
+
".exe", ".dll", ".so", ".dylib", ".bin", ".o", ".a", ".class", ".jar", ".wasm",
|
|
11
|
+
".woff", ".woff2", ".ttf", ".otf", ".eot",
|
|
12
|
+
".mp3", ".mp4", ".m4a", ".avi", ".mov", ".mkv", ".wav", ".flac", ".ogg", ".webm",
|
|
13
|
+
]);
|
|
14
|
+
/** List repo-tracked files (repo-relative, forward-slash paths). */
|
|
15
|
+
export async function listTrackedFiles(cwd) {
|
|
16
|
+
const { stdout } = await execFileAsync("git", ["ls-files", "-z"], { cwd, maxBuffer: 64 * 1024 * 1024 });
|
|
17
|
+
return stdout.split("\0").filter((path) => path !== "");
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Read a file for auditing: skip binaries (declared `-text`, known extension, or
|
|
21
|
+
* NUL content) and non-UTF-8 files; otherwise decode keeping any leading BOM.
|
|
22
|
+
*/
|
|
23
|
+
export async function readForAudit(cwd, path, isGitBinary) {
|
|
24
|
+
if (isGitBinary)
|
|
25
|
+
return { skip: "gitattributes-notext" };
|
|
26
|
+
if (BINARY_EXTENSIONS.has(extname(path).toLowerCase()))
|
|
27
|
+
return { skip: "binary-extension" };
|
|
28
|
+
const bytes = await readFile(join(cwd, path));
|
|
29
|
+
if (bytes.includes(0))
|
|
30
|
+
return { skip: "binary-content" };
|
|
31
|
+
try {
|
|
32
|
+
// ignoreBOM keeps the BOM in the decoded string, as analyzeContent expects.
|
|
33
|
+
return { content: new TextDecoder("utf-8", { fatal: true, ignoreBOM: true }).decode(bytes) };
|
|
34
|
+
}
|
|
35
|
+
catch {
|
|
36
|
+
return { skip: "non-utf8" };
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
/** Write UTF-8 `content` to a tracked file (a BOM in the string is encoded as bytes). */
|
|
40
|
+
export async function writeText(cwd, path, content) {
|
|
41
|
+
await writeFile(join(cwd, path), content, "utf8");
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=files.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"files.js","sourceRoot":"","sources":["../../src/io/files.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AACvD,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAGtC,MAAM,aAAa,GAAG,SAAS,CAAC,QAAQ,CAAC,CAAC;AAI1C,8FAA8F;AAC9F,MAAM,iBAAiB,GAAG,IAAI,GAAG,CAAC;IAChC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO;IACzE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM;IACnE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO;IAC9E,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;IACzC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO;CACjF,CAAC,CAAC;AAEH,oEAAoE;AACpE,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,GAAW;IAChD,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,aAAa,CAAC,KAAK,EAAE,CAAC,UAAU,EAAE,IAAI,CAAC,EAAE,EAAE,GAAG,EAAE,SAAS,EAAE,EAAE,GAAG,IAAI,GAAG,IAAI,EAAE,CAAC,CAAC;IACxG,OAAO,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,KAAK,EAAE,CAAC,CAAC;AAC1D,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,GAAW,EAAE,IAAY,EAAE,WAAoB;IAChF,IAAI,WAAW;QAAE,OAAO,EAAE,IAAI,EAAE,sBAAsB,EAAE,CAAC;IACzD,IAAI,iBAAiB,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,WAAW,EAAE,CAAC;QAAE,OAAO,EAAE,IAAI,EAAE,kBAAkB,EAAE,CAAC;IAC5F,MAAM,KAAK,GAAG,MAAM,QAAQ,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC,CAAC;IAC9C,IAAI,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC;QAAE,OAAO,EAAE,IAAI,EAAE,gBAAgB,EAAE,CAAC;IACzD,IAAI,CAAC;QACH,4EAA4E;QAC5E,OAAO,EAAE,OAAO,EAAE,IAAI,WAAW,CAAC,OAAO,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;IAC/F,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,CAAC;IAC9B,CAAC;AACH,CAAC;AAED,yFAAyF;AACzF,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,GAAW,EAAE,IAAY,EAAE,OAAe;IACxE,MAAM,SAAS,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC;AACpD,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,9 +1,55 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "appease",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.2",
|
|
4
4
|
"description": "Make pease in this app.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Emilio Platzer",
|
|
7
|
+
"repository": "emilioplatzer/appease",
|
|
8
|
+
"type": "module",
|
|
9
|
+
"main": "dist/index.js",
|
|
10
|
+
"types": "dist/index.d.ts",
|
|
11
|
+
"bin": {
|
|
12
|
+
"appease": "dist/cli.js"
|
|
13
|
+
},
|
|
14
|
+
"exports": {
|
|
15
|
+
".": {
|
|
16
|
+
"types": "./dist/index.d.ts",
|
|
17
|
+
"default": "./dist/index.js"
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
"files": [
|
|
21
|
+
"dist"
|
|
22
|
+
],
|
|
7
23
|
"scripts": {
|
|
24
|
+
"build": "tsc",
|
|
25
|
+
"build:test": "tsc -p test/tsconfig.json",
|
|
26
|
+
"pretest": "npm run build:test",
|
|
27
|
+
"test": "mocha",
|
|
28
|
+
"precoverage": "npm run build:test",
|
|
29
|
+
"coverage": "c8 mocha",
|
|
30
|
+
"prepublishOnly": "npm run build"
|
|
31
|
+
},
|
|
32
|
+
"overrides": {
|
|
33
|
+
"diff": ">=8.0.2",
|
|
34
|
+
"serialize-javascript": ">=7.0.0",
|
|
35
|
+
"uuid": ">=14.0.0"
|
|
36
|
+
},
|
|
37
|
+
"dependencies": {
|
|
38
|
+
"picomatch": "^4.0.4"
|
|
39
|
+
},
|
|
40
|
+
"devDependencies": {
|
|
41
|
+
"@types/mocha": "^10.0.10",
|
|
42
|
+
"@types/node": "^25.9.1",
|
|
43
|
+
"@types/picomatch": "^4.0.3",
|
|
44
|
+
"c8": "^11.0.0",
|
|
45
|
+
"mocha": "^11.7.6",
|
|
46
|
+
"qa-control": "^0.6.12",
|
|
47
|
+
"typescript": "^6.0.3"
|
|
48
|
+
},
|
|
49
|
+
"qa-control": {
|
|
50
|
+
"profile": "minimum",
|
|
51
|
+
"run-in": "server",
|
|
52
|
+
"type": "cmd-tool",
|
|
53
|
+
"gha": true
|
|
8
54
|
}
|
|
9
55
|
}
|