@vibe-agent-toolkit/resources 0.1.37 → 0.1.39-rc.1
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 +35 -26
- package/dist/ajv-factory.d.ts +33 -0
- package/dist/ajv-factory.d.ts.map +1 -0
- package/dist/ajv-factory.js +51 -0
- package/dist/ajv-factory.js.map +1 -0
- package/dist/config-parser.d.ts +0 -18
- package/dist/config-parser.d.ts.map +1 -1
- package/dist/config-parser.js +5 -46
- package/dist/config-parser.js.map +1 -1
- package/dist/frontmatter-editor.d.ts +45 -0
- package/dist/frontmatter-editor.d.ts.map +1 -0
- package/dist/frontmatter-editor.js +161 -0
- package/dist/frontmatter-editor.js.map +1 -0
- package/dist/frontmatter-link-validator.d.ts +5 -5
- package/dist/frontmatter-link-validator.d.ts.map +1 -1
- package/dist/frontmatter-link-validator.js +25 -24
- package/dist/frontmatter-link-validator.js.map +1 -1
- package/dist/frontmatter-validator.d.ts +3 -2
- package/dist/frontmatter-validator.d.ts.map +1 -1
- package/dist/frontmatter-validator.js +19 -20
- package/dist/frontmatter-validator.js.map +1 -1
- package/dist/index.d.ts +5 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +9 -1
- package/dist/index.js.map +1 -1
- package/dist/json-pointer-path.d.ts +13 -0
- package/dist/json-pointer-path.d.ts.map +1 -0
- package/dist/json-pointer-path.js +30 -0
- package/dist/json-pointer-path.js.map +1 -0
- package/dist/link-parser.js +14 -16
- package/dist/link-parser.js.map +1 -1
- package/dist/link-validator.d.ts +23 -1
- package/dist/link-validator.d.ts.map +1 -1
- package/dist/link-validator.js +107 -104
- package/dist/link-validator.js.map +1 -1
- package/dist/multi-schema-validator.d.ts.map +1 -1
- package/dist/multi-schema-validator.js +6 -8
- package/dist/multi-schema-validator.js.map +1 -1
- package/dist/resource-registry.d.ts +10 -2
- package/dist/resource-registry.d.ts.map +1 -1
- package/dist/resource-registry.js +25 -32
- package/dist/resource-registry.js.map +1 -1
- package/dist/rewriter-helpers.d.ts +49 -0
- package/dist/rewriter-helpers.d.ts.map +1 -0
- package/dist/rewriter-helpers.js +142 -0
- package/dist/rewriter-helpers.js.map +1 -0
- package/dist/schemas/project-config.d.ts +219 -171
- package/dist/schemas/project-config.d.ts.map +1 -1
- package/dist/schemas/project-config.js +2 -0
- package/dist/schemas/project-config.js.map +1 -1
- package/dist/schemas/validation-result.d.ts +36 -57
- package/dist/schemas/validation-result.d.ts.map +1 -1
- package/dist/schemas/validation-result.js +5 -27
- package/dist/schemas/validation-result.js.map +1 -1
- package/dist/types/resource-parser.d.ts.map +1 -1
- package/dist/types/resource-parser.js +2 -3
- package/dist/types/resource-parser.js.map +1 -1
- package/dist/types/resources.d.ts +1 -1
- package/dist/types/resources.d.ts.map +1 -1
- package/dist/types/resources.js.map +1 -1
- package/dist/types.d.ts +1 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +1 -1
- package/dist/types.js.map +1 -1
- package/dist/utils.d.ts +50 -11
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +53 -13
- package/dist/utils.js.map +1 -1
- package/package.json +5 -5
- package/src/ajv-factory.ts +56 -0
- package/src/config-parser.ts +5 -51
- package/src/frontmatter-editor.ts +214 -0
- package/src/frontmatter-link-validator.ts +23 -25
- package/src/frontmatter-validator.ts +29 -22
- package/src/index.ts +21 -2
- package/src/json-pointer-path.ts +29 -0
- package/src/link-parser.ts +27 -20
- package/src/link-validator.ts +194 -119
- package/src/multi-schema-validator.ts +10 -8
- package/src/resource-registry.ts +48 -33
- package/src/rewriter-helpers.ts +166 -0
- package/src/schemas/project-config.ts +2 -0
- package/src/schemas/validation-result.ts +5 -29
- package/src/types/resource-parser.ts +2 -3
- package/src/types/resources.ts +2 -1
- package/src/types.ts +0 -1
- package/src/utils.ts +72 -14
package/README.md
CHANGED
|
@@ -47,7 +47,7 @@ console.log(`Errors: ${result.errorCount}, Warnings: ${result.warningCount}`);
|
|
|
47
47
|
// Show any issues
|
|
48
48
|
for (const issue of result.issues) {
|
|
49
49
|
console.log(`${issue.severity.toUpperCase()}: ${issue.message}`);
|
|
50
|
-
if (issue.line) console.log(` at ${issue.
|
|
50
|
+
if (issue.line) console.log(` at ${issue.location}:${issue.line}`);
|
|
51
51
|
}
|
|
52
52
|
```
|
|
53
53
|
|
|
@@ -546,27 +546,35 @@ interface ValidationResult {
|
|
|
546
546
|
|
|
547
547
|
A single validation issue found during link validation.
|
|
548
548
|
|
|
549
|
+
`ValidationIssue` is the unified issue shape every VAT validator emits (defined
|
|
550
|
+
in `@vibe-agent-toolkit/agent-schema`). Each issue carries a registry `code`
|
|
551
|
+
(see [Validation Codes](../../docs/validation-codes.md)) and a resolved
|
|
552
|
+
`severity`.
|
|
553
|
+
|
|
549
554
|
```typescript
|
|
550
555
|
interface ValidationIssue {
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
line?: number; // Line number where the issue occurs
|
|
554
|
-
type: string; // Issue type identifier (e.g., 'broken_file', 'broken_anchor')
|
|
555
|
-
link: string; // The problematic link
|
|
556
|
+
code: string; // Registry code, e.g. 'LINK_BROKEN_FILE', 'EXTERNAL_URL_DEAD'
|
|
557
|
+
severity: SeverityLevel; // Resolved severity (after config overrides)
|
|
556
558
|
message: string; // Human-readable description
|
|
559
|
+
location?: string; // Project-relative path of the file containing the issue
|
|
560
|
+
line?: number; // Line number where the issue occurs
|
|
561
|
+
link?: string; // The problematic link (when applicable)
|
|
562
|
+
fix?: string; // Fix hint from the code registry
|
|
563
|
+
reference?: string; // Anchor into docs/validation-codes.md
|
|
557
564
|
suggestion?: string; // Optional suggestion for fixing
|
|
558
565
|
}
|
|
559
566
|
```
|
|
560
567
|
|
|
561
|
-
###
|
|
568
|
+
### SeverityLevel
|
|
562
569
|
|
|
563
570
|
```typescript
|
|
564
|
-
type
|
|
571
|
+
type SeverityLevel = 'error' | 'warning' | 'info' | 'ignore';
|
|
565
572
|
```
|
|
566
573
|
|
|
567
574
|
- `error` - Critical issue that should block usage (e.g., broken file link)
|
|
568
|
-
- `warning` - Non-critical issue that should be addressed (e.g.,
|
|
569
|
-
- `info` - Informational message
|
|
575
|
+
- `warning` - Non-critical issue that should be addressed (e.g., dead external URL)
|
|
576
|
+
- `info` - Informational message
|
|
577
|
+
- `ignore` - Suppressed; the issue is not emitted (set via `validation.severity` config)
|
|
570
578
|
|
|
571
579
|
## Frontmatter Support
|
|
572
580
|
|
|
@@ -721,19 +729,19 @@ vat resources validate docs/ --frontmatter-schema schema.json
|
|
|
721
729
|
|
|
722
730
|
### Validation Result
|
|
723
731
|
|
|
724
|
-
Frontmatter
|
|
732
|
+
Frontmatter findings are emitted into the same unified `result.issues` array as
|
|
733
|
+
link findings — each carries a `FRONTMATTER_*` registry code (e.g.
|
|
734
|
+
`FRONTMATTER_MISSING`, `FRONTMATTER_SCHEMA_ERROR`, `FRONTMATTER_INVALID_YAML`)
|
|
735
|
+
and a resolved `severity`. There is no separate `frontmatterValidation` field.
|
|
725
736
|
|
|
726
737
|
```typescript
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
field?: string;
|
|
735
|
-
}>;
|
|
736
|
-
};
|
|
738
|
+
const result = await registry.validate();
|
|
739
|
+
|
|
740
|
+
const frontmatterIssues = result.issues.filter((i) =>
|
|
741
|
+
i.code.startsWith('FRONTMATTER_'),
|
|
742
|
+
);
|
|
743
|
+
for (const issue of frontmatterIssues) {
|
|
744
|
+
console.log(`[${issue.severity}] ${issue.code} at ${issue.location}: ${issue.message}`);
|
|
737
745
|
}
|
|
738
746
|
```
|
|
739
747
|
|
|
@@ -889,9 +897,10 @@ const warnings = result.issues.filter(i => i.severity === 'warning');
|
|
|
889
897
|
// Group by resource
|
|
890
898
|
const issuesByResource = new Map<string, ValidationIssue[]>();
|
|
891
899
|
for (const issue of result.issues) {
|
|
892
|
-
const
|
|
900
|
+
const key = issue.location ?? '(unknown)';
|
|
901
|
+
const issues = issuesByResource.get(key) ?? [];
|
|
893
902
|
issues.push(issue);
|
|
894
|
-
issuesByResource.set(
|
|
903
|
+
issuesByResource.set(key, issues);
|
|
895
904
|
}
|
|
896
905
|
|
|
897
906
|
// Show summary
|
|
@@ -926,7 +935,7 @@ async function validateDocs() {
|
|
|
926
935
|
console.error(`\nValidation failed with ${result.errorCount} errors\n`);
|
|
927
936
|
|
|
928
937
|
for (const issue of result.issues.filter(i => i.severity === 'error')) {
|
|
929
|
-
console.error(`${issue.
|
|
938
|
+
console.error(`${issue.location ?? '(unknown)'}:${issue.line ?? '?'}`);
|
|
930
939
|
console.error(` ${issue.message}`);
|
|
931
940
|
if (issue.suggestion) {
|
|
932
941
|
console.error(` Suggestion: ${issue.suggestion}`);
|
|
@@ -1082,7 +1091,7 @@ Valid by default.
|
|
|
1082
1091
|
|
|
1083
1092
|
## Related Packages
|
|
1084
1093
|
|
|
1085
|
-
- [@vibe-agent-toolkit/utils](../utils) - Core shared utilities
|
|
1094
|
+
- [@vibe-agent-toolkit/utils](../utils/README.md) - Core shared utilities
|
|
1086
1095
|
|
|
1087
1096
|
## Future Enhancements
|
|
1088
1097
|
|
|
@@ -1098,7 +1107,7 @@ Planned features for future releases:
|
|
|
1098
1107
|
|
|
1099
1108
|
## Documentation
|
|
1100
1109
|
|
|
1101
|
-
- [Project Documentation](../../docs)
|
|
1110
|
+
- [Project Documentation](../../docs/README.md)
|
|
1102
1111
|
- [Architecture](../../docs/architecture/README.md)
|
|
1103
1112
|
|
|
1104
1113
|
## License
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ajv factory for adopters consuming VAT-generated schemas.
|
|
3
|
+
*
|
|
4
|
+
* VAT's frontmatter walker treats `format: "uri-reference"` (plus `uri`,
|
|
5
|
+
* `iri`, `iri-reference`) as first-class URI families and validates the
|
|
6
|
+
* referenced files via {@link import('./utils.js').resolveLocalHref}, not via
|
|
7
|
+
* Ajv. But adopters consuming the same schemas with vanilla
|
|
8
|
+
* `new Ajv(...)` hit Ajv's default strict mode, which upgrades
|
|
9
|
+
* `unknown format "uri-reference" ignored` from a warning to a thrown error.
|
|
10
|
+
*
|
|
11
|
+
* This helper returns an Ajv instance with the standard JSON Schema format
|
|
12
|
+
* vocabulary registered (via `ajv-formats`) plus no-op shims for
|
|
13
|
+
* `iri` / `iri-reference` (which `ajv-formats` does not ship). All
|
|
14
|
+
* URI-family schemas compile cleanly under strict mode.
|
|
15
|
+
*/
|
|
16
|
+
import { Ajv, type Options as AjvOptions } from 'ajv';
|
|
17
|
+
/**
|
|
18
|
+
* Construct an Ajv instance pre-registered with the URI-family formats VAT
|
|
19
|
+
* schemas use. Use this anywhere downstream code compiles a schema that may
|
|
20
|
+
* reference `format: "uri-reference"` (or `uri`, `iri`, `iri-reference`).
|
|
21
|
+
*
|
|
22
|
+
* @param options - Ajv options. Passed through unchanged — caller controls
|
|
23
|
+
* `allErrors`, `strict`, `allowUnionTypes`, `verbose`, etc.
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* import { createAjvWithUriFormats } from '@vibe-agent-toolkit/resources';
|
|
27
|
+
*
|
|
28
|
+
* const ajv = createAjvWithUriFormats({ allErrors: true });
|
|
29
|
+
* const validate = ajv.compile(mySchemaWithUriReference);
|
|
30
|
+
* if (!validate(data)) console.error(validate.errors);
|
|
31
|
+
*/
|
|
32
|
+
export declare function createAjvWithUriFormats(options?: AjvOptions): Ajv;
|
|
33
|
+
//# sourceMappingURL=ajv-factory.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ajv-factory.d.ts","sourceRoot":"","sources":["../src/ajv-factory.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAAE,GAAG,EAAE,KAAK,OAAO,IAAI,UAAU,EAAE,MAAM,KAAK,CAAC;AActD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,uBAAuB,CAAC,OAAO,GAAE,UAAe,GAAG,GAAG,CAUrE"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ajv factory for adopters consuming VAT-generated schemas.
|
|
3
|
+
*
|
|
4
|
+
* VAT's frontmatter walker treats `format: "uri-reference"` (plus `uri`,
|
|
5
|
+
* `iri`, `iri-reference`) as first-class URI families and validates the
|
|
6
|
+
* referenced files via {@link import('./utils.js').resolveLocalHref}, not via
|
|
7
|
+
* Ajv. But adopters consuming the same schemas with vanilla
|
|
8
|
+
* `new Ajv(...)` hit Ajv's default strict mode, which upgrades
|
|
9
|
+
* `unknown format "uri-reference" ignored` from a warning to a thrown error.
|
|
10
|
+
*
|
|
11
|
+
* This helper returns an Ajv instance with the standard JSON Schema format
|
|
12
|
+
* vocabulary registered (via `ajv-formats`) plus no-op shims for
|
|
13
|
+
* `iri` / `iri-reference` (which `ajv-formats` does not ship). All
|
|
14
|
+
* URI-family schemas compile cleanly under strict mode.
|
|
15
|
+
*/
|
|
16
|
+
import { Ajv } from 'ajv';
|
|
17
|
+
// ajv-formats is a CJS module published with `module.exports = formatsPlugin`
|
|
18
|
+
// plus an `exports.default` alias. Under NodeNext module resolution the
|
|
19
|
+
// default import is typed as the namespace object (not callable), even
|
|
20
|
+
// though the runtime value IS the plugin function. The `.default ??
|
|
21
|
+
// namespace` pattern below resolves both at type level and runtime.
|
|
22
|
+
import * as ajvFormatsModule from 'ajv-formats';
|
|
23
|
+
const addFormats = ajvFormatsModule.default ??
|
|
24
|
+
ajvFormatsModule;
|
|
25
|
+
/**
|
|
26
|
+
* Construct an Ajv instance pre-registered with the URI-family formats VAT
|
|
27
|
+
* schemas use. Use this anywhere downstream code compiles a schema that may
|
|
28
|
+
* reference `format: "uri-reference"` (or `uri`, `iri`, `iri-reference`).
|
|
29
|
+
*
|
|
30
|
+
* @param options - Ajv options. Passed through unchanged — caller controls
|
|
31
|
+
* `allErrors`, `strict`, `allowUnionTypes`, `verbose`, etc.
|
|
32
|
+
*
|
|
33
|
+
* @example
|
|
34
|
+
* import { createAjvWithUriFormats } from '@vibe-agent-toolkit/resources';
|
|
35
|
+
*
|
|
36
|
+
* const ajv = createAjvWithUriFormats({ allErrors: true });
|
|
37
|
+
* const validate = ajv.compile(mySchemaWithUriReference);
|
|
38
|
+
* if (!validate(data)) console.error(validate.errors);
|
|
39
|
+
*/
|
|
40
|
+
export function createAjvWithUriFormats(options = {}) {
|
|
41
|
+
const ajv = new Ajv(options);
|
|
42
|
+
addFormats(ajv);
|
|
43
|
+
// ajv-formats does not register `iri` / `iri-reference`. Adopters whose
|
|
44
|
+
// schemas declare those would still hit "unknown format" under strict
|
|
45
|
+
// mode. Register no-op validators — Ajv accepts the format token, and
|
|
46
|
+
// semantic validation happens through resolveLocalHref / equivalent.
|
|
47
|
+
ajv.addFormat('iri', true);
|
|
48
|
+
ajv.addFormat('iri-reference', true);
|
|
49
|
+
return ajv;
|
|
50
|
+
}
|
|
51
|
+
//# sourceMappingURL=ajv-factory.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ajv-factory.js","sourceRoot":"","sources":["../src/ajv-factory.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAAE,GAAG,EAA8B,MAAM,KAAK,CAAC;AACtD,8EAA8E;AAC9E,wEAAwE;AACxE,uEAAuE;AACvE,oEAAoE;AACpE,oEAAoE;AACpE,OAAO,KAAK,gBAAgB,MAAM,aAAa,CAAC;AAIhD,MAAM,UAAU,GACb,gBAA0D,CAAC,OAAO;IAClE,gBAA4C,CAAC;AAEhD;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,uBAAuB,CAAC,UAAsB,EAAE;IAC9D,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,CAAC;IAC7B,UAAU,CAAC,GAAG,CAAC,CAAC;IAChB,wEAAwE;IACxE,sEAAsE;IACtE,sEAAsE;IACtE,qEAAqE;IACrE,GAAG,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;IAC3B,GAAG,CAAC,SAAS,CAAC,eAAe,EAAE,IAAI,CAAC,CAAC;IACrC,OAAO,GAAG,CAAC;AACb,CAAC"}
|
package/dist/config-parser.d.ts
CHANGED
|
@@ -4,24 +4,6 @@
|
|
|
4
4
|
* Discovers and parses project configuration files with directory tree walk-up.
|
|
5
5
|
*/
|
|
6
6
|
import { type ProjectConfig } from './schemas/project-config.js';
|
|
7
|
-
/**
|
|
8
|
-
* Find the config file by walking up the directory tree.
|
|
9
|
-
*
|
|
10
|
-
* Starts from the current directory and walks up until the config file is found
|
|
11
|
-
* or the root directory is reached.
|
|
12
|
-
*
|
|
13
|
-
* @param startDir - Directory to start searching from (default: process.cwd())
|
|
14
|
-
* @returns Absolute path to config file, or undefined if not found
|
|
15
|
-
*
|
|
16
|
-
* @example
|
|
17
|
-
* ```typescript
|
|
18
|
-
* const configPath = await findConfigFile();
|
|
19
|
-
* if (configPath) {
|
|
20
|
-
* console.log(`Found config: ${configPath}`);
|
|
21
|
-
* }
|
|
22
|
-
* ```
|
|
23
|
-
*/
|
|
24
|
-
export declare function findConfigFile(startDir?: string): Promise<string | undefined>;
|
|
25
7
|
/**
|
|
26
8
|
* Parse a project configuration file.
|
|
27
9
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config-parser.d.ts","sourceRoot":"","sources":["../src/config-parser.ts"],"names":[],"mappings":"AAAA;;;;GAIG;
|
|
1
|
+
{"version":3,"file":"config-parser.d.ts","sourceRoot":"","sources":["../src/config-parser.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAOH,OAAO,EAAuB,KAAK,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAEtF;;;;;;;;;;;;;;;GAeG;AACH,wBAAsB,eAAe,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC,CAqBhF;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAsB,UAAU,CAAC,QAAQ,GAAE,MAAsB,GAAG,OAAO,CAAC,aAAa,GAAG,SAAS,CAAC,CAQrG"}
|
package/dist/config-parser.js
CHANGED
|
@@ -4,50 +4,9 @@
|
|
|
4
4
|
* Discovers and parses project configuration files with directory tree walk-up.
|
|
5
5
|
*/
|
|
6
6
|
import { readFile } from 'node:fs/promises';
|
|
7
|
-
import
|
|
8
|
-
import {
|
|
9
|
-
import { CORE_SCHEMA, load as loadYaml } from 'js-yaml';
|
|
7
|
+
import { findConfigFile } from '@vibe-agent-toolkit/utils';
|
|
8
|
+
import { parse as parseYaml } from 'yaml';
|
|
10
9
|
import { ProjectConfigSchema } from './schemas/project-config.js';
|
|
11
|
-
const CONFIG_FILENAME = 'vibe-agent-toolkit.config.yaml';
|
|
12
|
-
/**
|
|
13
|
-
* Find the config file by walking up the directory tree.
|
|
14
|
-
*
|
|
15
|
-
* Starts from the current directory and walks up until the config file is found
|
|
16
|
-
* or the root directory is reached.
|
|
17
|
-
*
|
|
18
|
-
* @param startDir - Directory to start searching from (default: process.cwd())
|
|
19
|
-
* @returns Absolute path to config file, or undefined if not found
|
|
20
|
-
*
|
|
21
|
-
* @example
|
|
22
|
-
* ```typescript
|
|
23
|
-
* const configPath = await findConfigFile();
|
|
24
|
-
* if (configPath) {
|
|
25
|
-
* console.log(`Found config: ${configPath}`);
|
|
26
|
-
* }
|
|
27
|
-
* ```
|
|
28
|
-
*/
|
|
29
|
-
export async function findConfigFile(startDir = process.cwd()) {
|
|
30
|
-
let currentDir = safePath.resolve(startDir);
|
|
31
|
-
const { root } = path.parse(currentDir);
|
|
32
|
-
while (true) {
|
|
33
|
-
const configPath = safePath.join(currentDir, CONFIG_FILENAME);
|
|
34
|
-
try {
|
|
35
|
-
// Check if file exists by attempting to read metadata
|
|
36
|
-
// eslint-disable-next-line security/detect-non-literal-fs-filename -- constructing path during tree walk
|
|
37
|
-
await readFile(configPath, 'utf-8');
|
|
38
|
-
return configPath;
|
|
39
|
-
}
|
|
40
|
-
catch {
|
|
41
|
-
// File doesn't exist, continue walking up
|
|
42
|
-
}
|
|
43
|
-
// Check if we've reached the root
|
|
44
|
-
if (currentDir === root) {
|
|
45
|
-
return undefined;
|
|
46
|
-
}
|
|
47
|
-
// Move up one directory
|
|
48
|
-
currentDir = path.dirname(currentDir);
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
10
|
/**
|
|
52
11
|
* Parse a project configuration file.
|
|
53
12
|
*
|
|
@@ -71,8 +30,7 @@ export async function parseConfigFile(configPath) {
|
|
|
71
30
|
// Parse YAML
|
|
72
31
|
let parsed;
|
|
73
32
|
try {
|
|
74
|
-
|
|
75
|
-
parsed = loadYaml(content, { schema: CORE_SCHEMA });
|
|
33
|
+
parsed = parseYaml(content);
|
|
76
34
|
}
|
|
77
35
|
catch (error) {
|
|
78
36
|
throw new Error(`Invalid YAML in config file: ${error instanceof Error ? error.message : String(error)}`);
|
|
@@ -106,7 +64,8 @@ export async function parseConfigFile(configPath) {
|
|
|
106
64
|
* ```
|
|
107
65
|
*/
|
|
108
66
|
export async function loadConfig(startDir = process.cwd()) {
|
|
109
|
-
|
|
67
|
+
// findConfigFile from utils is synchronous; awaiting a non-promise is a no-op.
|
|
68
|
+
const configPath = findConfigFile(startDir);
|
|
110
69
|
if (!configPath) {
|
|
111
70
|
return undefined;
|
|
112
71
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config-parser.js","sourceRoot":"","sources":["../src/config-parser.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"config-parser.js","sourceRoot":"","sources":["../src/config-parser.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAE5C,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAC3D,OAAO,EAAE,KAAK,IAAI,SAAS,EAAE,MAAM,MAAM,CAAC;AAE1C,OAAO,EAAE,mBAAmB,EAAsB,MAAM,6BAA6B,CAAC;AAEtF;;;;;;;;;;;;;;;GAeG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,UAAkB;IACtD,oBAAoB;IACpB,kHAAkH;IAClH,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;IAEpD,aAAa;IACb,IAAI,MAAe,CAAC;IACpB,IAAI,CAAC;QACH,MAAM,GAAG,SAAS,CAAC,OAAO,CAAC,CAAC;IAC9B,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,IAAI,KAAK,CAAC,gCAAgC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IAC5G,CAAC;IAED,0BAA0B;IAC1B,MAAM,MAAM,GAAG,mBAAmB,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;IACrD,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;QACpB,MAAM,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC9F,MAAM,IAAI,KAAK,CAAC,wBAAwB,MAAM,EAAE,CAAC,CAAC;IACpD,CAAC;IAED,OAAO,MAAM,CAAC,IAAI,CAAC;AACrB,CAAC;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,WAAmB,OAAO,CAAC,GAAG,EAAE;IAC/D,+EAA+E;IAC/E,MAAM,UAAU,GAAG,cAAc,CAAC,QAAQ,CAAC,CAAC;IAC5C,IAAI,CAAC,UAAU,EAAE,CAAC;QAChB,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,OAAO,MAAM,eAAe,CAAC,UAAU,CAAC,CAAC;AAC3C,CAAC"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* FrontmatterEditor — round-trip-safe primitive for editing YAML frontmatter
|
|
3
|
+
* in markdown files.
|
|
4
|
+
*
|
|
5
|
+
* Public surface: openFrontmatter(markdown) → FrontmatterEditor.
|
|
6
|
+
*
|
|
7
|
+
* Round-trip identity contract: openFrontmatter(x).toString() === x for any
|
|
8
|
+
* well-formed input, byte-for-byte. Mutations preserve comments, blank lines,
|
|
9
|
+
* key ordering, quoting style, and detected EOL.
|
|
10
|
+
*
|
|
11
|
+
* See docs/superpowers/specs/2026-05-17-frontmatter-editor-and-yaml-consolidation-design.md
|
|
12
|
+
* §5 for the full contract.
|
|
13
|
+
*/
|
|
14
|
+
export declare class FrontmatterParseError extends Error {
|
|
15
|
+
readonly cause: unknown;
|
|
16
|
+
constructor(message: string, cause: unknown);
|
|
17
|
+
}
|
|
18
|
+
/** Path to a value in the parsed frontmatter document. */
|
|
19
|
+
export type FrontmatterPath = string | readonly (string | number)[];
|
|
20
|
+
/** Scalar value type accepted by mutation methods. */
|
|
21
|
+
export type FrontmatterScalar = string | number | boolean | null;
|
|
22
|
+
export interface FrontmatterEditor {
|
|
23
|
+
body: string;
|
|
24
|
+
get(path: FrontmatterPath): unknown;
|
|
25
|
+
set(path: FrontmatterPath, value: FrontmatterScalar): void;
|
|
26
|
+
setArrayItem(path: FrontmatterPath, index: number, value: FrontmatterScalar): void;
|
|
27
|
+
appendArrayItem(path: FrontmatterPath, value: FrontmatterScalar): void;
|
|
28
|
+
delete(path: FrontmatterPath): void;
|
|
29
|
+
toString(): string;
|
|
30
|
+
/**
|
|
31
|
+
* Returns true if any mutating method has been called or `body` was
|
|
32
|
+
* reassigned to a different string. Use to gate writeFileSync and avoid
|
|
33
|
+
* the no-op-rewrite churn described in §"What's preserved, what isn't"
|
|
34
|
+
* of the markdown-rewriting skill.
|
|
35
|
+
*
|
|
36
|
+
* **Caveat:** any call to `set` / `setArrayItem` / `appendArrayItem` /
|
|
37
|
+
* `delete` flips the flag, even if the underlying value didn't change
|
|
38
|
+
* (e.g. `set('foo', sameValue)`). For strict byte-level dirty detection
|
|
39
|
+
* compare `editor.toString() !== originalText` instead. `body =` is the
|
|
40
|
+
* one exception — it only flips dirty on actual string change.
|
|
41
|
+
*/
|
|
42
|
+
isDirty(): boolean;
|
|
43
|
+
}
|
|
44
|
+
export declare function openFrontmatter(markdown: string): FrontmatterEditor;
|
|
45
|
+
//# sourceMappingURL=frontmatter-editor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"frontmatter-editor.d.ts","sourceRoot":"","sources":["../src/frontmatter-editor.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAIH,qBAAa,qBAAsB,SAAQ,KAAK;IAC9C,SAAyB,KAAK,EAAE,OAAO,CAAC;gBAE5B,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO;CAK5C;AAED,0DAA0D;AAC1D,MAAM,MAAM,eAAe,GAAG,MAAM,GAAG,SAAS,CAAC,MAAM,GAAG,MAAM,CAAC,EAAE,CAAC;AAEpE,sDAAsD;AACtD,MAAM,MAAM,iBAAiB,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,CAAC;AAEjE,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,IAAI,EAAE,eAAe,GAAG,OAAO,CAAC;IACpC,GAAG,CAAC,IAAI,EAAE,eAAe,EAAE,KAAK,EAAE,iBAAiB,GAAG,IAAI,CAAC;IAC3D,YAAY,CAAC,IAAI,EAAE,eAAe,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,iBAAiB,GAAG,IAAI,CAAC;IACnF,eAAe,CAAC,IAAI,EAAE,eAAe,EAAE,KAAK,EAAE,iBAAiB,GAAG,IAAI,CAAC;IACvE,MAAM,CAAC,IAAI,EAAE,eAAe,GAAG,IAAI,CAAC;IACpC,QAAQ,IAAI,MAAM,CAAC;IACnB;;;;;;;;;;;OAWG;IACH,OAAO,IAAI,OAAO,CAAC;CACpB;AA8JD,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,iBAAiB,CAEnE"}
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* FrontmatterEditor — round-trip-safe primitive for editing YAML frontmatter
|
|
3
|
+
* in markdown files.
|
|
4
|
+
*
|
|
5
|
+
* Public surface: openFrontmatter(markdown) → FrontmatterEditor.
|
|
6
|
+
*
|
|
7
|
+
* Round-trip identity contract: openFrontmatter(x).toString() === x for any
|
|
8
|
+
* well-formed input, byte-for-byte. Mutations preserve comments, blank lines,
|
|
9
|
+
* key ordering, quoting style, and detected EOL.
|
|
10
|
+
*
|
|
11
|
+
* See docs/superpowers/specs/2026-05-17-frontmatter-editor-and-yaml-consolidation-design.md
|
|
12
|
+
* §5 for the full contract.
|
|
13
|
+
*/
|
|
14
|
+
import { Document, parseDocument } from 'yaml';
|
|
15
|
+
export class FrontmatterParseError extends Error {
|
|
16
|
+
cause;
|
|
17
|
+
constructor(message, cause) {
|
|
18
|
+
super(message);
|
|
19
|
+
this.name = 'FrontmatterParseError';
|
|
20
|
+
this.cause = cause;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
const OPENING_FENCE = /^---\r?\n/;
|
|
24
|
+
// Closing fence: either immediately after opening (empty frontmatter), or
|
|
25
|
+
// preceded by a newline. Trailing variants accept newline or EOF.
|
|
26
|
+
const EMPTY_CLOSING_FENCE = /^---(?:\r?\n|$)/;
|
|
27
|
+
const CLOSING_FENCE = /(?:\r?\n---\r?\n|\r?\n---$)/;
|
|
28
|
+
function detectEol(input) {
|
|
29
|
+
const firstBreak = input.indexOf('\n');
|
|
30
|
+
if (firstBreak === -1)
|
|
31
|
+
return '\n';
|
|
32
|
+
return firstBreak > 0 && input.charAt(firstBreak - 1) === '\r' ? '\r\n' : '\n';
|
|
33
|
+
}
|
|
34
|
+
function splitFrontmatter(input) {
|
|
35
|
+
const eol = detectEol(input);
|
|
36
|
+
const openingMatch = OPENING_FENCE.exec(input);
|
|
37
|
+
if (!openingMatch) {
|
|
38
|
+
return { hasFrontmatter: false, frontmatterText: '', body: input, eol };
|
|
39
|
+
}
|
|
40
|
+
const afterOpening = input.slice(openingMatch[0].length);
|
|
41
|
+
// Handle empty frontmatter (closing fence immediately follows opening fence)
|
|
42
|
+
const emptyMatch = EMPTY_CLOSING_FENCE.exec(afterOpening);
|
|
43
|
+
if (emptyMatch) {
|
|
44
|
+
const bodyStart = emptyMatch[0].length;
|
|
45
|
+
return {
|
|
46
|
+
hasFrontmatter: true,
|
|
47
|
+
frontmatterText: '',
|
|
48
|
+
body: afterOpening.slice(bodyStart),
|
|
49
|
+
eol,
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
const closingMatch = CLOSING_FENCE.exec(afterOpening);
|
|
53
|
+
if (!closingMatch) {
|
|
54
|
+
return { hasFrontmatter: false, frontmatterText: '', body: input, eol };
|
|
55
|
+
}
|
|
56
|
+
const frontmatterText = afterOpening.slice(0, closingMatch.index);
|
|
57
|
+
const bodyStart = closingMatch.index + closingMatch[0].length;
|
|
58
|
+
const body = afterOpening.slice(bodyStart);
|
|
59
|
+
return { hasFrontmatter: true, frontmatterText, body, eol };
|
|
60
|
+
}
|
|
61
|
+
class FrontmatterEditorImpl {
|
|
62
|
+
doc;
|
|
63
|
+
hasFrontmatter;
|
|
64
|
+
eol;
|
|
65
|
+
_body;
|
|
66
|
+
_dirty = false;
|
|
67
|
+
get body() {
|
|
68
|
+
return this._body;
|
|
69
|
+
}
|
|
70
|
+
set body(value) {
|
|
71
|
+
if (value !== this._body) {
|
|
72
|
+
this._body = value;
|
|
73
|
+
this._dirty = true;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
isDirty() {
|
|
77
|
+
return this._dirty;
|
|
78
|
+
}
|
|
79
|
+
constructor(input) {
|
|
80
|
+
const split = splitFrontmatter(input);
|
|
81
|
+
this.hasFrontmatter = split.hasFrontmatter;
|
|
82
|
+
this.eol = split.eol;
|
|
83
|
+
this._body = split.body;
|
|
84
|
+
if (!split.hasFrontmatter) {
|
|
85
|
+
this.doc = new Document({});
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
try {
|
|
89
|
+
this.doc = parseDocument(split.frontmatterText, { prettyErrors: true });
|
|
90
|
+
if (this.doc.errors.length > 0) {
|
|
91
|
+
throw new FrontmatterParseError(`Invalid YAML frontmatter: ${this.doc.errors[0]?.message ?? 'unknown error'}`, this.doc.errors[0]);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
catch (error) {
|
|
95
|
+
if (error instanceof FrontmatterParseError)
|
|
96
|
+
throw error;
|
|
97
|
+
throw new FrontmatterParseError(`Failed to parse frontmatter: ${error instanceof Error ? error.message : String(error)}`, error);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
toPath(path) {
|
|
101
|
+
if (Array.isArray(path))
|
|
102
|
+
return path;
|
|
103
|
+
if (typeof path === 'string')
|
|
104
|
+
return [path];
|
|
105
|
+
return path;
|
|
106
|
+
}
|
|
107
|
+
get(path) {
|
|
108
|
+
const segments = this.toPath(path);
|
|
109
|
+
if (segments.length === 0)
|
|
110
|
+
return this.doc.toJS();
|
|
111
|
+
return this.doc.getIn(segments, false);
|
|
112
|
+
}
|
|
113
|
+
set(path, value) {
|
|
114
|
+
const segments = this.toPath(path);
|
|
115
|
+
this.doc.setIn(segments, value);
|
|
116
|
+
this._dirty = true;
|
|
117
|
+
}
|
|
118
|
+
setArrayItem(path, index, value) {
|
|
119
|
+
const segments = [...this.toPath(path), index];
|
|
120
|
+
this.doc.setIn(segments, value);
|
|
121
|
+
this._dirty = true;
|
|
122
|
+
}
|
|
123
|
+
appendArrayItem(path, value) {
|
|
124
|
+
const segments = this.toPath(path);
|
|
125
|
+
this.doc.addIn(segments, value);
|
|
126
|
+
this._dirty = true;
|
|
127
|
+
}
|
|
128
|
+
delete(path) {
|
|
129
|
+
const segments = this.toPath(path);
|
|
130
|
+
this.doc.deleteIn(segments);
|
|
131
|
+
this._dirty = true;
|
|
132
|
+
}
|
|
133
|
+
toString() {
|
|
134
|
+
// No frontmatter originally, and nothing was added → return body unchanged.
|
|
135
|
+
if (!this.hasFrontmatter && this.isDocEffectivelyEmpty()) {
|
|
136
|
+
return this.body;
|
|
137
|
+
}
|
|
138
|
+
// Empty frontmatter (e.g. `---\n---\n`) where the doc remained empty —
|
|
139
|
+
// preserve the empty fence block without injecting `null` or `{}` between.
|
|
140
|
+
if (this.hasFrontmatter && this.isDocEffectivelyEmpty()) {
|
|
141
|
+
return `---${this.eol}---${this.eol}${this.body}`;
|
|
142
|
+
}
|
|
143
|
+
const fmText = this.doc.toString();
|
|
144
|
+
const normalized = this.eol === '\r\n' ? fmText.replaceAll('\n', '\r\n') : fmText;
|
|
145
|
+
return `---${this.eol}${normalized}---${this.eol}${this.body}`;
|
|
146
|
+
}
|
|
147
|
+
isDocEffectivelyEmpty() {
|
|
148
|
+
const contents = this.doc.contents;
|
|
149
|
+
if (contents === null)
|
|
150
|
+
return true;
|
|
151
|
+
// yaml.YAMLMap and YAMLSeq expose `items`; an empty map/seq counts as empty.
|
|
152
|
+
const maybeItems = contents.items;
|
|
153
|
+
if (Array.isArray(maybeItems) && maybeItems.length === 0)
|
|
154
|
+
return true;
|
|
155
|
+
return false;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
export function openFrontmatter(markdown) {
|
|
159
|
+
return new FrontmatterEditorImpl(markdown);
|
|
160
|
+
}
|
|
161
|
+
//# sourceMappingURL=frontmatter-editor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"frontmatter-editor.js","sourceRoot":"","sources":["../src/frontmatter-editor.ts"],"names":[],"mappings":"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"}
|
|
@@ -7,11 +7,11 @@
|
|
|
7
7
|
* frontmatter-specific type codes plus a list of external URLs the registry
|
|
8
8
|
* can fold into its existing external URL collection.
|
|
9
9
|
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
10
|
+
* Code mapping:
|
|
11
|
+
* LINK_BROKEN_FILE -> FRONTMATTER_LINK_BROKEN
|
|
12
|
+
* LINK_BROKEN_ANCHOR -> FRONTMATTER_ANCHOR_MISSING
|
|
13
|
+
* LINK_TO_GITIGNORED -> FRONTMATTER_LINK_TO_GITIGNORED
|
|
14
|
+
* LINK_UNKNOWN -> FRONTMATTER_UNKNOWN_LINK
|
|
15
15
|
*
|
|
16
16
|
* Skipped (no issue, no external):
|
|
17
17
|
* email (mailto:)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"frontmatter-link-validator.d.ts","sourceRoot":"","sources":["../src/frontmatter-link-validator.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;
|
|
1
|
+
{"version":3,"file":"frontmatter-link-validator.d.ts","sourceRoot":"","sources":["../src/frontmatter-link-validator.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAKH,OAAO,EAAgB,KAAK,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAE7E,OAAO,KAAK,EAAE,WAAW,EAAgB,eAAe,EAAE,MAAM,YAAY,CAAC;AAU7E,kFAAkF;AAClF,MAAM,WAAW,sBAAsB;IACrC,GAAG,EAAE,MAAM,CAAC;IACZ,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,+BAA+B;IAC9C,MAAM,EAAE,eAAe,EAAE,CAAC;IAC1B,YAAY,EAAE,sBAAsB,EAAE,CAAC;CACxC;AAED;;;;;;;;GAQG;AACH,wBAAsB,wBAAwB,CAC5C,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,EAChD,MAAM,EAAE,MAAM,EACd,cAAc,EAAE,MAAM,EACtB,cAAc,EAAE,GAAG,CAAC,MAAM,EAAE,WAAW,EAAE,CAAC,EAC1C,OAAO,CAAC,EAAE,mBAAmB,GAC5B,OAAO,CAAC,+BAA+B,CAAC,CAoC1C"}
|
|
@@ -7,19 +7,27 @@
|
|
|
7
7
|
* frontmatter-specific type codes plus a list of external URLs the registry
|
|
8
8
|
* can fold into its existing external URL collection.
|
|
9
9
|
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
10
|
+
* Code mapping:
|
|
11
|
+
* LINK_BROKEN_FILE -> FRONTMATTER_LINK_BROKEN
|
|
12
|
+
* LINK_BROKEN_ANCHOR -> FRONTMATTER_ANCHOR_MISSING
|
|
13
|
+
* LINK_TO_GITIGNORED -> FRONTMATTER_LINK_TO_GITIGNORED
|
|
14
|
+
* LINK_UNKNOWN -> FRONTMATTER_UNKNOWN_LINK
|
|
15
15
|
*
|
|
16
16
|
* Skipped (no issue, no external):
|
|
17
17
|
* email (mailto:)
|
|
18
18
|
* anchor-only (validated as anchor in current file via validateLink)
|
|
19
19
|
*/
|
|
20
|
+
import { createRegistryIssue } from '@vibe-agent-toolkit/agent-schema';
|
|
20
21
|
import { classifyLink } from './link-parser.js';
|
|
21
22
|
import { validateLink } from './link-validator.js';
|
|
22
23
|
import { walkFrontmatterUriReferences } from './schema-uri-walker.js';
|
|
24
|
+
/** Map the link-level code emitted by validateLink to its frontmatter-scoped code. */
|
|
25
|
+
const LINK_CODE_TO_FRONTMATTER_CODE = {
|
|
26
|
+
LINK_BROKEN_FILE: 'FRONTMATTER_LINK_BROKEN',
|
|
27
|
+
LINK_BROKEN_ANCHOR: 'FRONTMATTER_ANCHOR_MISSING',
|
|
28
|
+
LINK_TO_GITIGNORED: 'FRONTMATTER_LINK_TO_GITIGNORED',
|
|
29
|
+
LINK_UNKNOWN: 'FRONTMATTER_UNKNOWN_LINK',
|
|
30
|
+
};
|
|
23
31
|
/**
|
|
24
32
|
* Validate every URI-family frontmatter value against the file system.
|
|
25
33
|
*
|
|
@@ -63,24 +71,17 @@ export async function validateFrontmatterLinks(frontmatter, schema, sourceFilePa
|
|
|
63
71
|
return { issues, externalUrls };
|
|
64
72
|
}
|
|
65
73
|
function rewriteIssue(issue, dottedPath) {
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
case 'link_to_gitignored':
|
|
79
|
-
return 'frontmatter_link_to_gitignored';
|
|
80
|
-
case 'unknown_link':
|
|
81
|
-
return 'frontmatter_unknown_link';
|
|
82
|
-
default:
|
|
83
|
-
return originalType;
|
|
84
|
-
}
|
|
74
|
+
const mappedCode = LINK_CODE_TO_FRONTMATTER_CODE[issue.code] ?? issue.code;
|
|
75
|
+
const message = `field \`${dottedPath}\`: ${issue.message}`;
|
|
76
|
+
const extras = {};
|
|
77
|
+
if (issue.location !== undefined)
|
|
78
|
+
extras.location = issue.location;
|
|
79
|
+
if (issue.line !== undefined)
|
|
80
|
+
extras.line = issue.line;
|
|
81
|
+
if (issue.link !== undefined)
|
|
82
|
+
extras.link = issue.link;
|
|
83
|
+
if (issue.suggestion !== undefined)
|
|
84
|
+
extras.suggestion = issue.suggestion;
|
|
85
|
+
return createRegistryIssue(mappedCode, message, extras);
|
|
85
86
|
}
|
|
86
87
|
//# sourceMappingURL=frontmatter-link-validator.js.map
|