@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 +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/integration.d.ts +92 -10
- package/dist/integration.d.ts.map +1 -1
- package/dist/integration.js +10 -60
- package/dist/integration.test.js +1 -98
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
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,OAAO,EAAE,
|
|
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
|
|
1
|
+
export { default } from './integration.js';
|
package/dist/integration.d.ts
CHANGED
|
@@ -1,103 +1,192 @@
|
|
|
1
1
|
import type { AstroIntegration } from 'astro';
|
|
2
2
|
/**
|
|
3
|
-
* Inline rules config that mirrors the Rust
|
|
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
|
-
/**
|
|
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
|
-
/**
|
|
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;
|
|
1
|
+
{"version":3,"file":"integration.d.ts","sourceRoot":"","sources":["../src/integration.ts"],"names":[],"mappings":"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"}
|
package/dist/integration.js
CHANGED
|
@@ -1,38 +1,7 @@
|
|
|
1
1
|
import { execFileSync } from 'node:child_process';
|
|
2
|
-
import { existsSync
|
|
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
|
-
//
|
|
105
|
-
let
|
|
106
|
-
if (options.
|
|
107
|
-
args.push('--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, {
|
|
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
|
};
|
package/dist/integration.test.js
CHANGED
|
@@ -1,72 +1,6 @@
|
|
|
1
1
|
import { describe, it } from 'node:test';
|
|
2
2
|
import assert from 'node:assert/strict';
|
|
3
|
-
import postAudit
|
|
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 } },
|