@casoon/astro-post-audit 0.2.0 → 0.2.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/dist/index.d.ts CHANGED
@@ -1,3 +1,3 @@
1
- export { default, rulesToToml } from './integration.js';
1
+ export { default } from './integration.js';
2
2
  export type { PostAuditOptions, RulesConfig } from './integration.js';
3
3
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AACxD,YAAY,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAC3C,YAAY,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC"}
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- export { default, rulesToToml } from './integration.js';
1
+ export { default } from './integration.js';
@@ -1,103 +1,192 @@
1
1
  import type { AstroIntegration } from 'astro';
2
2
  /**
3
- * Inline rules config that mirrors the Rust rules.toml structure.
3
+ * Inline rules config that mirrors the Rust config structure.
4
4
  * All sections and fields are optional — only set what you want to override.
5
5
  */
6
6
  export interface RulesConfig {
7
+ /** Site-level settings. */
7
8
  site?: {
9
+ /** Base URL for canonical/sitemap checks. Also settable via `site` option or Astro's `site` config. */
8
10
  base_url?: string;
9
11
  };
12
+ /** File filters — glob patterns to include or exclude pages from all checks. */
13
+ filters?: {
14
+ /** Only check files matching these glob patterns. Merged with the top-level `include` option. */
15
+ include?: string[];
16
+ /** Skip files matching these glob patterns (e.g. `["404.html", "drafts/**"]`). Merged with the top-level `exclude` option. */
17
+ exclude?: string[];
18
+ };
19
+ /** URL normalization rules for internal link and canonical consistency. */
10
20
  url_normalization?: {
21
+ /** Trailing slash policy. `"always"`: require trailing slash, `"never"`: forbid, `"ignore"`: no check. @default "always" */
11
22
  trailing_slash?: 'always' | 'never' | 'ignore';
23
+ /** Whether `index.html` in URLs is allowed. `"forbid"`: warn on `/page/index.html` links, `"allow"`: permit them. @default "forbid" */
12
24
  index_html?: 'forbid' | 'allow';
13
25
  };
26
+ /** Canonical `<link rel="canonical">` tag checks. */
14
27
  canonical?: {
28
+ /** Every page must have a canonical tag. @default true */
15
29
  require?: boolean;
30
+ /** Canonical URL must be absolute (not relative). @default true */
16
31
  absolute?: boolean;
32
+ /** Canonical must point to the same origin as `site`. @default true */
17
33
  same_origin?: boolean;
34
+ /** Canonical must be a self-reference (point to the page itself). @default false */
18
35
  self_reference?: boolean;
19
36
  };
37
+ /** Robots meta tag checks. */
20
38
  robots_meta?: {
39
+ /** Don't warn on pages with `noindex`. @default true */
21
40
  allow_noindex?: boolean;
41
+ /** Treat any `noindex` page as an error. @default false */
22
42
  fail_if_noindex?: boolean;
23
43
  };
44
+ /** Internal link consistency checks. */
24
45
  links?: {
46
+ /** Check that internal links resolve to existing pages. @default true */
25
47
  check_internal?: boolean;
48
+ /** Broken internal links are errors (not just warnings). @default true */
26
49
  fail_on_broken?: boolean;
50
+ /** Warn on query parameters (`?foo=bar`) in internal links. @default true */
27
51
  forbid_query_params_internal?: boolean;
52
+ /** Validate that `#fragment` targets exist in the linked page. @default false */
28
53
  check_fragments?: boolean;
54
+ /** Warn about pages with no incoming internal links (orphan pages). @default false */
29
55
  detect_orphan_pages?: boolean;
56
+ /** Warn on `http://` in internal links (mixed content). @default true */
30
57
  check_mixed_content?: boolean;
31
58
  };
59
+ /** Sitemap cross-reference checks. */
32
60
  sitemap?: {
61
+ /** `sitemap.xml` must exist in `dist/`. @default false */
33
62
  require?: boolean;
63
+ /** Canonical URLs should appear in the sitemap. @default true */
34
64
  canonical_must_be_in_sitemap?: boolean;
65
+ /** Sitemap must not contain non-canonical URLs. @default false */
35
66
  forbid_noncanonical_in_sitemap?: boolean;
67
+ /** Every sitemap URL must correspond to a page in `dist/`. @default true */
36
68
  entries_must_exist_in_dist?: boolean;
37
69
  };
70
+ /** `robots.txt` file checks. */
38
71
  robots_txt?: {
72
+ /** `robots.txt` must exist. @default false */
39
73
  require?: boolean;
74
+ /** `robots.txt` must contain a link to the sitemap. @default false */
40
75
  require_sitemap_link?: boolean;
41
76
  };
77
+ /** Basic HTML structure checks. */
42
78
  html_basics?: {
79
+ /** `<html lang="...">` attribute is required. @default true */
43
80
  lang_attr_required?: boolean;
81
+ /** `<title>` tag is required and must be non-empty. @default true */
44
82
  title_required?: boolean;
83
+ /** `<meta name="description">` is required. @default false */
45
84
  meta_description_required?: boolean;
85
+ /** `<meta name="viewport">` is required. @default true */
46
86
  viewport_required?: boolean;
87
+ /** Warn if `<title>` exceeds this character length. @default 60 */
47
88
  title_max_length?: number;
89
+ /** Warn if meta description exceeds this character length. @default 160 */
48
90
  meta_description_max_length?: number;
49
91
  };
92
+ /** Heading hierarchy checks. */
50
93
  headings?: {
94
+ /** Page must have at least one `<h1>`. @default true */
51
95
  require_h1?: boolean;
96
+ /** Only one `<h1>` per page. @default true */
52
97
  single_h1?: boolean;
98
+ /** No heading level gaps (e.g. `<h2>` followed by `<h4>`). @default false */
53
99
  no_skip?: boolean;
54
100
  };
101
+ /** Accessibility (a11y) heuristics — static checks, no layout computation. */
55
102
  a11y?: {
103
+ /** `<img>` elements must have an `alt` attribute. @default true */
56
104
  img_alt_required?: boolean;
105
+ /** Allow images with `role="presentation"` or `aria-hidden="true"` to skip `alt`. @default true */
57
106
  allow_decorative_images?: boolean;
107
+ /** `<a>` elements must have an accessible name (text, `aria-label`, or `aria-labelledby`). @default true */
58
108
  a_accessible_name_required?: boolean;
109
+ /** `<button>` elements must have an accessible name. @default true */
59
110
  button_name_required?: boolean;
111
+ /** Form controls must have an associated `<label>`. @default true */
60
112
  label_for_required?: boolean;
113
+ /** Warn on generic link text like "click here", "mehr", "weiter". @default true */
61
114
  warn_generic_link_text?: boolean;
115
+ /** Warn if `aria-hidden="true"` is set on a focusable element. @default true */
62
116
  aria_hidden_focusable_check?: boolean;
117
+ /** Require a skip navigation link (e.g. `<a href="#main-content">`). @default false */
63
118
  require_skip_link?: boolean;
64
119
  };
120
+ /** Asset reference and size checks. Enable via `checkAssets` option or set fields here. */
65
121
  assets?: {
122
+ /** Check that `<img>`, `<script>`, `<link>` references resolve to files in `dist/`. @default false */
66
123
  check_broken_assets?: boolean;
124
+ /** Warn if `<img>` is missing `width`/`height` attributes (CLS prevention). @default false */
67
125
  check_image_dimensions?: boolean;
126
+ /** Warn if any image file exceeds this size in KB. Off by default. */
68
127
  max_image_size_kb?: number;
128
+ /** Warn if any JS file exceeds this size in KB. Off by default. */
69
129
  max_js_size_kb?: number;
130
+ /** Warn if any CSS file exceeds this size in KB. Off by default. */
70
131
  max_css_size_kb?: number;
132
+ /** Warn if asset filenames lack a cache-busting hash. @default false */
71
133
  require_hashed_filenames?: boolean;
72
134
  };
135
+ /** Open Graph and Twitter Card meta tag checks. */
73
136
  opengraph?: {
137
+ /** Require `og:title` meta tag. @default false */
74
138
  require_og_title?: boolean;
139
+ /** Require `og:description` meta tag. @default false */
75
140
  require_og_description?: boolean;
141
+ /** Require `og:image` meta tag. @default false */
76
142
  require_og_image?: boolean;
143
+ /** Require `twitter:card` meta tag. @default false */
77
144
  require_twitter_card?: boolean;
78
145
  };
146
+ /** Structured data (JSON-LD) validation. Enable via `checkStructuredData` option or set fields here. */
79
147
  structured_data?: {
148
+ /** Validate JSON-LD syntax and semantics (`@context`, `@type`, required properties). @default false */
80
149
  check_json_ld?: boolean;
150
+ /** Every page must contain at least one JSON-LD block. @default false */
81
151
  require_json_ld?: boolean;
152
+ /** Warn if a page has multiple JSON-LD blocks with the same `@type`. @default false */
153
+ detect_duplicate_types?: boolean;
82
154
  };
155
+ /** Hreflang checks for multilingual sites. */
83
156
  hreflang?: {
157
+ /** Enable hreflang link checks. @default false */
84
158
  check_hreflang?: boolean;
159
+ /** Require an `x-default` hreflang entry. @default false */
85
160
  require_x_default?: boolean;
161
+ /** Hreflang must include a self-referencing entry. @default false */
86
162
  require_self_reference?: boolean;
163
+ /** Hreflang links must be reciprocal (A→B and B→A). @default false */
87
164
  require_reciprocal?: boolean;
88
165
  };
166
+ /** Security heuristic checks. Enable via `checkSecurity` option or set fields here. */
89
167
  security?: {
168
+ /** Warn on `target="_blank"` without `rel="noopener"`. @default true */
90
169
  check_target_blank?: boolean;
170
+ /** Warn on `http://` resource URLs (mixed content). @default true */
91
171
  check_mixed_content?: boolean;
172
+ /** Warn on inline `<script>` tags. @default false */
92
173
  warn_inline_scripts?: boolean;
93
174
  };
175
+ /** Duplicate content detection. Enable via `checkDuplicates` option or set fields here. */
94
176
  content_quality?: {
177
+ /** Warn if multiple pages share the same `<title>`. @default false */
95
178
  detect_duplicate_titles?: boolean;
179
+ /** Warn if multiple pages share the same meta description. @default false */
96
180
  detect_duplicate_descriptions?: boolean;
181
+ /** Warn if multiple pages share the same `<h1>`. @default false */
97
182
  detect_duplicate_h1?: boolean;
183
+ /** Warn if pages have identical content (by hash). @default false */
98
184
  detect_duplicate_pages?: boolean;
99
185
  };
100
- /** Custom severity overrides per rule ID. Maps rule IDs to 'error' | 'warning' | 'info' | 'off'. */
186
+ /**
187
+ * Override severity per rule ID.
188
+ * @example `{ "html/title-too-long": "off", "a11y/img-alt-missing": "error" }`
189
+ */
101
190
  severity?: Record<string, 'error' | 'warning' | 'info' | 'off'>;
102
191
  /** @deprecated Not yet implemented — will be ignored. */
103
192
  external_links?: {
@@ -110,9 +199,7 @@ export interface RulesConfig {
110
199
  };
111
200
  }
112
201
  export interface PostAuditOptions {
113
- /** Path to rules.toml config file. Mutually exclusive with `rules`. */
114
- config?: string;
115
- /** Inline rules config (generates a temporary rules.toml). Mutually exclusive with `config`. */
202
+ /** Inline rules config. */
116
203
  rules?: RulesConfig;
117
204
  /** Base URL (auto-detected from Astro's `site` config if not set) */
118
205
  site?: string;
@@ -143,10 +230,5 @@ export interface PostAuditOptions {
143
230
  /** Throw an AstroError when the audit finds errors (fails the build). Default: false */
144
231
  throwOnError?: boolean;
145
232
  }
146
- /**
147
- * Serialize a RulesConfig object to TOML format.
148
- * @internal Exported for testing only.
149
- */
150
- export declare function rulesToToml(rules: RulesConfig): string;
151
233
  export default function postAudit(options?: PostAuditOptions): AstroIntegration;
152
234
  //# sourceMappingURL=integration.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"integration.d.ts","sourceRoot":"","sources":["../src/integration.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,OAAO,CAAC;AAO9C;;;GAGG;AACH,MAAM,WAAW,WAAW;IAC1B,IAAI,CAAC,EAAE;QAAE,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAC7B,iBAAiB,CAAC,EAAE;QAClB,cAAc,CAAC,EAAE,QAAQ,GAAG,OAAO,GAAG,QAAQ,CAAC;QAC/C,UAAU,CAAC,EAAE,QAAQ,GAAG,OAAO,CAAC;KACjC,CAAC;IACF,SAAS,CAAC,EAAE;QACV,OAAO,CAAC,EAAE,OAAO,CAAC;QAClB,QAAQ,CAAC,EAAE,OAAO,CAAC;QACnB,WAAW,CAAC,EAAE,OAAO,CAAC;QACtB,cAAc,CAAC,EAAE,OAAO,CAAC;KAC1B,CAAC;IACF,WAAW,CAAC,EAAE;QACZ,aAAa,CAAC,EAAE,OAAO,CAAC;QACxB,eAAe,CAAC,EAAE,OAAO,CAAC;KAC3B,CAAC;IACF,KAAK,CAAC,EAAE;QACN,cAAc,CAAC,EAAE,OAAO,CAAC;QACzB,cAAc,CAAC,EAAE,OAAO,CAAC;QACzB,4BAA4B,CAAC,EAAE,OAAO,CAAC;QACvC,eAAe,CAAC,EAAE,OAAO,CAAC;QAC1B,mBAAmB,CAAC,EAAE,OAAO,CAAC;QAC9B,mBAAmB,CAAC,EAAE,OAAO,CAAC;KAC/B,CAAC;IACF,OAAO,CAAC,EAAE;QACR,OAAO,CAAC,EAAE,OAAO,CAAC;QAClB,4BAA4B,CAAC,EAAE,OAAO,CAAC;QACvC,8BAA8B,CAAC,EAAE,OAAO,CAAC;QACzC,0BAA0B,CAAC,EAAE,OAAO,CAAC;KACtC,CAAC;IACF,UAAU,CAAC,EAAE;QACX,OAAO,CAAC,EAAE,OAAO,CAAC;QAClB,oBAAoB,CAAC,EAAE,OAAO,CAAC;KAChC,CAAC;IACF,WAAW,CAAC,EAAE;QACZ,kBAAkB,CAAC,EAAE,OAAO,CAAC;QAC7B,cAAc,CAAC,EAAE,OAAO,CAAC;QACzB,yBAAyB,CAAC,EAAE,OAAO,CAAC;QACpC,iBAAiB,CAAC,EAAE,OAAO,CAAC;QAC5B,gBAAgB,CAAC,EAAE,MAAM,CAAC;QAC1B,2BAA2B,CAAC,EAAE,MAAM,CAAC;KACtC,CAAC;IACF,QAAQ,CAAC,EAAE;QACT,UAAU,CAAC,EAAE,OAAO,CAAC;QACrB,SAAS,CAAC,EAAE,OAAO,CAAC;QACpB,OAAO,CAAC,EAAE,OAAO,CAAC;KACnB,CAAC;IACF,IAAI,CAAC,EAAE;QACL,gBAAgB,CAAC,EAAE,OAAO,CAAC;QAC3B,uBAAuB,CAAC,EAAE,OAAO,CAAC;QAClC,0BAA0B,CAAC,EAAE,OAAO,CAAC;QACrC,oBAAoB,CAAC,EAAE,OAAO,CAAC;QAC/B,kBAAkB,CAAC,EAAE,OAAO,CAAC;QAC7B,sBAAsB,CAAC,EAAE,OAAO,CAAC;QACjC,2BAA2B,CAAC,EAAE,OAAO,CAAC;QACtC,iBAAiB,CAAC,EAAE,OAAO,CAAC;KAC7B,CAAC;IACF,MAAM,CAAC,EAAE;QACP,mBAAmB,CAAC,EAAE,OAAO,CAAC;QAC9B,sBAAsB,CAAC,EAAE,OAAO,CAAC;QACjC,iBAAiB,CAAC,EAAE,MAAM,CAAC;QAC3B,cAAc,CAAC,EAAE,MAAM,CAAC;QACxB,eAAe,CAAC,EAAE,MAAM,CAAC;QACzB,wBAAwB,CAAC,EAAE,OAAO,CAAC;KACpC,CAAC;IACF,SAAS,CAAC,EAAE;QACV,gBAAgB,CAAC,EAAE,OAAO,CAAC;QAC3B,sBAAsB,CAAC,EAAE,OAAO,CAAC;QACjC,gBAAgB,CAAC,EAAE,OAAO,CAAC;QAC3B,oBAAoB,CAAC,EAAE,OAAO,CAAC;KAChC,CAAC;IACF,eAAe,CAAC,EAAE;QAChB,aAAa,CAAC,EAAE,OAAO,CAAC;QACxB,eAAe,CAAC,EAAE,OAAO,CAAC;KAC3B,CAAC;IACF,QAAQ,CAAC,EAAE;QACT,cAAc,CAAC,EAAE,OAAO,CAAC;QACzB,iBAAiB,CAAC,EAAE,OAAO,CAAC;QAC5B,sBAAsB,CAAC,EAAE,OAAO,CAAC;QACjC,kBAAkB,CAAC,EAAE,OAAO,CAAC;KAC9B,CAAC;IACF,QAAQ,CAAC,EAAE;QACT,kBAAkB,CAAC,EAAE,OAAO,CAAC;QAC7B,mBAAmB,CAAC,EAAE,OAAO,CAAC;QAC9B,mBAAmB,CAAC,EAAE,OAAO,CAAC;KAC/B,CAAC;IACF,eAAe,CAAC,EAAE;QAChB,uBAAuB,CAAC,EAAE,OAAO,CAAC;QAClC,6BAA6B,CAAC,EAAE,OAAO,CAAC;QACxC,mBAAmB,CAAC,EAAE,OAAO,CAAC;QAC9B,sBAAsB,CAAC,EAAE,OAAO,CAAC;KAClC,CAAC;IACF,oGAAoG;IACpG,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,GAAG,SAAS,GAAG,MAAM,GAAG,KAAK,CAAC,CAAC;IAChE,yDAAyD;IACzD,cAAc,CAAC,EAAE;QACf,OAAO,CAAC,EAAE,OAAO,CAAC;QAClB,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,cAAc,CAAC,EAAE,MAAM,CAAC;QACxB,cAAc,CAAC,EAAE,OAAO,CAAC;QACzB,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;QACzB,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;KAC1B,CAAC;CACH;AAED,MAAM,WAAW,gBAAgB;IAC/B,uEAAuE;IACvE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,gGAAgG;IAChG,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB,qEAAqE;IACrE,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,+BAA+B;IAC/B,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,oBAAoB;IACpB,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACzB,+CAA+C;IAC/C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,+BAA+B;IAC/B,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,+BAA+B;IAC/B,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,8BAA8B;IAC9B,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,sCAAsC;IACtC,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,kDAAkD;IAClD,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,uCAAuC;IACvC,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,yCAAyC;IACzC,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,8DAA8D;IAC9D,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,oDAAoD;IACpD,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,wFAAwF;IACxF,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,WAAW,GAAG,MAAM,CAuBtD;AAUD,MAAM,CAAC,OAAO,UAAU,SAAS,CAAC,OAAO,GAAE,gBAAqB,GAAG,gBAAgB,CAgHlF"}
1
+ {"version":3,"file":"integration.d.ts","sourceRoot":"","sources":["../src/integration.ts"],"names":[],"mappings":"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"}
@@ -1,38 +1,7 @@
1
1
  import { execFileSync } from 'node:child_process';
2
- import { existsSync, mkdtempSync, writeFileSync, unlinkSync, rmdirSync } from 'node:fs';
2
+ import { existsSync } from 'node:fs';
3
3
  import { dirname, join } from 'node:path';
4
- import { tmpdir } from 'node:os';
5
4
  import { fileURLToPath } from 'node:url';
6
- /**
7
- * Serialize a RulesConfig object to TOML format.
8
- * @internal Exported for testing only.
9
- */
10
- export function rulesToToml(rules) {
11
- const lines = [];
12
- for (const [section, values] of Object.entries(rules)) {
13
- if (values == null || typeof values !== 'object')
14
- continue;
15
- lines.push(`[${section}]`);
16
- for (const [key, val] of Object.entries(values)) {
17
- if (val === undefined)
18
- continue;
19
- // Quote keys that contain special chars (e.g. rule IDs like "html/lang-missing")
20
- const tomlKey = /^[a-zA-Z0-9_-]+$/.test(key) ? key : `"${key}"`;
21
- if (typeof val === 'string') {
22
- lines.push(`${tomlKey} = "${val}"`);
23
- }
24
- else if (Array.isArray(val)) {
25
- const items = val.map((v) => `"${v}"`).join(', ');
26
- lines.push(`${tomlKey} = [${items}]`);
27
- }
28
- else {
29
- lines.push(`${tomlKey} = ${val}`);
30
- }
31
- }
32
- lines.push('');
33
- }
34
- return lines.join('\n');
35
- }
36
5
  function resolveBinaryPath() {
37
6
  const binDir = join(dirname(fileURLToPath(import.meta.url)), '..', 'bin');
38
7
  const binaryName = process.platform === 'win32' ? 'astro-post-audit.exe' : 'astro-post-audit';
@@ -50,11 +19,6 @@ export default function postAudit(options = {}) {
50
19
  'astro:build:done': ({ dir, logger }) => {
51
20
  if (options.disable)
52
21
  return;
53
- // Validate mutual exclusion: config and rules cannot both be set
54
- if (options.config && options.rules) {
55
- throw new Error('astro-post-audit: "config" and "rules" are mutually exclusive. ' +
56
- 'Use "config" to point to a rules.toml file, OR use "rules" to provide inline config — not both.');
57
- }
58
22
  // Validate that rules is a non-empty object if provided
59
23
  if (options.rules && typeof options.rules === 'object' && Object.keys(options.rules).length === 0) {
60
24
  logger.warn('astro-post-audit: "rules" is an empty object — using default config.');
@@ -101,20 +65,18 @@ export default function postAudit(options = {}) {
101
65
  args.push('--exclude', pattern);
102
66
  }
103
67
  }
104
- // Config: explicit file path OR generate temp from inline rules
105
- let tempConfigPath;
106
- if (options.config) {
107
- args.push('--config', options.config);
108
- }
109
- else if (options.rules) {
110
- const tempDir = mkdtempSync(join(tmpdir(), 'astro-post-audit-'));
111
- tempConfigPath = join(tempDir, 'rules.toml');
112
- writeFileSync(tempConfigPath, rulesToToml(options.rules), 'utf-8');
113
- args.push('--config', tempConfigPath);
68
+ // Pipe inline rules config via stdin as JSON
69
+ let stdinInput;
70
+ if (options.rules) {
71
+ args.push('--config-stdin');
72
+ stdinInput = JSON.stringify(options.rules);
114
73
  }
115
74
  logger.info('Running post-build audit...');
116
75
  try {
117
- execFileSync(binaryPath, args, { stdio: 'inherit' });
76
+ execFileSync(binaryPath, args, {
77
+ stdio: stdinInput ? ['pipe', 'inherit', 'inherit'] : 'inherit',
78
+ input: stdinInput,
79
+ });
118
80
  logger.info('All checks passed!');
119
81
  }
120
82
  catch (err) {
@@ -131,18 +93,6 @@ export default function postAudit(options = {}) {
131
93
  logger.error(`Audit failed with exit code ${exitCode ?? 'unknown'}`);
132
94
  }
133
95
  }
134
- finally {
135
- // Clean up temp config
136
- if (tempConfigPath) {
137
- try {
138
- unlinkSync(tempConfigPath);
139
- rmdirSync(dirname(tempConfigPath));
140
- }
141
- catch {
142
- // ignore cleanup errors
143
- }
144
- }
145
- }
146
96
  },
147
97
  },
148
98
  };
@@ -1,72 +1,6 @@
1
1
  import { describe, it } from 'node:test';
2
2
  import assert from 'node:assert/strict';
3
- import postAudit, { rulesToToml } from './integration.js';
4
- // ==========================================================================
5
- // rulesToToml serialization
6
- // ==========================================================================
7
- describe('rulesToToml', () => {
8
- it('serializes boolean values', () => {
9
- const rules = {
10
- canonical: { require: true, absolute: false },
11
- };
12
- const toml = rulesToToml(rules);
13
- assert.ok(toml.includes('[canonical]'));
14
- assert.ok(toml.includes('require = true'));
15
- assert.ok(toml.includes('absolute = false'));
16
- });
17
- it('serializes string values with quotes', () => {
18
- const rules = {
19
- url_normalization: { trailing_slash: 'always', index_html: 'forbid' },
20
- };
21
- const toml = rulesToToml(rules);
22
- assert.ok(toml.includes('[url_normalization]'));
23
- assert.ok(toml.includes('trailing_slash = "always"'));
24
- assert.ok(toml.includes('index_html = "forbid"'));
25
- });
26
- it('serializes numeric values', () => {
27
- const rules = {
28
- html_basics: { title_max_length: 60, meta_description_max_length: 160 },
29
- };
30
- const toml = rulesToToml(rules);
31
- assert.ok(toml.includes('title_max_length = 60'));
32
- assert.ok(toml.includes('meta_description_max_length = 160'));
33
- });
34
- it('serializes array values', () => {
35
- const rules = {
36
- external_links: {
37
- allow_domains: ['example.com', 'test.org'],
38
- },
39
- };
40
- const toml = rulesToToml(rules);
41
- assert.ok(toml.includes('[external_links]'));
42
- assert.ok(toml.includes('allow_domains = ["example.com", "test.org"]'));
43
- });
44
- it('skips undefined values', () => {
45
- const rules = {
46
- canonical: { require: true },
47
- };
48
- const toml = rulesToToml(rules);
49
- // Only 'require' should be present, not 'absolute', 'same_origin', 'self_reference'
50
- assert.ok(toml.includes('require = true'));
51
- assert.ok(!toml.includes('absolute'));
52
- assert.ok(!toml.includes('same_origin'));
53
- });
54
- it('handles empty rules', () => {
55
- const toml = rulesToToml({});
56
- assert.equal(toml, '');
57
- });
58
- it('handles multiple sections', () => {
59
- const rules = {
60
- canonical: { require: true },
61
- headings: { require_h1: true, single_h1: false },
62
- };
63
- const toml = rulesToToml(rules);
64
- assert.ok(toml.includes('[canonical]'));
65
- assert.ok(toml.includes('[headings]'));
66
- assert.ok(toml.includes('require_h1 = true'));
67
- assert.ok(toml.includes('single_h1 = false'));
68
- });
69
- });
3
+ import postAudit from './integration.js';
70
4
  // ==========================================================================
71
5
  // postAudit integration factory
72
6
  // ==========================================================================
@@ -99,37 +33,6 @@ describe('postAudit', () => {
99
33
  const integration = postAudit(options);
100
34
  assert.equal(integration.name, 'astro-post-audit');
101
35
  });
102
- it('throws when both config and rules are set', () => {
103
- const integration = postAudit({
104
- config: '/path/to/rules.toml',
105
- rules: { canonical: { require: true } },
106
- });
107
- // Simulate astro:build:done hook
108
- const hook = integration.hooks['astro:build:done'];
109
- assert.throws(() => hook({
110
- dir: new URL('file:///tmp/dist/'),
111
- logger: {
112
- info: () => { },
113
- warn: () => { },
114
- error: () => { },
115
- },
116
- }), {
117
- message: /mutually exclusive/,
118
- });
119
- });
120
- it('does not throw when only config is set', () => {
121
- const integration = postAudit({ config: '/path/to/rules.toml' });
122
- const hook = integration.hooks['astro:build:done'];
123
- // Should not throw (will just warn about missing binary)
124
- assert.doesNotThrow(() => hook({
125
- dir: new URL('file:///tmp/dist/'),
126
- logger: {
127
- info: () => { },
128
- warn: () => { },
129
- error: () => { },
130
- },
131
- }));
132
- });
133
36
  it('does not throw when only rules is set', () => {
134
37
  const integration = postAudit({
135
38
  rules: { canonical: { require: true } },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@casoon/astro-post-audit",
3
- "version": "0.2.0",
3
+ "version": "0.2.2",
4
4
  "description": "Astro integration for post-build auditing: SEO, links, and lightweight WCAG checks",
5
5
  "license": "MIT",
6
6
  "type": "module",