@casoon/astro-post-audit 0.2.0 → 0.2.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/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 +91 -9
- package/dist/integration.d.ts.map +1 -1
- package/dist/integration.js +10 -52
- package/dist/integration.test.js +1 -67
- 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,190 @@
|
|
|
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;
|
|
82
152
|
};
|
|
153
|
+
/** Hreflang checks for multilingual sites. */
|
|
83
154
|
hreflang?: {
|
|
155
|
+
/** Enable hreflang link checks. @default false */
|
|
84
156
|
check_hreflang?: boolean;
|
|
157
|
+
/** Require an `x-default` hreflang entry. @default false */
|
|
85
158
|
require_x_default?: boolean;
|
|
159
|
+
/** Hreflang must include a self-referencing entry. @default false */
|
|
86
160
|
require_self_reference?: boolean;
|
|
161
|
+
/** Hreflang links must be reciprocal (A→B and B→A). @default false */
|
|
87
162
|
require_reciprocal?: boolean;
|
|
88
163
|
};
|
|
164
|
+
/** Security heuristic checks. Enable via `checkSecurity` option or set fields here. */
|
|
89
165
|
security?: {
|
|
166
|
+
/** Warn on `target="_blank"` without `rel="noopener"`. @default true */
|
|
90
167
|
check_target_blank?: boolean;
|
|
168
|
+
/** Warn on `http://` resource URLs (mixed content). @default true */
|
|
91
169
|
check_mixed_content?: boolean;
|
|
170
|
+
/** Warn on inline `<script>` tags. @default false */
|
|
92
171
|
warn_inline_scripts?: boolean;
|
|
93
172
|
};
|
|
173
|
+
/** Duplicate content detection. Enable via `checkDuplicates` option or set fields here. */
|
|
94
174
|
content_quality?: {
|
|
175
|
+
/** Warn if multiple pages share the same `<title>`. @default false */
|
|
95
176
|
detect_duplicate_titles?: boolean;
|
|
177
|
+
/** Warn if multiple pages share the same meta description. @default false */
|
|
96
178
|
detect_duplicate_descriptions?: boolean;
|
|
179
|
+
/** Warn if multiple pages share the same `<h1>`. @default false */
|
|
97
180
|
detect_duplicate_h1?: boolean;
|
|
181
|
+
/** Warn if pages have identical content (by hash). @default false */
|
|
98
182
|
detect_duplicate_pages?: boolean;
|
|
99
183
|
};
|
|
100
|
-
/**
|
|
184
|
+
/**
|
|
185
|
+
* Override severity per rule ID.
|
|
186
|
+
* @example `{ "html/title-too-long": "off", "a11y/img-alt-missing": "error" }`
|
|
187
|
+
*/
|
|
101
188
|
severity?: Record<string, 'error' | 'warning' | 'info' | 'off'>;
|
|
102
189
|
/** @deprecated Not yet implemented — will be ignored. */
|
|
103
190
|
external_links?: {
|
|
@@ -110,9 +197,9 @@ export interface RulesConfig {
|
|
|
110
197
|
};
|
|
111
198
|
}
|
|
112
199
|
export interface PostAuditOptions {
|
|
113
|
-
/** Path to
|
|
200
|
+
/** Path to a TOML config file. Mutually exclusive with `rules`. */
|
|
114
201
|
config?: string;
|
|
115
|
-
/** Inline rules config
|
|
202
|
+
/** Inline rules config. Mutually exclusive with `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';
|
|
@@ -53,7 +22,7 @@ export default function postAudit(options = {}) {
|
|
|
53
22
|
// Validate mutual exclusion: config and rules cannot both be set
|
|
54
23
|
if (options.config && options.rules) {
|
|
55
24
|
throw new Error('astro-post-audit: "config" and "rules" are mutually exclusive. ' +
|
|
56
|
-
'Use "config" to point to a
|
|
25
|
+
'Use "config" to point to a config file, OR use "rules" to provide inline config — not both.');
|
|
57
26
|
}
|
|
58
27
|
// Validate that rules is a non-empty object if provided
|
|
59
28
|
if (options.rules && typeof options.rules === 'object' && Object.keys(options.rules).length === 0) {
|
|
@@ -101,20 +70,21 @@ export default function postAudit(options = {}) {
|
|
|
101
70
|
args.push('--exclude', pattern);
|
|
102
71
|
}
|
|
103
72
|
}
|
|
104
|
-
// Config: explicit file path OR
|
|
105
|
-
let
|
|
73
|
+
// Config: explicit file path OR pipe inline rules via stdin
|
|
74
|
+
let stdinInput;
|
|
106
75
|
if (options.config) {
|
|
107
76
|
args.push('--config', options.config);
|
|
108
77
|
}
|
|
109
78
|
else if (options.rules) {
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
writeFileSync(tempConfigPath, rulesToToml(options.rules), 'utf-8');
|
|
113
|
-
args.push('--config', tempConfigPath);
|
|
79
|
+
args.push('--config-stdin');
|
|
80
|
+
stdinInput = JSON.stringify(options.rules);
|
|
114
81
|
}
|
|
115
82
|
logger.info('Running post-build audit...');
|
|
116
83
|
try {
|
|
117
|
-
execFileSync(binaryPath, args, {
|
|
84
|
+
execFileSync(binaryPath, args, {
|
|
85
|
+
stdio: stdinInput ? ['pipe', 'inherit', 'inherit'] : 'inherit',
|
|
86
|
+
input: stdinInput,
|
|
87
|
+
});
|
|
118
88
|
logger.info('All checks passed!');
|
|
119
89
|
}
|
|
120
90
|
catch (err) {
|
|
@@ -131,18 +101,6 @@ export default function postAudit(options = {}) {
|
|
|
131
101
|
logger.error(`Audit failed with exit code ${exitCode ?? 'unknown'}`);
|
|
132
102
|
}
|
|
133
103
|
}
|
|
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
104
|
},
|
|
147
105
|
},
|
|
148
106
|
};
|
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
|
// ==========================================================================
|