@refrakt-md/content 0.35.0 → 0.37.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.
Files changed (53) hide show
  1. package/dist/edges/exclude.d.ts +47 -0
  2. package/dist/edges/exclude.d.ts.map +1 -0
  3. package/dist/edges/exclude.js +124 -0
  4. package/dist/edges/exclude.js.map +1 -0
  5. package/dist/edges/extract.d.ts +122 -0
  6. package/dist/edges/extract.d.ts.map +1 -0
  7. package/dist/edges/extract.js +317 -0
  8. package/dist/edges/extract.js.map +1 -0
  9. package/dist/edges/git-scan.d.ts +69 -0
  10. package/dist/edges/git-scan.d.ts.map +1 -0
  11. package/dist/edges/git-scan.js +138 -0
  12. package/dist/edges/git-scan.js.map +1 -0
  13. package/dist/edges/index.d.ts +119 -0
  14. package/dist/edges/index.d.ts.map +1 -0
  15. package/dist/edges/index.js +264 -0
  16. package/dist/edges/index.js.map +1 -0
  17. package/dist/format.d.ts +22 -0
  18. package/dist/format.d.ts.map +1 -1
  19. package/dist/format.js +7 -20
  20. package/dist/format.js.map +1 -1
  21. package/dist/frontmatter.d.ts +25 -0
  22. package/dist/frontmatter.d.ts.map +1 -1
  23. package/dist/frontmatter.js.map +1 -1
  24. package/dist/index.d.ts +3 -2
  25. package/dist/index.d.ts.map +1 -1
  26. package/dist/index.js +3 -2
  27. package/dist/index.js.map +1 -1
  28. package/dist/layout.d.ts +1 -1
  29. package/dist/layout.d.ts.map +1 -1
  30. package/dist/loader.d.ts +15 -0
  31. package/dist/loader.d.ts.map +1 -1
  32. package/dist/loader.js +23 -1
  33. package/dist/loader.js.map +1 -1
  34. package/dist/refract-loader.d.ts +23 -0
  35. package/dist/refract-loader.d.ts.map +1 -1
  36. package/dist/refract-loader.js +81 -5
  37. package/dist/refract-loader.js.map +1 -1
  38. package/dist/router.d.ts +1 -1
  39. package/dist/router.d.ts.map +1 -1
  40. package/dist/site.d.ts +173 -5
  41. package/dist/site.d.ts.map +1 -1
  42. package/dist/site.js +250 -133
  43. package/dist/site.js.map +1 -1
  44. package/dist/validate-content.d.ts +83 -0
  45. package/dist/validate-content.d.ts.map +1 -0
  46. package/dist/validate-content.js +143 -0
  47. package/dist/validate-content.js.map +1 -0
  48. package/dist/validate.d.ts +32 -0
  49. package/dist/validate.d.ts.map +1 -1
  50. package/dist/validate.js +31 -10
  51. package/dist/validate.js.map +1 -1
  52. package/frontmatter.schema.json +7 -0
  53. package/package.json +9 -5
