@hardlydifficult/text 1.0.7 → 1.0.9
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/README.md +42 -0
- package/dist/healYaml.d.ts +9 -0
- package/dist/healYaml.d.ts.map +1 -0
- package/dist/healYaml.js +32 -0
- package/dist/healYaml.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -1
- package/dist/index.js.map +1 -1
- package/dist/linker.d.ts +90 -0
- package/dist/linker.d.ts.map +1 -0
- package/dist/linker.js +251 -0
- package/dist/linker.js.map +1 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -149,3 +149,45 @@ formatWithLineNumbers("line 1\nline 2\n...\nline 100", 98);
|
|
|
149
149
|
```
|
|
150
150
|
|
|
151
151
|
This is useful for displaying code snippets, file contents, or log output with line numbers for reference.
|
|
152
|
+
|
|
153
|
+
### `createLinker(rules?)`
|
|
154
|
+
|
|
155
|
+
Create a reusable linker that turns matched text patterns into platform-specific links.
|
|
156
|
+
|
|
157
|
+
Supports:
|
|
158
|
+
|
|
159
|
+
- plain strings
|
|
160
|
+
- idempotent re-runs (won't double-link existing linked text)
|
|
161
|
+
- skipping code spans/backticks and existing links by default
|
|
162
|
+
- deterministic conflict handling (priority, then longest match, then rule order)
|
|
163
|
+
|
|
164
|
+
```typescript
|
|
165
|
+
import { createLinker } from "@hardlydifficult/text";
|
|
166
|
+
|
|
167
|
+
const linker = createLinker()
|
|
168
|
+
.linear("fairmint")
|
|
169
|
+
.githubPr("Fairmint/api")
|
|
170
|
+
.custom(/\bINC-\d+\b/g, ({ match }) => `https://incident.io/${match}`);
|
|
171
|
+
|
|
172
|
+
const slack = linker.linkText("Fix ENG-533 and PR#42", { format: "slack" });
|
|
173
|
+
// "Fix <https://linear.app/fairmint/issue/ENG-533|ENG-533> and <https://github.com/Fairmint/api/pull/42|PR#42>"
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
You can also pass rules up front:
|
|
177
|
+
|
|
178
|
+
```typescript
|
|
179
|
+
const linker = createLinker([
|
|
180
|
+
{
|
|
181
|
+
pattern: /\b([A-Z]{2,6}-\d+)\b/g,
|
|
182
|
+
href: "https://linear.app/fairmint/issue/$1",
|
|
183
|
+
},
|
|
184
|
+
]);
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
Formats:
|
|
188
|
+
|
|
189
|
+
- `slack` → `<url|text>`
|
|
190
|
+
- `markdown` / `discord` → `[text](url)`
|
|
191
|
+
- `plaintext` → raw `url`
|
|
192
|
+
|
|
193
|
+
`linker.apply(text, options)` is an alias of `linker.linkText(text, options)`.
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Heal common YAML formatting issues from LLM output.
|
|
3
|
+
*
|
|
4
|
+
* Fixes applied:
|
|
5
|
+
* - Strips markdown code fences (```yaml ... ```)
|
|
6
|
+
* - Quotes plain scalar values that contain colons (prevents "nested mappings" parse errors)
|
|
7
|
+
*/
|
|
8
|
+
export declare function healYaml(yaml: string): string;
|
|
9
|
+
//# sourceMappingURL=healYaml.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"healYaml.d.ts","sourceRoot":"","sources":["../src/healYaml.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CA0B7C"}
|
package/dist/healYaml.js
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.healYaml = healYaml;
|
|
4
|
+
/**
|
|
5
|
+
* Heal common YAML formatting issues from LLM output.
|
|
6
|
+
*
|
|
7
|
+
* Fixes applied:
|
|
8
|
+
* - Strips markdown code fences (```yaml ... ```)
|
|
9
|
+
* - Quotes plain scalar values that contain colons (prevents "nested mappings" parse errors)
|
|
10
|
+
*/
|
|
11
|
+
function healYaml(yaml) {
|
|
12
|
+
let cleaned = yaml.trim();
|
|
13
|
+
// Strip markdown code fences
|
|
14
|
+
if (cleaned.startsWith("```")) {
|
|
15
|
+
const firstNewline = cleaned.indexOf("\n");
|
|
16
|
+
cleaned = cleaned.slice(firstNewline + 1);
|
|
17
|
+
}
|
|
18
|
+
if (cleaned.endsWith("```")) {
|
|
19
|
+
cleaned = cleaned.slice(0, cleaned.lastIndexOf("```"));
|
|
20
|
+
}
|
|
21
|
+
cleaned = cleaned.trim();
|
|
22
|
+
// Quote plain scalar values that contain `: ` (colon-space).
|
|
23
|
+
// Pattern matches `key: value` where value is a plain scalar containing a colon.
|
|
24
|
+
// Skips values already quoted (`"`), single-quoted (`'`), block scalars (`|`, `>`),
|
|
25
|
+
// or flow collections (`[`, `{`).
|
|
26
|
+
cleaned = cleaned.replace(/^(\s*\w+:[ \t]+)(?!["'|>[{])(.+:.+)$/gm, (_, prefix, value) => {
|
|
27
|
+
const escaped = value.replace(/"/g, '\\"');
|
|
28
|
+
return `${prefix}"${escaped}"`;
|
|
29
|
+
});
|
|
30
|
+
return cleaned;
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=healYaml.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"healYaml.js","sourceRoot":"","sources":["../src/healYaml.ts"],"names":[],"mappings":";;AAOA,4BA0BC;AAjCD;;;;;;GAMG;AACH,SAAgB,QAAQ,CAAC,IAAY;IACnC,IAAI,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;IAE1B,6BAA6B;IAC7B,IAAI,OAAO,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC;QAC9B,MAAM,YAAY,GAAG,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QAC3C,OAAO,GAAG,OAAO,CAAC,KAAK,CAAC,YAAY,GAAG,CAAC,CAAC,CAAC;IAC5C,CAAC;IACD,IAAI,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;QAC5B,OAAO,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,OAAO,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC,CAAC;IACzD,CAAC;IACD,OAAO,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC;IAEzB,6DAA6D;IAC7D,iFAAiF;IACjF,oFAAoF;IACpF,kCAAkC;IAClC,OAAO,GAAG,OAAO,CAAC,OAAO,CACvB,wCAAwC,EACxC,CAAC,CAAC,EAAE,MAAc,EAAE,KAAa,EAAE,EAAE;QACnC,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;QAC3C,OAAO,GAAG,MAAM,IAAI,OAAO,GAAG,CAAC;IACjC,CAAC,CACF,CAAC;IAEF,OAAO,OAAO,CAAC;AACjB,CAAC"}
|
package/dist/index.d.ts
CHANGED
|
@@ -8,4 +8,6 @@ export type { BuildTreeOptions } from "./buildFileTree.js";
|
|
|
8
8
|
export { convertFormat } from "./convertFormat.js";
|
|
9
9
|
export type { TextFormat } from "./convertFormat.js";
|
|
10
10
|
export { formatWithLineNumbers } from "./formatWithLineNumbers.js";
|
|
11
|
+
export { healYaml } from "./healYaml.js";
|
|
12
|
+
export { Linker, createLinker, type LinkRule, type LinkHrefBuilder, type LinkMatchContext, type LinkerApplyOptions, type LinkerPlatform, } from "./linker.js";
|
|
11
13
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,WAAW,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAC9E,OAAO,EAAE,eAAe,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AACrE,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,EAAE,aAAa,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AACvE,YAAY,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAC3D,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,YAAY,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AACrD,OAAO,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,WAAW,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAC9E,OAAO,EAAE,eAAe,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AACrE,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,EAAE,aAAa,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AACvE,YAAY,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAC3D,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,YAAY,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AACrD,OAAO,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAC;AACnE,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EACL,MAAM,EACN,YAAY,EACZ,KAAK,QAAQ,EACb,KAAK,eAAe,EACpB,KAAK,gBAAgB,EACrB,KAAK,kBAAkB,EACvB,KAAK,cAAc,GACpB,MAAM,aAAa,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.formatWithLineNumbers = exports.convertFormat = exports.FILE_TREE_DEFAULTS = exports.buildFileTree = exports.formatDuration = exports.slugify = exports.chunkText = exports.extractPlaceholders = exports.replaceTemplate = exports.formatErrorForLog = exports.formatError = exports.getErrorMessage = void 0;
|
|
3
|
+
exports.createLinker = exports.Linker = exports.healYaml = exports.formatWithLineNumbers = exports.convertFormat = exports.FILE_TREE_DEFAULTS = exports.buildFileTree = exports.formatDuration = exports.slugify = exports.chunkText = exports.extractPlaceholders = exports.replaceTemplate = exports.formatErrorForLog = exports.formatError = exports.getErrorMessage = void 0;
|
|
4
4
|
var errors_js_1 = require("./errors.js");
|
|
5
5
|
Object.defineProperty(exports, "getErrorMessage", { enumerable: true, get: function () { return errors_js_1.getErrorMessage; } });
|
|
6
6
|
Object.defineProperty(exports, "formatError", { enumerable: true, get: function () { return errors_js_1.formatError; } });
|
|
@@ -21,4 +21,9 @@ var convertFormat_js_1 = require("./convertFormat.js");
|
|
|
21
21
|
Object.defineProperty(exports, "convertFormat", { enumerable: true, get: function () { return convertFormat_js_1.convertFormat; } });
|
|
22
22
|
var formatWithLineNumbers_js_1 = require("./formatWithLineNumbers.js");
|
|
23
23
|
Object.defineProperty(exports, "formatWithLineNumbers", { enumerable: true, get: function () { return formatWithLineNumbers_js_1.formatWithLineNumbers; } });
|
|
24
|
+
var healYaml_js_1 = require("./healYaml.js");
|
|
25
|
+
Object.defineProperty(exports, "healYaml", { enumerable: true, get: function () { return healYaml_js_1.healYaml; } });
|
|
26
|
+
var linker_js_1 = require("./linker.js");
|
|
27
|
+
Object.defineProperty(exports, "Linker", { enumerable: true, get: function () { return linker_js_1.Linker; } });
|
|
28
|
+
Object.defineProperty(exports, "createLinker", { enumerable: true, get: function () { return linker_js_1.createLinker; } });
|
|
24
29
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAA,yCAA8E;AAArE,4GAAA,eAAe,OAAA;AAAE,wGAAA,WAAW,OAAA;AAAE,8GAAA,iBAAiB,OAAA;AACxD,6CAAqE;AAA5D,8GAAA,eAAe,OAAA;AAAE,kHAAA,mBAAmB,OAAA;AAC7C,+CAA2C;AAAlC,yGAAA,SAAS,OAAA;AAClB,2CAAuC;AAA9B,qGAAA,OAAO,OAAA;AAChB,yDAAqD;AAA5C,mHAAA,cAAc,OAAA;AACvB,uDAAuE;AAA9D,iHAAA,aAAa,OAAA;AAAE,sHAAA,kBAAkB,OAAA;AAE1C,uDAAmD;AAA1C,iHAAA,aAAa,OAAA;AAEtB,uEAAmE;AAA1D,iIAAA,qBAAqB,OAAA"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAA,yCAA8E;AAArE,4GAAA,eAAe,OAAA;AAAE,wGAAA,WAAW,OAAA;AAAE,8GAAA,iBAAiB,OAAA;AACxD,6CAAqE;AAA5D,8GAAA,eAAe,OAAA;AAAE,kHAAA,mBAAmB,OAAA;AAC7C,+CAA2C;AAAlC,yGAAA,SAAS,OAAA;AAClB,2CAAuC;AAA9B,qGAAA,OAAO,OAAA;AAChB,yDAAqD;AAA5C,mHAAA,cAAc,OAAA;AACvB,uDAAuE;AAA9D,iHAAA,aAAa,OAAA;AAAE,sHAAA,kBAAkB,OAAA;AAE1C,uDAAmD;AAA1C,iHAAA,aAAa,OAAA;AAEtB,uEAAmE;AAA1D,iIAAA,qBAAqB,OAAA;AAC9B,6CAAyC;AAAhC,uGAAA,QAAQ,OAAA;AACjB,yCAQqB;AAPnB,mGAAA,MAAM,OAAA;AACN,yGAAA,YAAY,OAAA"}
|
package/dist/linker.d.ts
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
export type LinkerPlatform = "slack" | "discord" | "markdown" | "plaintext";
|
|
2
|
+
export interface LinkerApplyOptions {
|
|
3
|
+
/**
|
|
4
|
+
* Target output format.
|
|
5
|
+
* Alias: `platform`.
|
|
6
|
+
* Default: "markdown"
|
|
7
|
+
*/
|
|
8
|
+
format?: LinkerPlatform;
|
|
9
|
+
platform?: LinkerPlatform;
|
|
10
|
+
/**
|
|
11
|
+
* When true (default), skips linkification inside inline/fenced code spans.
|
|
12
|
+
*/
|
|
13
|
+
skipCode?: boolean;
|
|
14
|
+
/**
|
|
15
|
+
* When true (default), skips linkification inside existing links.
|
|
16
|
+
*/
|
|
17
|
+
skipExistingLinks?: boolean;
|
|
18
|
+
}
|
|
19
|
+
export interface LinkMatchContext {
|
|
20
|
+
/** Full regex match text. */
|
|
21
|
+
match: string;
|
|
22
|
+
/** Positional capture groups. */
|
|
23
|
+
groups: string[];
|
|
24
|
+
/** Rule name assigned at registration time. */
|
|
25
|
+
ruleName: string;
|
|
26
|
+
/** Match start index in the original input. */
|
|
27
|
+
index: number;
|
|
28
|
+
/** Original input string. */
|
|
29
|
+
input: string;
|
|
30
|
+
}
|
|
31
|
+
export type LinkHrefBuilder = (context: LinkMatchContext) => string;
|
|
32
|
+
export interface LinkRule {
|
|
33
|
+
/** Optional stable name for diagnostics and conflict visibility. */
|
|
34
|
+
name?: string;
|
|
35
|
+
/** Match pattern. Global matching is enforced automatically. */
|
|
36
|
+
pattern: RegExp;
|
|
37
|
+
/**
|
|
38
|
+
* URL template string (supports $0/$& for full match, $1..$N for groups).
|
|
39
|
+
* Convenience alias for `toHref`.
|
|
40
|
+
*/
|
|
41
|
+
href?: string;
|
|
42
|
+
/**
|
|
43
|
+
* Either a URL template string or a callback that builds an href from match context.
|
|
44
|
+
* If both `href` and `toHref` are provided, `toHref` wins.
|
|
45
|
+
*/
|
|
46
|
+
toHref?: string | LinkHrefBuilder;
|
|
47
|
+
/**
|
|
48
|
+
* Higher priority wins for overlapping matches that start at the same index.
|
|
49
|
+
* Default: 0
|
|
50
|
+
*/
|
|
51
|
+
priority?: number;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Stateful linker utility that applies configured rules to text.
|
|
55
|
+
*
|
|
56
|
+
* Behavior highlights:
|
|
57
|
+
* - idempotent by default (skips existing links)
|
|
58
|
+
* - skips code spans by default
|
|
59
|
+
* - deterministic overlap resolution (priority, length, then declaration order)
|
|
60
|
+
*/
|
|
61
|
+
export declare class Linker {
|
|
62
|
+
private readonly rules;
|
|
63
|
+
constructor(initialRules?: LinkRule[]);
|
|
64
|
+
private addRule;
|
|
65
|
+
rule(rule: LinkRule): this;
|
|
66
|
+
rule(name: string, rule: Omit<LinkRule, "name">): this;
|
|
67
|
+
custom(pattern: RegExp, toHref: string | LinkHrefBuilder, options?: {
|
|
68
|
+
name?: string;
|
|
69
|
+
priority?: number;
|
|
70
|
+
}): this;
|
|
71
|
+
linear(workspace: string, options?: {
|
|
72
|
+
name?: string;
|
|
73
|
+
priority?: number;
|
|
74
|
+
}): this;
|
|
75
|
+
githubPr(repository: string, options?: {
|
|
76
|
+
name?: string;
|
|
77
|
+
priority?: number;
|
|
78
|
+
}): this;
|
|
79
|
+
apply(input: string, options?: LinkerApplyOptions): string;
|
|
80
|
+
linkText(input: string, options?: LinkerApplyOptions): string;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Create a linker with optional initial rules.
|
|
84
|
+
*
|
|
85
|
+
* - `href` accepts template substitutions (`$0`/`$&`, `$1..$N`)
|
|
86
|
+
* - `toHref` callback, when provided, takes precedence over `href`
|
|
87
|
+
* - omitted `priority` defaults to `0`
|
|
88
|
+
*/
|
|
89
|
+
export declare function createLinker(initialRules?: LinkRule[]): Linker;
|
|
90
|
+
//# sourceMappingURL=linker.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"linker.d.ts","sourceRoot":"","sources":["../src/linker.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,cAAc,GAAG,OAAO,GAAG,SAAS,GAAG,UAAU,GAAG,WAAW,CAAC;AAE5E,MAAM,WAAW,kBAAkB;IACjC;;;;OAIG;IACH,MAAM,CAAC,EAAE,cAAc,CAAC;IACxB,QAAQ,CAAC,EAAE,cAAc,CAAC;IAC1B;;OAEG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;OAEG;IACH,iBAAiB,CAAC,EAAE,OAAO,CAAC;CAC7B;AAED,MAAM,WAAW,gBAAgB;IAC/B,6BAA6B;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,iCAAiC;IACjC,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,+CAA+C;IAC/C,QAAQ,EAAE,MAAM,CAAC;IACjB,+CAA+C;IAC/C,KAAK,EAAE,MAAM,CAAC;IACd,6BAA6B;IAC7B,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,MAAM,eAAe,GAAG,CAAC,OAAO,EAAE,gBAAgB,KAAK,MAAM,CAAC;AAEpE,MAAM,WAAW,QAAQ;IACvB,oEAAoE;IACpE,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,gEAAgE;IAChE,OAAO,EAAE,MAAM,CAAC;IAChB;;;OAGG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,GAAG,eAAe,CAAC;IAClC;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AA2JD;;;;;;;GAOG;AACH,qBAAa,MAAM;IACjB,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAsB;gBAEhC,YAAY,GAAE,QAAQ,EAAO;IAMzC,OAAO,CAAC,OAAO;IAKf,IAAI,CAAC,IAAI,EAAE,QAAQ,GAAG,IAAI;IAC1B,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,QAAQ,EAAE,MAAM,CAAC,GAAG,IAAI;IActD,MAAM,CACJ,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,MAAM,GAAG,eAAe,EAChC,OAAO,GAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAO,GACjD,IAAI;IASP,MAAM,CACJ,SAAS,EAAE,MAAM,EACjB,OAAO,GAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAO,GACjD,IAAI;IAQP,QAAQ,CACN,UAAU,EAAE,MAAM,EAClB,OAAO,GAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAO,GACjD,IAAI;IASP,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,GAAE,kBAAuB,GAAG,MAAM;IAI9D,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,GAAE,kBAAuB,GAAG,MAAM;CAqFlE;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,YAAY,GAAE,QAAQ,EAAO,GAAG,MAAM,CAElE"}
|
package/dist/linker.js
ADDED
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Linker = void 0;
|
|
4
|
+
exports.createLinker = createLinker;
|
|
5
|
+
function ensureGlobal(pattern) {
|
|
6
|
+
if (pattern.flags.includes("g")) {
|
|
7
|
+
return new RegExp(pattern.source, pattern.flags);
|
|
8
|
+
}
|
|
9
|
+
return new RegExp(pattern.source, `${pattern.flags}g`);
|
|
10
|
+
}
|
|
11
|
+
function templateToHref(template) {
|
|
12
|
+
return ({ match, groups }) => template.replace(/\$\$|\$(\d+|&|0)/g, (token, capture) => {
|
|
13
|
+
if (token === "$$") {
|
|
14
|
+
return "$";
|
|
15
|
+
}
|
|
16
|
+
if (capture === "&" || capture === "0") {
|
|
17
|
+
return match;
|
|
18
|
+
}
|
|
19
|
+
const index = Number(capture);
|
|
20
|
+
if (!Number.isInteger(index) || index < 0) {
|
|
21
|
+
return "";
|
|
22
|
+
}
|
|
23
|
+
return groups[index - 1] ?? "";
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
function compileRule(rule, index) {
|
|
27
|
+
const source = rule.toHref ?? rule.href;
|
|
28
|
+
if (source === undefined) {
|
|
29
|
+
throw new Error(`Invalid linker rule "${rule.name ?? `rule-${String(index + 1)}`}": missing href/toHref`);
|
|
30
|
+
}
|
|
31
|
+
const toHref = typeof source === "string" ? templateToHref(source) : source;
|
|
32
|
+
return {
|
|
33
|
+
name: rule.name ?? `rule-${String(index + 1)}`,
|
|
34
|
+
pattern: ensureGlobal(rule.pattern),
|
|
35
|
+
priority: rule.priority ?? 0,
|
|
36
|
+
toHref,
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
function pushSpans(source, pattern, spans) {
|
|
40
|
+
const matcher = ensureGlobal(pattern);
|
|
41
|
+
let match = matcher.exec(source);
|
|
42
|
+
while (match !== null) {
|
|
43
|
+
if (match[0].length === 0) {
|
|
44
|
+
matcher.lastIndex += 1;
|
|
45
|
+
match = matcher.exec(source);
|
|
46
|
+
continue;
|
|
47
|
+
}
|
|
48
|
+
spans.push({
|
|
49
|
+
start: match.index,
|
|
50
|
+
end: match.index + match[0].length,
|
|
51
|
+
});
|
|
52
|
+
match = matcher.exec(source);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
function normalizeSpans(spans) {
|
|
56
|
+
if (spans.length <= 1) {
|
|
57
|
+
return spans;
|
|
58
|
+
}
|
|
59
|
+
spans.sort((a, b) => a.start - b.start || a.end - b.end);
|
|
60
|
+
const merged = [spans[0]];
|
|
61
|
+
for (let i = 1; i < spans.length; i++) {
|
|
62
|
+
const current = spans[i];
|
|
63
|
+
const previous = merged[merged.length - 1];
|
|
64
|
+
if (current.start <= previous.end) {
|
|
65
|
+
previous.end = Math.max(previous.end, current.end);
|
|
66
|
+
continue;
|
|
67
|
+
}
|
|
68
|
+
merged.push(current);
|
|
69
|
+
}
|
|
70
|
+
return merged;
|
|
71
|
+
}
|
|
72
|
+
function getProtectedSpans(input, options) {
|
|
73
|
+
const spans = [];
|
|
74
|
+
if (options.skipCode) {
|
|
75
|
+
// Fenced code blocks first, then inline spans.
|
|
76
|
+
pushSpans(input, /```[\s\S]*?```/g, spans);
|
|
77
|
+
pushSpans(input, /`[^`\n]+`/g, spans);
|
|
78
|
+
}
|
|
79
|
+
if (options.skipExistingLinks) {
|
|
80
|
+
// Slack and angle-bracket links/mentions.
|
|
81
|
+
pushSpans(input, /<[^>\n]+>/g, spans);
|
|
82
|
+
// Markdown links.
|
|
83
|
+
pushSpans(input, /\[[^\]]+\]\([^)]+\)/g, spans);
|
|
84
|
+
// Plain URLs.
|
|
85
|
+
pushSpans(input, /https?:\/\/[^\s<>()]+/g, spans);
|
|
86
|
+
}
|
|
87
|
+
return normalizeSpans(spans);
|
|
88
|
+
}
|
|
89
|
+
function overlapsProtected(spans, start, end) {
|
|
90
|
+
for (const span of spans) {
|
|
91
|
+
if (span.end <= start) {
|
|
92
|
+
continue;
|
|
93
|
+
}
|
|
94
|
+
if (span.start >= end) {
|
|
95
|
+
return false;
|
|
96
|
+
}
|
|
97
|
+
return true;
|
|
98
|
+
}
|
|
99
|
+
return false;
|
|
100
|
+
}
|
|
101
|
+
function formatLink(href, text, platform) {
|
|
102
|
+
switch (platform) {
|
|
103
|
+
case "slack":
|
|
104
|
+
return `<${href}|${text}>`;
|
|
105
|
+
case "discord":
|
|
106
|
+
case "markdown":
|
|
107
|
+
return `[${text}](${href})`;
|
|
108
|
+
case "plaintext":
|
|
109
|
+
return href;
|
|
110
|
+
default:
|
|
111
|
+
return text;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
function resolvePlatform(options) {
|
|
115
|
+
return options.format ?? options.platform ?? "markdown";
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Stateful linker utility that applies configured rules to text.
|
|
119
|
+
*
|
|
120
|
+
* Behavior highlights:
|
|
121
|
+
* - idempotent by default (skips existing links)
|
|
122
|
+
* - skips code spans by default
|
|
123
|
+
* - deterministic overlap resolution (priority, length, then declaration order)
|
|
124
|
+
*/
|
|
125
|
+
class Linker {
|
|
126
|
+
rules = [];
|
|
127
|
+
constructor(initialRules = []) {
|
|
128
|
+
for (const rule of initialRules) {
|
|
129
|
+
this.addRule(rule);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
addRule(rule) {
|
|
133
|
+
this.rules.push(compileRule(rule, this.rules.length));
|
|
134
|
+
return this;
|
|
135
|
+
}
|
|
136
|
+
rule(ruleOrName, maybeRule) {
|
|
137
|
+
if (typeof ruleOrName === "string") {
|
|
138
|
+
if (maybeRule === undefined) {
|
|
139
|
+
throw new Error(`Missing rule config for "${ruleOrName}"`);
|
|
140
|
+
}
|
|
141
|
+
return this.addRule({ ...maybeRule, name: ruleOrName });
|
|
142
|
+
}
|
|
143
|
+
return this.addRule(ruleOrName);
|
|
144
|
+
}
|
|
145
|
+
custom(pattern, toHref, options = {}) {
|
|
146
|
+
return this.addRule({
|
|
147
|
+
name: options.name,
|
|
148
|
+
pattern,
|
|
149
|
+
toHref,
|
|
150
|
+
priority: options.priority,
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
linear(workspace, options = {}) {
|
|
154
|
+
return this.custom(/\b([A-Z]{2,6}-\d+)\b/g, ({ match }) => `https://linear.app/${workspace}/issue/${match}`, { name: options.name ?? "linear", priority: options.priority });
|
|
155
|
+
}
|
|
156
|
+
githubPr(repository, options = {}) {
|
|
157
|
+
return this.custom(/\bPR#(\d+)\b/g, ({ groups }) => `https://github.com/${repository}/pull/${groups[0] ?? ""}`, { name: options.name ?? "github-pr", priority: options.priority });
|
|
158
|
+
}
|
|
159
|
+
apply(input, options = {}) {
|
|
160
|
+
return this.linkText(input, options);
|
|
161
|
+
}
|
|
162
|
+
linkText(input, options = {}) {
|
|
163
|
+
if (this.rules.length === 0 || input === "") {
|
|
164
|
+
return input;
|
|
165
|
+
}
|
|
166
|
+
const platform = resolvePlatform(options);
|
|
167
|
+
const protectedSpans = getProtectedSpans(input, {
|
|
168
|
+
skipCode: options.skipCode ?? true,
|
|
169
|
+
skipExistingLinks: options.skipExistingLinks ?? true,
|
|
170
|
+
});
|
|
171
|
+
const candidates = [];
|
|
172
|
+
for (let ruleOrder = 0; ruleOrder < this.rules.length; ruleOrder++) {
|
|
173
|
+
const rule = this.rules[ruleOrder];
|
|
174
|
+
const matcher = rule.pattern;
|
|
175
|
+
matcher.lastIndex = 0;
|
|
176
|
+
let match = matcher.exec(input);
|
|
177
|
+
while (match !== null) {
|
|
178
|
+
const matchedText = match[0];
|
|
179
|
+
if (matchedText.length === 0) {
|
|
180
|
+
matcher.lastIndex += 1;
|
|
181
|
+
match = matcher.exec(input);
|
|
182
|
+
continue;
|
|
183
|
+
}
|
|
184
|
+
const start = match.index;
|
|
185
|
+
const end = start + matchedText.length;
|
|
186
|
+
if (!overlapsProtected(protectedSpans, start, end)) {
|
|
187
|
+
candidates.push({
|
|
188
|
+
start,
|
|
189
|
+
end,
|
|
190
|
+
text: matchedText,
|
|
191
|
+
groups: match.slice(1),
|
|
192
|
+
ruleOrder,
|
|
193
|
+
ruleName: rule.name,
|
|
194
|
+
priority: rule.priority,
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
match = matcher.exec(input);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
if (candidates.length === 0) {
|
|
201
|
+
return input;
|
|
202
|
+
}
|
|
203
|
+
candidates.sort((a, b) => a.start - b.start ||
|
|
204
|
+
b.priority - a.priority ||
|
|
205
|
+
b.end - b.start - (a.end - a.start) ||
|
|
206
|
+
b.ruleOrder - a.ruleOrder);
|
|
207
|
+
const selected = [];
|
|
208
|
+
let cursorEnd = -1;
|
|
209
|
+
for (const candidate of candidates) {
|
|
210
|
+
if (candidate.start < cursorEnd) {
|
|
211
|
+
continue;
|
|
212
|
+
}
|
|
213
|
+
selected.push(candidate);
|
|
214
|
+
cursorEnd = candidate.end;
|
|
215
|
+
}
|
|
216
|
+
let output = "";
|
|
217
|
+
let inputCursor = 0;
|
|
218
|
+
for (const candidate of selected) {
|
|
219
|
+
output += input.slice(inputCursor, candidate.start);
|
|
220
|
+
const rule = this.rules[candidate.ruleOrder];
|
|
221
|
+
const href = rule.toHref({
|
|
222
|
+
match: candidate.text,
|
|
223
|
+
groups: candidate.groups,
|
|
224
|
+
ruleName: candidate.ruleName,
|
|
225
|
+
index: candidate.start,
|
|
226
|
+
input,
|
|
227
|
+
});
|
|
228
|
+
if (href === "") {
|
|
229
|
+
output += candidate.text;
|
|
230
|
+
}
|
|
231
|
+
else {
|
|
232
|
+
output += formatLink(href, candidate.text, platform);
|
|
233
|
+
}
|
|
234
|
+
inputCursor = candidate.end;
|
|
235
|
+
}
|
|
236
|
+
output += input.slice(inputCursor);
|
|
237
|
+
return output;
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
exports.Linker = Linker;
|
|
241
|
+
/**
|
|
242
|
+
* Create a linker with optional initial rules.
|
|
243
|
+
*
|
|
244
|
+
* - `href` accepts template substitutions (`$0`/`$&`, `$1..$N`)
|
|
245
|
+
* - `toHref` callback, when provided, takes precedence over `href`
|
|
246
|
+
* - omitted `priority` defaults to `0`
|
|
247
|
+
*/
|
|
248
|
+
function createLinker(initialRules = []) {
|
|
249
|
+
return new Linker(initialRules);
|
|
250
|
+
}
|
|
251
|
+
//# sourceMappingURL=linker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"linker.js","sourceRoot":"","sources":["../src/linker.ts"],"names":[],"mappings":"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"}
|