@aexol/spectral 0.9.126 → 0.9.128
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/agent/index.d.ts.map +1 -1
- package/dist/agent/index.js +5 -0
- package/dist/extensions/seo/analyzers/content.d.ts +29 -6
- package/dist/extensions/seo/analyzers/content.d.ts.map +1 -1
- package/dist/extensions/seo/analyzers/content.js +243 -8
- package/dist/extensions/seo/analyzers/crawler.d.ts.map +1 -1
- package/dist/extensions/seo/analyzers/crawler.js +133 -7
- package/dist/extensions/seo/analyzers/drift.d.ts.map +1 -1
- package/dist/extensions/seo/analyzers/drift.js +86 -29
- package/dist/extensions/seo/analyzers/images.d.ts +10 -4
- package/dist/extensions/seo/analyzers/images.d.ts.map +1 -1
- package/dist/extensions/seo/analyzers/images.js +153 -5
- package/dist/extensions/seo/analyzers/performance.d.ts +3 -3
- package/dist/extensions/seo/analyzers/performance.d.ts.map +1 -1
- package/dist/extensions/seo/analyzers/performance.js +77 -6
- package/dist/extensions/seo/analyzers/readability.d.ts.map +1 -1
- package/dist/extensions/seo/analyzers/readability.js +17 -9
- package/dist/extensions/seo/analyzers/schema.d.ts.map +1 -1
- package/dist/extensions/seo/analyzers/schema.js +99 -10
- package/dist/extensions/seo/analyzers/sitemap.d.ts.map +1 -1
- package/dist/extensions/seo/analyzers/sitemap.js +57 -16
- package/dist/extensions/seo/analyzers/technical.d.ts +0 -7
- package/dist/extensions/seo/analyzers/technical.d.ts.map +1 -1
- package/dist/extensions/seo/analyzers/technical.js +408 -37
- package/dist/extensions/seo/config.d.ts +2 -0
- package/dist/extensions/seo/config.d.ts.map +1 -1
- package/dist/extensions/seo/config.js +2 -0
- package/dist/extensions/seo/tools/batch.js +1 -1
- package/dist/extensions/seo/tools/content.d.ts.map +1 -1
- package/dist/extensions/seo/tools/content.js +5 -3
- package/dist/extensions/seo/tools/full-audit.d.ts +1 -1
- package/dist/extensions/seo/tools/full-audit.d.ts.map +1 -1
- package/dist/extensions/seo/tools/full-audit.js +391 -66
- package/dist/extensions/seo/tools/helpers.d.ts +15 -4
- package/dist/extensions/seo/tools/helpers.d.ts.map +1 -1
- package/dist/extensions/seo/tools/helpers.js +57 -6
- package/dist/extensions/seo/tools/performance.d.ts.map +1 -1
- package/dist/extensions/seo/tools/performance.js +17 -11
- package/dist/extensions/seo/tools/report.d.ts.map +1 -1
- package/dist/extensions/seo/tools/report.js +513 -47
- package/dist/extensions/seo/types.d.ts +295 -3
- package/dist/extensions/seo/types.d.ts.map +1 -1
- package/dist/extensions/seo/utils/fetcher.d.ts +4 -0
- package/dist/extensions/seo/utils/fetcher.d.ts.map +1 -1
- package/dist/extensions/seo/utils/fetcher.js +77 -11
- package/dist/extensions/seo/utils/parser.d.ts +3 -1
- package/dist/extensions/seo/utils/parser.d.ts.map +1 -1
- package/dist/extensions/seo/utils/parser.js +105 -25
- package/dist/extensions/seo/utils/renderer.d.ts +6 -1
- package/dist/extensions/seo/utils/renderer.d.ts.map +1 -1
- package/dist/extensions/seo/utils/renderer.js +207 -1
- package/dist/extensions/seo/utils/url-safety.d.ts.map +1 -1
- package/dist/extensions/seo/utils/url-safety.js +19 -3
- package/dist/extensions/web/tools/fetch.js +2 -2
- package/dist/memory/tools/compact-context.d.ts.map +1 -1
- package/dist/memory/tools/compact-context.js +10 -3
- package/dist/sdk/agent-core/agent-loop.d.ts.map +1 -1
- package/dist/sdk/agent-core/agent-loop.js +87 -4
- package/dist/sdk/agent-core/types.d.ts +1 -0
- package/dist/sdk/agent-core/types.d.ts.map +1 -1
- package/dist/sdk/ai/utils/validation.d.ts +0 -7
- package/dist/sdk/ai/utils/validation.d.ts.map +1 -1
- package/dist/sdk/ai/utils/validation.js +21 -1
- package/dist/sdk/coding-agent/core/extensions/runner.d.ts.map +1 -1
- package/dist/sdk/coding-agent/core/extensions/runner.js +15 -1
- package/dist/sdk/coding-agent/core/tools/apply-patch.d.ts +7 -2
- package/dist/sdk/coding-agent/core/tools/apply-patch.d.ts.map +1 -1
- package/dist/sdk/coding-agent/core/tools/apply-patch.js +219 -41
- package/dist/sdk/coding-agent/core/tools/atomic-write.d.ts +30 -0
- package/dist/sdk/coding-agent/core/tools/atomic-write.d.ts.map +1 -0
- package/dist/sdk/coding-agent/core/tools/atomic-write.js +42 -0
- package/dist/sdk/coding-agent/core/tools/edit-diff.d.ts +10 -4
- package/dist/sdk/coding-agent/core/tools/edit-diff.d.ts.map +1 -1
- package/dist/sdk/coding-agent/core/tools/edit-diff.js +44 -24
- package/dist/sdk/coding-agent/core/tools/edit.d.ts +6 -0
- package/dist/sdk/coding-agent/core/tools/edit.d.ts.map +1 -1
- package/dist/sdk/coding-agent/core/tools/edit.js +31 -5
- package/dist/sdk/coding-agent/core/tools/file-mutation-queue.d.ts +9 -3
- package/dist/sdk/coding-agent/core/tools/file-mutation-queue.d.ts.map +1 -1
- package/dist/sdk/coding-agent/core/tools/file-mutation-queue.js +42 -3
- package/dist/sdk/coding-agent/core/tools/read.d.ts.map +1 -1
- package/dist/sdk/coding-agent/core/tools/read.js +79 -47
- package/dist/sdk/coding-agent/core/tools/truncate.d.ts +4 -2
- package/dist/sdk/coding-agent/core/tools/truncate.d.ts.map +1 -1
- package/dist/sdk/coding-agent/core/tools/truncate.js +43 -23
- package/dist/sdk/coding-agent/core/tools/write.d.ts +5 -8
- package/dist/sdk/coding-agent/core/tools/write.d.ts.map +1 -1
- package/dist/sdk/coding-agent/core/tools/write.js +29 -11
- package/package.json +1 -1
|
@@ -35,20 +35,86 @@ const REQUIRED_PROPERTIES = {
|
|
|
35
35
|
VideoObject: ["name", "uploadDate"],
|
|
36
36
|
JobPosting: ["title", "description", "hiringOrganization"],
|
|
37
37
|
Course: ["name", "provider"],
|
|
38
|
+
HowTo: ["name", "step"],
|
|
39
|
+
ItemList: ["itemListElement"],
|
|
40
|
+
Recipe: ["name", "recipeIngredient", "recipeInstructions"],
|
|
41
|
+
FAQPage: ["mainEntity"],
|
|
42
|
+
SoftwareApplication: ["name", "operatingSystem"],
|
|
43
|
+
WebApplication: ["name", "operatingSystem"],
|
|
44
|
+
Person: ["name"],
|
|
45
|
+
WebSite: ["name", "url"],
|
|
38
46
|
};
|
|
47
|
+
/** Normalize a `@type` value (string or array) into a single type name,
|
|
48
|
+
* stripping a leading `https://schema.org/` prefix when present. */
|
|
49
|
+
function normalizeType(rawType) {
|
|
50
|
+
if (typeof rawType === "string") {
|
|
51
|
+
return rawType.replace("https://schema.org/", "");
|
|
52
|
+
}
|
|
53
|
+
if (Array.isArray(rawType) && rawType.length > 0) {
|
|
54
|
+
const first = rawType[0];
|
|
55
|
+
return typeof first === "string" ? first.replace("https://schema.org/", "") : "Unknown";
|
|
56
|
+
}
|
|
57
|
+
return "Unknown";
|
|
58
|
+
}
|
|
59
|
+
/** Build a map of `@id` -> entity from a list of JSON-LD items. */
|
|
60
|
+
function buildEntityMap(items) {
|
|
61
|
+
const map = new Map();
|
|
62
|
+
for (const item of items) {
|
|
63
|
+
if (!item || typeof item !== "object")
|
|
64
|
+
continue;
|
|
65
|
+
const obj = item;
|
|
66
|
+
const id = obj["@id"];
|
|
67
|
+
if (typeof id === "string" && id.length > 0 && !map.has(id)) {
|
|
68
|
+
map.set(id, item);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
return map;
|
|
72
|
+
}
|
|
73
|
+
/** Resolve `@id` references recursively. A bare reference (an object containing
|
|
74
|
+
* only `@id`, or `@id` plus one other key) is replaced by the referenced
|
|
75
|
+
* entity. A `visited` Set prevents infinite loops on cyclic references. */
|
|
76
|
+
function resolveReferences(value, entityMap, visited) {
|
|
77
|
+
if (!value || typeof value !== "object")
|
|
78
|
+
return value;
|
|
79
|
+
if (Array.isArray(value)) {
|
|
80
|
+
return value.map((v) => resolveReferences(v, entityMap, visited));
|
|
81
|
+
}
|
|
82
|
+
const obj = value;
|
|
83
|
+
const id = obj["@id"];
|
|
84
|
+
if (typeof id === "string") {
|
|
85
|
+
const keys = Object.keys(obj);
|
|
86
|
+
const isBareRef = keys.length === 1 || keys.length === 2;
|
|
87
|
+
if (isBareRef && entityMap.has(id) && !visited.has(id)) {
|
|
88
|
+
visited.add(id);
|
|
89
|
+
const resolved = resolveReferences(entityMap.get(id), entityMap, visited);
|
|
90
|
+
visited.delete(id);
|
|
91
|
+
return resolved;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
// Recursively resolve nested references on a shallow copy.
|
|
95
|
+
const out = {};
|
|
96
|
+
for (const [k, v] of Object.entries(obj)) {
|
|
97
|
+
out[k] = resolveReferences(v, entityMap, visited);
|
|
98
|
+
}
|
|
99
|
+
return out;
|
|
100
|
+
}
|
|
39
101
|
/** Validate a parsed JSON-LD object and return issues. */
|
|
40
|
-
function validateSchemaItem(item) {
|
|
102
|
+
function validateSchemaItem(item, entityMap) {
|
|
41
103
|
if (!item || typeof item !== "object") {
|
|
42
104
|
return { type: "Unknown", issues: ["Invalid schema object"] };
|
|
43
105
|
}
|
|
44
|
-
|
|
106
|
+
let obj;
|
|
107
|
+
if (entityMap) {
|
|
108
|
+
const resolved = resolveReferences(item, entityMap, new Set());
|
|
109
|
+
obj = (resolved && typeof resolved === "object"
|
|
110
|
+
? resolved
|
|
111
|
+
: item);
|
|
112
|
+
}
|
|
113
|
+
else {
|
|
114
|
+
obj = item;
|
|
115
|
+
}
|
|
45
116
|
const rawType = obj["@type"];
|
|
46
|
-
|
|
47
|
-
const type = typeof rawType === "string"
|
|
48
|
-
? rawType.replace("https://schema.org/", "")
|
|
49
|
-
: Array.isArray(rawType) && rawType.length > 0
|
|
50
|
-
? rawType[0].replace("https://schema.org/", "")
|
|
51
|
-
: "Unknown";
|
|
117
|
+
const type = normalizeType(rawType);
|
|
52
118
|
const issues = [];
|
|
53
119
|
if (!obj["@context"]) {
|
|
54
120
|
issues.push("Missing @context");
|
|
@@ -64,7 +130,7 @@ function validateSchemaItem(item) {
|
|
|
64
130
|
}
|
|
65
131
|
// Check for relative URLs.
|
|
66
132
|
const jsonStr = JSON.stringify(obj);
|
|
67
|
-
if (
|
|
133
|
+
if (/("url"\s*:\s*"\/)[^/]/.test(jsonStr)) {
|
|
68
134
|
issues.push("Contains relative URL — should be absolute");
|
|
69
135
|
}
|
|
70
136
|
// Check date formats.
|
|
@@ -85,11 +151,25 @@ export function auditSchema(html, url) {
|
|
|
85
151
|
const deprecatedTypes = [];
|
|
86
152
|
const relativeUrls = [];
|
|
87
153
|
const invalidDates = [];
|
|
154
|
+
const duplicateEntities = [];
|
|
88
155
|
let missingContext = false;
|
|
89
156
|
// Re-validate with deeper checks using parsed JSON-LD.
|
|
90
157
|
const jsonLdItems = extractJsonLd(html);
|
|
158
|
+
const entityMap = buildEntityMap(jsonLdItems);
|
|
159
|
+
const seenIds = new Set();
|
|
91
160
|
for (const item of jsonLdItems) {
|
|
92
|
-
|
|
161
|
+
if (item && typeof item === "object") {
|
|
162
|
+
const id = item["@id"];
|
|
163
|
+
if (typeof id === "string" && id.length > 0) {
|
|
164
|
+
if (seenIds.has(id)) {
|
|
165
|
+
duplicateEntities.push(id);
|
|
166
|
+
}
|
|
167
|
+
else {
|
|
168
|
+
seenIds.add(id);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
const { type, issues } = validateSchemaItem(item, entityMap);
|
|
93
173
|
if (DEPRECATED_TYPES.has(type)) {
|
|
94
174
|
deprecatedTypes.push(type);
|
|
95
175
|
}
|
|
@@ -115,6 +195,9 @@ export function auditSchema(html, url) {
|
|
|
115
195
|
if (detectedSchemas.length === 0) {
|
|
116
196
|
recommendations.push("No structured data found. Add JSON-LD markup for rich result eligibility.");
|
|
117
197
|
}
|
|
198
|
+
if (duplicateEntities.length > 0) {
|
|
199
|
+
recommendations.push(`Duplicate @id entities detected: ${duplicateEntities.length}. Deduplicate entities referenced by @id.`);
|
|
200
|
+
}
|
|
118
201
|
// Recommend types based on page content.
|
|
119
202
|
const hasArticle = pageData.wordCount > 300 && (pageData.title ?? "").length > 0;
|
|
120
203
|
if (hasArticle && !detectedSchemas.some((s) => ["Article", "BlogPosting", "NewsArticle"].includes(s.type))) {
|
|
@@ -123,8 +206,14 @@ export function auditSchema(html, url) {
|
|
|
123
206
|
if (detectedSchemas.length > 0 && !detectedSchemas.some((s) => s.type === "BreadcrumbList")) {
|
|
124
207
|
recommendations.push("Add BreadcrumbList schema to improve navigation rich results.");
|
|
125
208
|
}
|
|
209
|
+
const schemaIssues = deprecatedTypes.length + relativeUrls.length + invalidDates.length +
|
|
210
|
+
(missingContext ? 1 : 0) + duplicateEntities.length;
|
|
211
|
+
const score = detectedSchemas.length === 0
|
|
212
|
+
? 0
|
|
213
|
+
: Math.max(0, Math.round(100 - (schemaIssues / detectedSchemas.length) * 25));
|
|
126
214
|
return {
|
|
127
215
|
url,
|
|
216
|
+
score,
|
|
128
217
|
detectedSchemas,
|
|
129
218
|
deprecatedTypes,
|
|
130
219
|
missingContext,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sitemap.d.ts","sourceRoot":"","sources":["../../../../src/extensions/seo/analyzers/sitemap.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AACzD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AA8C9C,wCAAwC;AACxC,wBAAsB,cAAc,CAClC,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,SAAS,GAChB,OAAO,CAAC,qBAAqB,CAAC,
|
|
1
|
+
{"version":3,"file":"sitemap.d.ts","sourceRoot":"","sources":["../../../../src/extensions/seo/analyzers/sitemap.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AACzD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AA8C9C,wCAAwC;AACxC,wBAAsB,cAAc,CAClC,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,SAAS,GAChB,OAAO,CAAC,qBAAqB,CAAC,CAsGhC;AAED,MAAM,WAAW,oBAAoB;IACnC,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,mDAAmD;AACnD,wBAAgB,eAAe,CAAC,OAAO,EAAE,oBAAoB,EAAE,GAAG,MAAM,CAuBvE"}
|
|
@@ -52,39 +52,80 @@ export async function analyzeSitemap(sitemapUrl, config) {
|
|
|
52
52
|
// Validate URLs.
|
|
53
53
|
let invalidEntries = 0;
|
|
54
54
|
const validUrls = [];
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
55
|
+
let childSitemapUrls = parsed.childSitemaps;
|
|
56
|
+
// Recursively resolve sitemap indexes up to 10 children.
|
|
57
|
+
if (parsed.isIndex && childSitemapUrls.length > 0) {
|
|
58
|
+
const childLimit = Math.min(childSitemapUrls.length, 10);
|
|
59
|
+
const childResults = await Promise.allSettled(childSitemapUrls.slice(0, childLimit).map((childUrl) => fetchPage(childUrl, config)));
|
|
60
|
+
for (let i = 0; i < childResults.length; i++) {
|
|
61
|
+
const child = childResults[i];
|
|
62
|
+
if (child.status === "fulfilled" && child.value.statusCode === 200) {
|
|
63
|
+
const childParsed = parseSitemapXml(child.value.content);
|
|
64
|
+
if (!childParsed.isIndex) {
|
|
65
|
+
for (const u of childParsed.urls) {
|
|
66
|
+
try {
|
|
67
|
+
new URL(u.loc);
|
|
68
|
+
validUrls.push(u.loc);
|
|
69
|
+
}
|
|
70
|
+
catch {
|
|
71
|
+
invalidEntries++;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
else {
|
|
76
|
+
warnings.push(`Nested sitemap index at ${childSitemapUrls[i]} — only 2 levels supported.`);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
else {
|
|
80
|
+
const err = child.status === "rejected" ? child.reason : child.value.statusCode;
|
|
81
|
+
warnings.push(`Failed to fetch child sitemap ${childSitemapUrls[i]}: ${err}`);
|
|
82
|
+
}
|
|
59
83
|
}
|
|
60
|
-
|
|
61
|
-
|
|
84
|
+
if (childSitemapUrls.length > 10) {
|
|
85
|
+
warnings.push(`Sitemap index has ${childSitemapUrls.length} children, only first 10 were fetched.`);
|
|
62
86
|
}
|
|
63
87
|
}
|
|
88
|
+
else {
|
|
89
|
+
for (const u of parsed.urls) {
|
|
90
|
+
try {
|
|
91
|
+
new URL(u.loc);
|
|
92
|
+
validUrls.push(u.loc);
|
|
93
|
+
}
|
|
94
|
+
catch {
|
|
95
|
+
invalidEntries++;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
const totalUrls = validUrls.length;
|
|
64
100
|
// Calculate lastmod coverage.
|
|
65
|
-
const withLastmod = parsed.urls.filter((u) => u.lastmod).length;
|
|
66
|
-
const lastmodCoverage = parsed.
|
|
67
|
-
?
|
|
68
|
-
: 0
|
|
101
|
+
const withLastmod = parsed.isIndex ? 0 : parsed.urls.filter((u) => u.lastmod).length;
|
|
102
|
+
const lastmodCoverage = parsed.isIndex
|
|
103
|
+
? 0
|
|
104
|
+
: parsed.urls.length > 0
|
|
105
|
+
? Math.round((withLastmod / parsed.urls.length) * 100)
|
|
106
|
+
: 0;
|
|
107
|
+
if (parsed.isIndex) {
|
|
108
|
+
warnings.push(`Resolved ${validUrls.length} URLs from ${Math.min(childSitemapUrls.length, 10)} child sitemaps.`);
|
|
109
|
+
}
|
|
69
110
|
// Size warnings.
|
|
70
|
-
if (result.contentLengthBytes > 50_000_000) {
|
|
111
|
+
if (!parsed.isIndex && result.contentLengthBytes > 50_000_000) {
|
|
71
112
|
warnings.push("Sitemap exceeds 50MB uncompressed limit. Split into multiple sitemaps.");
|
|
72
113
|
}
|
|
73
|
-
if (parsed.urls.length > 50_000) {
|
|
74
|
-
warnings.push(
|
|
114
|
+
if (!parsed.isIndex && parsed.urls.length > 50_000) {
|
|
115
|
+
warnings.push(`Sitemap contains ${parsed.urls.length} URLs, exceeding the 50,000 limit. Split into multiple sitemaps.`);
|
|
75
116
|
}
|
|
76
|
-
if (lastmodCoverage < 50 && parsed.urls.length > 0) {
|
|
117
|
+
if (!parsed.isIndex && lastmodCoverage < 50 && parsed.urls.length > 0) {
|
|
77
118
|
warnings.push(`Only ${lastmodCoverage}% of URLs have lastmod dates. Adding lastmod improves crawl efficiency.`);
|
|
78
119
|
}
|
|
79
120
|
return {
|
|
80
121
|
url: result.finalUrl,
|
|
81
|
-
urlCount:
|
|
122
|
+
urlCount: totalUrls,
|
|
82
123
|
urls: validUrls,
|
|
83
124
|
lastmodCoverage,
|
|
84
125
|
invalidEntries,
|
|
85
126
|
sizeBytes: result.contentLengthBytes,
|
|
86
127
|
isSitemapIndex: parsed.isIndex,
|
|
87
|
-
childSitemaps:
|
|
128
|
+
childSitemaps: childSitemapUrls,
|
|
88
129
|
warnings,
|
|
89
130
|
};
|
|
90
131
|
}
|
|
@@ -1,10 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Technical SEO audit analyzer.
|
|
3
|
-
*
|
|
4
|
-
* Ported from the Python `seo-technical/SKILL.md` directives in claude-seo.
|
|
5
|
-
* Audits crawlability, indexability, security, URL structure, mobile,
|
|
6
|
-
* and AI crawler management — all using local HTTP fetches only.
|
|
7
|
-
*/
|
|
8
1
|
import type { SeoConfig } from "../config.js";
|
|
9
2
|
import type { FetchResult, PageData, TechnicalAuditResult } from "../types.js";
|
|
10
3
|
export declare function auditTechnical(url: string, config: SeoConfig, pageData?: PageData, fetchResult?: FetchResult): Promise<TechnicalAuditResult>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"technical.d.ts","sourceRoot":"","sources":["../../../../src/extensions/seo/analyzers/technical.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"technical.d.ts","sourceRoot":"","sources":["../../../../src/extensions/seo/analyzers/technical.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,KAAK,EAAc,WAAW,EAAE,QAAQ,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AAiE3F,wBAAsB,cAAc,CAClC,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,SAAS,EACjB,QAAQ,CAAC,EAAE,QAAQ,EACnB,WAAW,CAAC,EAAE,WAAW,GACxB,OAAO,CAAC,oBAAoB,CAAC,CAqoB/B"}
|