@@ -0,0 +1,143 @@
1
+ /**
2
+ * The fast validation tier — SPEC-135 D3 / D14 / WORK-577.
3
+ *
4
+ * `loadContent` validates as a side effect of building a `Site`: it resolves
5
+ * routes and layouts, shells out to git for timestamps, runs the identity
6
+ * transform, and then runs three more cross-page phases over every page. A CLI
7
+ * that called it would be no faster than a build, which defeats the reason for
8
+ * having a CLI (D3).
9
+ *
10
+ * This runs the two steps validation actually needs — parse and validate —
11
+ * against a config built by the *same* function the build uses, so the two
12
+ * cannot disagree about which tags and attributes exist (D14).
13
+ */
14
+ import { resolve } from 'node:path';
15
+ import Markdoc from '@markdoc/markdoc';
16
+ import { fsProjectFiles } from '@refrakt-md/types/project-files';
17
+ import { escapeFenceTags } from '@refrakt-md/runes';
18
+ import { ContentTree } from './content-tree.js';
19
+ import { parseFrontmatter } from './frontmatter.js';
20
+ import { Router } from './router.js';
21
+ import { buildPageContentVariables, buildPageTransformConfig, buildPreprocessHookSets, parsePagePartials, } from './site.js';
22
+ import { validatePageDetailed } from './validate.js';
23
+ /**
24
+ * Validate every page in a content tree, returning findings.
25
+ *
26
+ * Accepts a directory path or a pre-built {@link ContentTree}. Runs parse,
27
+ * preprocess and `Markdoc.validate`, and **nothing else**: no `resolveLayouts`,
28
+ * no `resolveTimestamps` (no git), no `Markdoc.transform`, no `runPipeline`.
29
+ *
30
+ * Two departures from WORK-577's acceptance criteria, both in service of the
31
+ * agreement the same item calls its real deliverable:
32
+ *
33
+ * - **It resolves routes.** The criteria say not to call `router.resolve`, to
34
+ * keep the tier fast. `Router.resolve` is pure string manipulation with no
35
+ * I/O (`router.ts:46`), so it costs nothing measurable — and without it every
36
+ * finding's `url` would differ from the build's, making the agreement
37
+ * approximate where it could be exact.
38
+ * - **It runs preprocess hooks.** The criteria do not mention them. They are
39
+ * not optional: `{% snippet %}` resolves itself into a fence node during
40
+ * preprocess and `{% include %}` pastes partial content in, so skipping them
41
+ * validates a different tree than the build does — precisely the divergence
42
+ * D5a exists to forbid.
43
+ *
44
+ * What stays skipped is where the cost actually is: git, layouts, the identity
45
+ * transform, and the three cross-page phases. Those are the `--deep` tier.
46
+ */
47
+ export async function validateContent(source, options = {}) {
48
+ const tree = typeof source === 'string' ? await ContentTree.fromDirectory(source) : source;
49
+ const router = new Router(options.basePath ?? '/');
50
+ // Mirror `loadContent`'s defaults for the directory form. It derives a
51
+ // project root from the content directory's parent and roots a
52
+ // `fsProjectFiles` provider there; without the same defaults, snippet's
53
+ // preprocess cannot read files here while it can in a build, and the two
54
+ // paths report different findings for the same corpus.
55
+ //
56
+ // Found by running this function against refrakt's own 235-page site and
57
+ // diffing: 13 findings the build had and this did not, plus one it had and
58
+ // the build did not — all of them snippet tags that resolved in one path and
59
+ // not the other. Exactly the divergence D5a forbids, and invisible without
60
+ // the comparison.
61
+ const env = { ...options };
62
+ if (typeof source === 'string') {
63
+ const projectRoot = options.projectRoot ?? resolve(source, '..');
64
+ env.projectRoot = projectRoot;
65
+ env.sandbox = options.sandbox ?? fsProjectFiles(projectRoot);
66
+ }
67
+ const parsedPartials = await parsePagePartials(tree, env);
68
+ const hookSets = buildPreprocessHookSets(env, parsedPartials);
69
+ // D5a — settings come off the site config exactly as `loadContent` reads
70
+ // them (`site.ts`), and are handed to `validatePageDetailed`, which resolves
71
+ // them through `resolveValidationIds`. Not reimplemented here: the three-way
72
+ // refinement (demote / drop / always-report) has one implementation, and
73
+ // this path calls it.
74
+ const settings = options.validation ??
75
+ options.siteConfig?.validation;
76
+ const out = [];
77
+ for (const page of tree.pages()) {
78
+ const { frontmatter, content } = parseFrontmatter(page.raw);
79
+ const route = router.resolve(page.relativePath, frontmatter);
80
+ let ast = Markdoc.parse(escapeFenceTags(content));
81
+ // Computed before preprocess, exactly as the build does, so snippet can
82
+ // resolve `path=$file.path`-style references. `timestamps` is omitted —
83
+ // that is the git call the fast tier exists to skip, and nothing in
84
+ // preprocess reads `$file.created` / `$file.modified`.
85
+ const contentVariables = buildPageContentVariables({
86
+ ast,
87
+ frontmatter,
88
+ relativePath: page.relativePath,
89
+ filePath: page.filePath,
90
+ url: route.url,
91
+ draft: route.draft,
92
+ variables: options.variables,
93
+ projectRoot: env.projectRoot,
94
+ sandbox: env.sandbox,
95
+ sandboxExamplesDir: options.sandboxExamplesDir,
96
+ securityPolicy: options.securityPolicy,
97
+ siteConfig: options.siteConfig,
98
+ });
99
+ // Preprocess needs somewhere to put its own diagnostics. They are
100
+ // collected and discarded here: a preprocess warning is a pipeline
101
+ // finding, not a content-validation finding, and reporting it from this
102
+ // entry point would make the fast tier return findings a `validatePage`
103
+ // comparison could never match. The build still reports them.
104
+ const ppCtx = {
105
+ info() { },
106
+ warn() { },
107
+ error() { },
108
+ projectRoot: env.projectRoot,
109
+ sandbox: env.sandbox,
110
+ variables: contentVariables,
111
+ partials: parsedPartials ?? {},
112
+ };
113
+ for (const { hooks } of hookSets) {
114
+ if (!hooks.preprocess)
115
+ continue;
116
+ const next = await hooks.preprocess(ast, { url: route.url, relativePath: page.relativePath, filePath: page.filePath }, ppCtx);
117
+ if (next)
118
+ ast = next;
119
+ }
120
+ const { config } = buildPageTransformConfig({
121
+ ast,
122
+ content,
123
+ path: route.url,
124
+ sourcePath: page.relativePath,
125
+ icons: options.icons,
126
+ additionalTags: options.additionalTags,
127
+ contentVariables,
128
+ partials: parsedPartials,
129
+ });
130
+ for (const finding of validatePageDetailed(ast, config, { url: route.url, settings })) {
131
+ out.push({
132
+ file: page.relativePath,
133
+ url: route.url,
134
+ line: finding.line,
135
+ severity: finding.warning.severity,
136
+ id: finding.id,
137
+ message: finding.warning.message,
138
+ });
139
+ }
140
+ }
141
+ return out;
142
+ }
143
+ //# sourceMappingURL=validate-content.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validate-content.js","sourceRoot":"","sources":["../src/validate-content.ts"],"names":[],"mappings":"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"}
@@ -99,5 +99,37 @@ export interface ValidatePageOptions {
99
99
  * value in an `info` stream of every check the project has decided against.
100
100
  */
101
101
  export declare function validatePage(ast: Node, config: unknown, opts: ValidatePageOptions): PipelineWarning[];
102
+ /**
103
+ * A finding, plus the structured fields `PipelineWarning` has nowhere to put.
104
+ *
105
+ * `PipelineWarning` is the build's diagnostic shape: severity, phase, plugin,
106
+ * url, message. The Markdoc error id and source line are *formatted into* the
107
+ * message there, which is fine for a build summary a human reads and useless to
108
+ * a caller that wants to filter by id or open a file at a line — the CLI's
109
+ * `--format json` (WORK-578) and the MCP tool (WORK-581, SPEC-135 D6).
110
+ *
111
+ * Carried alongside rather than added to `PipelineWarning` so the build's
112
+ * diagnostic shape is unchanged and the two cannot drift: the warning here is
113
+ * the identical object `validatePage` returns.
114
+ */
115
+ export interface DetailedFinding {
116
+ /** Exactly what `validatePage` reports for this finding. */
117
+ warning: PipelineWarning;
118
+ /** Markdoc error id, e.g. `tag-undefined`. Absent only when validation
119
+ * itself crashed and the finding is the fallback. */
120
+ id?: string;
121
+ /** 1-based source line, matching what the message renders. */
122
+ line?: number;
123
+ }
124
+ /**
125
+ * {@link validatePage}, keeping the structured fields.
126
+ *
127
+ * This is where the dispositions actually live; `validatePage` is a projection
128
+ * of it. Single-sourced deliberately — SPEC-135 D5a requires that every caller
129
+ * resolve settings through `resolveValidationIds` rather than reimplementing
130
+ * the three-way refinement, and the cheapest way to guarantee that is for there
131
+ * to be exactly one implementation to call.
132
+ */
133
+ export declare function validatePageDetailed(ast: Node, config: unknown, opts: ValidatePageOptions): DetailedFinding[];
102
134
  export {};
103
135
  //# sourceMappingURL=validate.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../src/validate.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAiB,MAAM,kBAAkB,CAAC;AAC5D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAEzD;;;;;;;;;;;;GAYG;AAEH,4EAA4E;AAC5E,KAAK,YAAY,GAAG,OAAO,GAAG,MAAM,GAAG,SAAS,GAAG,OAAO,GAAG,UAAU,CAAC;AAExE;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,sBAAsB,EAAE,SAAS,MAAM,EAenD,CAAC;AAmBF;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,YAAY,GAAG,OAAO,CAE3D;AAED;;;;;;GAMG;AACH,MAAM,WAAW,kBAAkB;IAClC;kDAC8C;IAC9C,OAAO,EAAE,OAAO,CAAC;IACjB,8EAA8E;IAC9E,GAAG,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACxB;8CAC0C;IAC1C,UAAU,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CAC/B;AAED,eAAO,MAAM,2BAA2B,EAAE,kBAAsC,CAAC;AAEjF,sDAAsD;AACtD,wBAAgB,oBAAoB,CAAC,QAAQ,CAAC,EAAE,kBAAkB,GAAG,GAAG,CAAC,MAAM,CAAC,CAI/E;AASD,MAAM,WAAW,mBAAmB;IACnC,4CAA4C;IAC5C,GAAG,EAAE,MAAM,CAAC;IACZ,6EAA6E;IAC7E,QAAQ,CAAC,EAAE,kBAAkB,CAAC;IAC9B;;;;uEAImE;IACnE,aAAa,CAAC,EAAE,MAAM,CAAC;CACvB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,wBAAgB,YAAY,CAC3B,GAAG,EAAE,IAAI,EACT,MAAM,EAAE,OAAO,EACf,IAAI,EAAE,mBAAmB,GACvB,eAAe,EAAE,CA+CnB"}
1
+ {"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../src/validate.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAiB,MAAM,kBAAkB,CAAC;AAC5D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAEzD;;;;;;;;;;;;GAYG;AAEH,4EAA4E;AAC5E,KAAK,YAAY,GAAG,OAAO,GAAG,MAAM,GAAG,SAAS,GAAG,OAAO,GAAG,UAAU,CAAC;AAExE;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,sBAAsB,EAAE,SAAS,MAAM,EAenD,CAAC;AAmBF;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,YAAY,GAAG,OAAO,CAE3D;AAED;;;;;;GAMG;AACH,MAAM,WAAW,kBAAkB;IAClC;kDAC8C;IAC9C,OAAO,EAAE,OAAO,CAAC;IACjB,8EAA8E;IAC9E,GAAG,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACxB;8CAC0C;IAC1C,UAAU,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CAC/B;AAED,eAAO,MAAM,2BAA2B,EAAE,kBAAsC,CAAC;AAEjF,sDAAsD;AACtD,wBAAgB,oBAAoB,CAAC,QAAQ,CAAC,EAAE,kBAAkB,GAAG,GAAG,CAAC,MAAM,CAAC,CAI/E;AASD,MAAM,WAAW,mBAAmB;IACnC,4CAA4C;IAC5C,GAAG,EAAE,MAAM,CAAC;IACZ,6EAA6E;IAC7E,QAAQ,CAAC,EAAE,kBAAkB,CAAC;IAC9B;;;;uEAImE;IACnE,aAAa,CAAC,EAAE,MAAM,CAAC;CACvB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,wBAAgB,YAAY,CAC3B,GAAG,EAAE,IAAI,EACT,MAAM,EAAE,OAAO,EACf,IAAI,EAAE,mBAAmB,GACvB,eAAe,EAAE,CAEnB;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,WAAW,eAAe;IAC/B,4DAA4D;IAC5D,OAAO,EAAE,eAAe,CAAC;IACzB;0DACsD;IACtD,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,8DAA8D;IAC9D,IAAI,CAAC,EAAE,MAAM,CAAC;CACd;AAED;;;;;;;;GAQG;AACH,wBAAgB,oBAAoB,CACnC,GAAG,EAAE,IAAI,EACT,MAAM,EAAE,OAAO,EACf,IAAI,EAAE,mBAAmB,GACvB,eAAe,EAAE,CAwDnB"}
package/dist/validate.js CHANGED
@@ -97,6 +97,18 @@ function demotedIds(settings) {
97
97
  * value in an `info` stream of every check the project has decided against.
98
98
  */
99
99
  export function validatePage(ast, config, opts) {
100
+ return validatePageDetailed(ast, config, opts).map((f) => f.warning);
101
+ }
102
+ /**
103
+ * {@link validatePage}, keeping the structured fields.
104
+ *
105
+ * This is where the dispositions actually live; `validatePage` is a projection
106
+ * of it. Single-sourced deliberately — SPEC-135 D5a requires that every caller
107
+ * resolve settings through `resolveValidationIds` rather than reimplementing
108
+ * the three-way refinement, and the cheapest way to guarantee that is for there
109
+ * to be exactly one implementation to call.
110
+ */
111
+ export function validatePageDetailed(ast, config, opts) {
100
112
  const settings = opts.settings ?? DEFAULT_VALIDATION_SETTINGS;
101
113
  const allowed = resolveValidationIds(settings);
102
114
  const demoted = demotedIds(settings);
@@ -108,11 +120,13 @@ export function validatePage(ast, config, opts) {
108
120
  catch (err) {
109
121
  return [
110
122
  {
111
- severity: 'warning',
112
- phase: 'validate',
113
- pluginName,
114
- url: opts.url,
115
- message: `content validation could not run: ${err.message}`,
123
+ warning: {
124
+ severity: 'warning',
125
+ phase: 'validate',
126
+ pluginName,
127
+ url: opts.url,
128
+ message: `content validation could not run: ${err.message}`,
129
+ },
116
130
  },
117
131
  ];
118
132
  }
@@ -133,12 +147,19 @@ export function validatePage(ast, config, opts) {
133
147
  continue;
134
148
  }
135
149
  }
150
+ const rawLine = finding.lines?.[0];
136
151
  out.push({
137
- severity,
138
- phase: 'validate',
139
- pluginName,
140
- url: opts.url,
141
- message: formatFinding(finding, opts.contributedBy),
152
+ warning: {
153
+ severity,
154
+ phase: 'validate',
155
+ pluginName,
156
+ url: opts.url,
157
+ message: formatFinding(finding, opts.contributedBy),
158
+ },
159
+ id,
160
+ // `formatFinding` renders `line + 1`; match it so a caller and the
161
+ // message never disagree about which line is meant.
162
+ line: typeof rawLine === 'number' ? rawLine + 1 : undefined,
142
163
  });
143
164
  }
144
165
  return out;
@@ -1 +1 @@
1
- {"version":3,"file":"validate.js","sourceRoot":"","sources":["../src/validate.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"validate.js","sourceRoot":"","sources":["../src/validate.ts"],"names":[],"mappings":"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"}
@@ -78,6 +78,13 @@
78
78
  "modified": {
79
79
  "description": "Last-modified date (ISO 8601), overriding what git history or the filesystem reports.",
80
80
  "type": "string"
81
+ },
82
+ "documents": {
83
+ "description": "Repository paths this page is about. Read by `refrakt stale` and the `refrakt.stale` MCP tool to rank documentation against the code it describes, and to answer \"I am about to change these files — what documents them?\". Unlike a review marker this does not decay: it names the page's subject, which survives every edit to the code. Paths are repo-root-relative POSIX; one that resolves to no file is reported as an error, because the author asserted the relationship. Does not cascade from a `_layout.md`.",
84
+ "type": "array",
85
+ "items": {
86
+ "type": "string"
87
+ }
81
88
  }
82
89
  }
83
90
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@refrakt-md/content",
3
3
  "description": "Content loading and transformation pipeline",
4
- "version": "0.35.0",
4
+ "version": "0.37.0",
5
5
  "type": "module",
6
6
  "license": "MIT",
7
7
  "repository": {
@@ -20,6 +20,10 @@
20
20
  ".": {
21
21
  "types": "./dist/index.d.ts",
22
22
  "default": "./dist/index.js"
23
+ },
24
+ "./edges": {
25
+ "types": "./dist/edges/index.d.ts",
26
+ "default": "./dist/edges/index.js"
23
27
  }
24
28
  },
25
29
  "files": [
@@ -30,10 +34,10 @@
30
34
  "build": "tsc"
31
35
  },
32
36
  "dependencies": {
33
- "@refrakt-md/highlight": "0.35.0",
34
- "@refrakt-md/runes": "0.35.0",
35
- "@refrakt-md/transform": "0.35.0",
36
- "@refrakt-md/types": "0.35.0",
37
+ "@refrakt-md/highlight": "0.37.0",
38
+ "@refrakt-md/runes": "0.37.0",
39
+ "@refrakt-md/transform": "0.37.0",
40
+ "@refrakt-md/types": "0.37.0",
37
41
  "@markdoc/markdoc": "0.4.0",
38
42
  "yaml": "^2.4.0"
39
43
  }