@patdown/rules 0.3.1 → 0.5.0
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.
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"markdown-patdown-rule-parser.d.ts","sourceRoot":"","sources":["../src/markdown-patdown-rule-parser.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;
|
|
1
|
+
{"version":3,"file":"markdown-patdown-rule-parser.d.ts","sourceRoot":"","sources":["../src/markdown-patdown-rule-parser.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AA4LpD;;;GAGG;AACH,wBAAgB,yBAAyB,CAAC,QAAQ,EAAE,MAAM,GAAG,aAAa,CAAC,WAAW,CAAC,CAiBtF"}
|
|
@@ -12,8 +12,18 @@ function atxHeadingTitle(line) {
|
|
|
12
12
|
const title = match[1]?.trim() ?? '';
|
|
13
13
|
return title.length === 0 ? undefined : title;
|
|
14
14
|
}
|
|
15
|
+
function unwrapGlobToken(token) {
|
|
16
|
+
const trimmed = token.trim();
|
|
17
|
+
if (trimmed.length >= 2 && trimmed.startsWith('`') && trimmed.endsWith('`')) {
|
|
18
|
+
return trimmed.slice(1, -1);
|
|
19
|
+
}
|
|
20
|
+
return trimmed;
|
|
21
|
+
}
|
|
15
22
|
function splitGlobList(raw) {
|
|
16
|
-
return raw
|
|
23
|
+
return raw
|
|
24
|
+
.split(/[,\s]+/u)
|
|
25
|
+
.map(unwrapGlobToken)
|
|
26
|
+
.filter((part) => part.length > 0);
|
|
17
27
|
}
|
|
18
28
|
function globValuesFromLine(line) {
|
|
19
29
|
const match = globLinePattern.exec(line);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"patdown-rule-source.d.ts","sourceRoot":"","sources":["../src/patdown-rule-source.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAQ,MAAM,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAA;AAG/E,OAAO,
|
|
1
|
+
{"version":3,"file":"patdown-rule-source.d.ts","sourceRoot":"","sources":["../src/patdown-rule-source.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAQ,MAAM,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAA;AAG/E,OAAO,EAGN,KAAK,oBAAoB,EACzB,MAAM,mBAAmB,CAAA;AAC1B,OAAO,EAAE,0BAA0B,EAAE,MAAM,4BAA4B,CAAA;;;;AAEvE,2FAA2F;AAC3F,qBAAa,uBAAwB,SAAQ,6BAA4C;IACxF,QAAQ,CAAC,oBAAoB,EAAE,MAAM,CAAA;IACrC,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAA;CAC/B,CAAC;IACD,IAAa,OAAO,IAAI,MAAM,CAE7B;CACD;;;;AAED,oDAAoD;AACpD,qBAAa,sBAAuB,SAAQ,4BAA2C;IACtF,QAAQ,CAAC,oBAAoB,EAAE,MAAM,CAAA;CACrC,CAAC;IACD,IAAa,OAAO,IAAI,MAAM,CAE7B;CACD;;;;AAED;;;GAGG;AACH,qBAAa,sBAAuB,SAAQ,4BAA2C;IACtF,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;CACxB,CAAC;CAAG;;+BASwB,CAC1B,qBAAqB,EAAE,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,KACxC,MAAM,CAAC,MAAM,CACjB,oBAAoB,EAClB,uBAAuB,GACvB,sBAAsB,GACtB,sBAAsB,GACtB,0BAA0B,EAC5B,UAAU,CAAC,UAAU,GAAG,IAAI,CAAC,IAAI,CACjC;;AAhBH;;;GAGG;AACH,qBAAa,iBAAkB,SAAQ,sBAcA;CAAG;AAY1C,uGAAuG;AACvG,wBAAgB,wBAAwB,CACvC,cAAc,EAAE,MAAM,EACtB,QAAQ,EAAE,MAAM,GACd,MAAM,CAAC,MAAM,CACf,MAAM,EACN,uBAAuB,GAAG,sBAAsB,EAChD,UAAU,CAAC,UAAU,GAAG,IAAI,CAAC,IAAI,CACjC,CAsBA;AAED;;;GAGG;AACH,wBAAgB,2BAA2B,CAC1C,qBAAqB,EAAE,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,EAC5C,aAAa,GAAE,MAAoC,GACjD,MAAM,CAAC,MAAM,CACf,MAAM,EACN,uBAAuB,GAAG,sBAAsB,EAChD,UAAU,CAAC,UAAU,GAAG,IAAI,CAAC,IAAI,CACjC,CAkBA;AAsHD,qFAAqF;AACrF,eAAO,MAAM,6BAA6B,8CAExC,CAAA"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Context, Data, Effect, FileSystem, Layer, Option, Path } from 'effect';
|
|
2
2
|
import { parseMarkdownPatdownRules } from '#src/markdown-patdown-rule-parser';
|
|
3
|
-
import { defaultPatdownRulesFileName } from '#src/patdown-rule';
|
|
3
|
+
import { defaultPatdownRulesFileName, } from '#src/patdown-rule';
|
|
4
4
|
import { PatdownYesThresholdInvalid } from '#src/patdown-yes-threshold';
|
|
5
5
|
/** No AGENTS.PATDOWN.md (or override path) existed walking up from the start directory. */
|
|
6
6
|
export class PatdownRulesFileMissing extends Data.TaggedError('PatdownRulesFileMissing') {
|
|
@@ -71,27 +71,76 @@ export function resolvePatdownRulesFilePath(rulesFilePathOverride, rulesFileName
|
|
|
71
71
|
});
|
|
72
72
|
});
|
|
73
73
|
}
|
|
74
|
-
function
|
|
74
|
+
function parseMarkdownPatdownRulesFile(markdown) {
|
|
75
|
+
return Effect.try({
|
|
76
|
+
try: () => parseMarkdownPatdownRules(markdown),
|
|
77
|
+
catch: (cause) => cause instanceof PatdownYesThresholdInvalid
|
|
78
|
+
? cause
|
|
79
|
+
: new PatdownRulesLoadFailed({
|
|
80
|
+
message: cause instanceof Error ? cause.message : String(cause),
|
|
81
|
+
}),
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
function loadMarkdownPatdownRulesFromFile(patdownRulesFilePath) {
|
|
75
85
|
return Effect.gen(function* () {
|
|
76
|
-
const patdownRulesFilePath = yield* resolvePatdownRulesFilePath(rulesFilePathOverride);
|
|
77
86
|
const fileSystem = yield* FileSystem.FileSystem;
|
|
78
87
|
const markdown = yield* fileSystem
|
|
79
88
|
.readFileString(patdownRulesFilePath)
|
|
80
89
|
.pipe(Effect.mapError(() => new PatdownRulesReadFailed({ patdownRulesFilePath })));
|
|
81
|
-
const parsed = yield*
|
|
82
|
-
try: () => parseMarkdownPatdownRules(markdown),
|
|
83
|
-
catch: (cause) => cause instanceof PatdownYesThresholdInvalid
|
|
84
|
-
? cause
|
|
85
|
-
: new PatdownRulesLoadFailed({
|
|
86
|
-
message: cause instanceof Error ? cause.message : String(cause),
|
|
87
|
-
}),
|
|
88
|
-
});
|
|
90
|
+
const parsed = yield* parseMarkdownPatdownRulesFile(markdown);
|
|
89
91
|
return {
|
|
90
92
|
patdownRules: parsed,
|
|
91
93
|
patdownRulesFilePath,
|
|
92
94
|
};
|
|
93
95
|
});
|
|
94
96
|
}
|
|
97
|
+
/** Loads every `*.md` rule file in a directory, skipping README.md. */
|
|
98
|
+
function loadMarkdownPatdownRulesFromDirectory(patdownRulesDirectoryPath) {
|
|
99
|
+
return Effect.gen(function* () {
|
|
100
|
+
const fileSystem = yield* FileSystem.FileSystem;
|
|
101
|
+
const path = yield* Path.Path;
|
|
102
|
+
const entries = yield* fileSystem
|
|
103
|
+
.readDirectory(patdownRulesDirectoryPath)
|
|
104
|
+
.pipe(Effect.mapError(() => new PatdownRulesReadFailed({ patdownRulesFilePath: patdownRulesDirectoryPath })));
|
|
105
|
+
const ruleFiles = entries
|
|
106
|
+
.filter((entry) => entry.toLowerCase().endsWith('.md'))
|
|
107
|
+
.filter((entry) => entry.toLowerCase() !== 'readme.md')
|
|
108
|
+
.toSorted((left, right) => left.localeCompare(right));
|
|
109
|
+
if (ruleFiles.length === 0) {
|
|
110
|
+
return yield* new PatdownRulesLoadFailed({
|
|
111
|
+
message: `patdown: rules directory ${patdownRulesDirectoryPath} has no rule markdown files`,
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
const rules = [];
|
|
115
|
+
for (const ruleFile of ruleFiles) {
|
|
116
|
+
const rulePath = path.join(patdownRulesDirectoryPath, ruleFile);
|
|
117
|
+
const document = yield* loadMarkdownPatdownRulesFromFile(rulePath);
|
|
118
|
+
if (document.patdownRules.length === 0) {
|
|
119
|
+
return yield* new PatdownRulesLoadFailed({
|
|
120
|
+
message: `patdown: rules file ${rulePath} has no # headings`,
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
rules.push(...document.patdownRules);
|
|
124
|
+
}
|
|
125
|
+
return {
|
|
126
|
+
patdownRules: rules,
|
|
127
|
+
patdownRulesFilePath: patdownRulesDirectoryPath,
|
|
128
|
+
};
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
function loadMarkdownPatdownRules(rulesFilePathOverride) {
|
|
132
|
+
return Effect.gen(function* () {
|
|
133
|
+
const patdownRulesFilePath = yield* resolvePatdownRulesFilePath(rulesFilePathOverride);
|
|
134
|
+
const fileSystem = yield* FileSystem.FileSystem;
|
|
135
|
+
const info = yield* fileSystem
|
|
136
|
+
.stat(patdownRulesFilePath)
|
|
137
|
+
.pipe(Effect.mapError(() => new PatdownRulesReadFailed({ patdownRulesFilePath })));
|
|
138
|
+
if (info.type === 'Directory') {
|
|
139
|
+
return yield* loadMarkdownPatdownRulesFromDirectory(patdownRulesFilePath);
|
|
140
|
+
}
|
|
141
|
+
return yield* loadMarkdownPatdownRulesFromFile(patdownRulesFilePath);
|
|
142
|
+
});
|
|
143
|
+
}
|
|
95
144
|
/** Live patdown rule source that reads markdown (`AGENTS.PATDOWN.md` by default). */
|
|
96
145
|
export const MarkdownPatdownRuleSourceLive = Layer.succeed(PatdownRuleSource, {
|
|
97
146
|
loadPatdownRules: loadMarkdownPatdownRules,
|