@power-seo/content-analysis 1.0.6 → 1.0.8

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 CCBD SEO Contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -12,9 +12,9 @@ Keyword-focused content analysis with real-time scoring, readability checks, and
12
12
  [![TypeScript](https://img.shields.io/badge/TypeScript-5.x-blue)](https://www.typescriptlang.org/)
13
13
  [![tree-shakeable](https://img.shields.io/badge/tree--shakeable-yes-brightgreen)](https://bundlephobia.com/package/@power-seo/content-analysis)
14
14
 
15
- `@power-seo/content-analysis` delivers a comprehensive, WordPress SEO plugin–style scoring pipeline for evaluating text content, comparable to Yoast SEO, All in One SEO (AIOSEO), Rank Math, SEOPress, and The SEO Framework. Provide a page title, meta description, body content, focus keyphrase, images, and links — get back structured `good` / `needs-improvement` / `poor` results across all critical SEO factors. Run it server-side in a CMS, client-side in a React editor, or inside a CI content quality gate. All 13 analysis checks are fully configurable and tree-shakeable.
15
+ `@power-seo/content-analysis` delivers a comprehensive, WordPress SEO plugin–style scoring pipeline for evaluating text content, comparable to Yoast SEO, All in One SEO (AIOSEO), Rank Math, SEOPress, and The SEO Framework. Provide a page title, meta description, body content, focus keyphrase, images, and links — get back structured `good` / `ok` / `poor` results across all critical SEO factors. Run it server-side in a CMS, client-side in a React editor, or inside a CI content quality gate. All 13 analysis checks are fully configurable and tree-shakeable.
16
16
 
17
- > **Zero runtime dependencies** — only `@power-seo/core` as a peer.
17
+ > **Zero external runtime dependencies** — `@power-seo/core` is a direct dependency bundled with this package; no extra install needed.
18
18
 
19
19
  ---
20
20
 
@@ -82,15 +82,15 @@ Keyword-focused content analysis with real-time scoring, readability checks, and
82
82
  ## Installation
83
83
 
84
84
  ```bash
85
- npm install @power-seo/content-analysis @power-seo/core
85
+ npm install @power-seo/content-analysis
86
86
  ```
87
87
 
88
88
  ```bash
89
- yarn add @power-seo/content-analysis @power-seo/core
89
+ yarn add @power-seo/content-analysis
90
90
  ```
91
91
 
92
92
  ```bash
93
- pnpm add @power-seo/content-analysis @power-seo/core
93
+ pnpm add @power-seo/content-analysis
94
94
  ```
95
95
 
96
96
  ---
@@ -103,21 +103,21 @@ import { analyzeContent } from '@power-seo/content-analysis';
103
103
  const result = analyzeContent({
104
104
  title: 'Best Running Shoes for Beginners',
105
105
  metaDescription: 'Discover the best running shoes for beginners with our expert guide.',
106
- keyphrase: 'running shoes for beginners',
106
+ focusKeyphrase: 'running shoes for beginners',
107
107
  content: '<h1>Best Running Shoes</h1><p>Finding the right running shoes...</p>',
108
- url: 'https://example.com/best-running-shoes',
109
108
  });
110
109
 
111
- console.log(result.overallStatus); // "good" | "needs-improvement" | "poor"
110
+ console.log(result.score); // e.g. 38
111
+ console.log(result.maxScore); // e.g. 55
112
112
  console.log(result.results);
113
- // [{ id: 'title-presence', status: 'good', message: '...' }, ...]
113
+ // [{ id: 'title-presence', status: 'good', description: '...', score: 5, maxScore: 5 }, ...]
114
114
  ```
115
115
 
116
116
  ![SEO Check Results](../../image/content-analysis/check-results.svg)
117
117
 
118
118
  **Status thresholds (per check):**
119
119
  - `good` — check fully passes
120
- - `needs-improvement` — check partially passes
120
+ - `ok` — check partially passes
121
121
  - `poor` — check fails
122
122
 
123
123
  ---
@@ -134,16 +134,16 @@ import { analyzeContent } from '@power-seo/content-analysis';
134
134
  const output = analyzeContent({
135
135
  title: 'Next.js SEO Best Practices',
136
136
  metaDescription: 'Learn how to optimize your Next.js app for search engines with meta tags and structured data.',
137
- keyphrase: 'next.js seo',
137
+ focusKeyphrase: 'next.js seo',
138
138
  content: htmlString,
139
- url: 'https://example.com/nextjs-seo',
140
139
  images: imageList,
141
140
  internalLinks: internalLinks,
142
141
  externalLinks: externalLinks,
143
142
  });
144
143
 
145
- // output.overallStatus 'good' | 'needs-improvement' | 'poor'
146
- // output.results AnalysisResult[]
144
+ // output.score number (sum of all check scores)
145
+ // output.maxScore number (maximum possible score)
146
+ // output.results → AnalysisResult[]
147
147
  ```
148
148
 
149
149
  ### Running Individual Checks
@@ -162,20 +162,22 @@ import {
162
162
  } from '@power-seo/content-analysis';
163
163
 
164
164
  const titleResults = checkTitle({
165
- title: 'React SEO Guide',
166
- keyphrase: 'react seo',
167
165
  content: '',
166
+ title: 'React SEO Guide',
167
+ focusKeyphrase: 'react seo',
168
168
  });
169
- // [{ id: 'title-presence', status: 'good', message: '...' },
170
- // { id: 'title-keyphrase', status: 'good', message: '...' }]
169
+ // [
170
+ // { id: 'title-presence', title: 'SEO title', description: '...', status: 'good', score: 5, maxScore: 5 },
171
+ // { id: 'title-keyphrase', title: 'Keyphrase in title', description: '...', status: 'good', score: 5, maxScore: 5 }
172
+ // ]
171
173
 
172
174
  const wcResult = checkWordCount({ content: shortHtml });
173
- // { id: 'word-count', status: 'poor', message: 'Content is 180 words, below minimum of 300.' }
175
+ // { id: 'word-count', title: 'Word count', description: 'The content is 180 words...', status: 'poor', score: 1, maxScore: 5 }
174
176
  ```
175
177
 
176
178
  ### Disabling Specific Checks
177
179
 
178
- Pass `config.disabledChecks` to skip checks that don't apply to your content type:
180
+ Pass `config.disabledChecks` to exclude specific checks from the output. Checks are still executed internally but their results are filtered from `output.results` and excluded from `score`/`maxScore` totals. Invalid check IDs are silently ignored.
179
181
 
180
182
  ```ts
181
183
  import { analyzeContent } from '@power-seo/content-analysis';
@@ -191,6 +193,7 @@ Import from the `/react` entry point for pre-built analysis UI components:
191
193
 
192
194
  ```tsx
193
195
  import { ContentAnalyzer, ScorePanel, CheckList } from '@power-seo/content-analysis/react';
196
+ import { analyzeContent } from '@power-seo/content-analysis';
194
197
  import type { ContentAnalysisInput } from '@power-seo/content-analysis';
195
198
 
196
199
  // All-in-one component
@@ -217,13 +220,13 @@ Block deploys when SEO checks fail:
217
220
  ```ts
218
221
  import { analyzeContent } from '@power-seo/content-analysis';
219
222
 
220
- const output = analyzeContent({ title, metaDescription, keyphrase, content });
223
+ const output = analyzeContent({ title, metaDescription, focusKeyphrase, content });
221
224
 
222
225
  const failures = output.results.filter((r) => r.status === 'poor');
223
226
 
224
227
  if (failures.length > 0) {
225
228
  console.error('SEO checks failed:');
226
- failures.forEach((r) => console.error(' ✗', r.message));
229
+ failures.forEach((r) => console.error(' ✗', r.description));
227
230
  process.exit(1);
228
231
  }
229
232
  ```
@@ -255,31 +258,31 @@ function analyzeContent(
255
258
  | `content` | `string` | ✅ | Body HTML string |
256
259
  | `title` | `string` | — | Page `<title>` content |
257
260
  | `metaDescription` | `string` | — | Meta description content |
258
- | `keyphrase` | `string` | — | Focus keyphrase to analyze against |
259
- | `url` | `string` | — | Page URL (used for slug analysis) |
261
+ | `focusKeyphrase` | `string` | — | Focus keyphrase to analyze against |
262
+ | `slug` | `string` | — | URL slug (used for keyphrase-in-slug check) |
260
263
  | `images` | `Array<{ src: string; alt?: string }>` | — | Images found on the page |
261
264
  | `internalLinks` | `string[]` | — | Internal link URLs |
262
265
  | `externalLinks` | `string[]` | — | External link URLs |
263
266
 
264
267
  #### `ContentAnalysisOutput`
265
268
 
266
- | Field | Type | Description |
267
- | --------------- | ------------------ | --------------------------------------------------------- |
268
- | `overallStatus` | `AnalysisStatus` | `'good'` \| `'needs-improvement'` \| `'poor'` |
269
- | `score` | `number` | Sum of all individual check scores |
270
- | `maxScore` | `number` | Maximum possible score (varies by enabled checks) |
271
- | `results` | `AnalysisResult[]` | Per-check results |
272
- | `recommendations` | `string[]` | Descriptions from all failed or partial checks |
269
+ | Field | Type | Description |
270
+ | ----------------- | ------------------ | ----------------------------------------------------- |
271
+ | `score` | `number` | Sum of all individual check scores |
272
+ | `maxScore` | `number` | Maximum possible score (varies by enabled checks) |
273
+ | `results` | `AnalysisResult[]` | Per-check results |
274
+ | `recommendations` | `string[]` | Descriptions from all failed or partial checks |
273
275
 
274
276
  #### `AnalysisResult`
275
277
 
276
- | Field | Type | Description |
277
- | --------- | ---------------- | --------------------------------------------- |
278
- | `id` | `CheckId` | Unique check identifier (see table below) |
279
- | `status` | `AnalysisStatus` | `'good'` \| `'needs-improvement'` \| `'poor'` |
280
- | `message` | `string` | Human-readable actionable feedback |
281
- | `score` | `number` | Points earned for this check |
282
- | `maxScore`| `number` | Maximum points for this check |
278
+ | Field | Type | Description |
279
+ | ------------- | ---------------- | --------------------------------------------------------- |
280
+ | `id` | `string` | Unique check identifier (one of the `CheckId` values) |
281
+ | `title` | `string` | Short display label for the check (e.g. `"SEO title"`) |
282
+ | `description` | `string` | Human-readable actionable feedback |
283
+ | `status` | `AnalysisStatus` | `'good'` \| `'ok'` \| `'poor'` |
284
+ | `score` | `number` | Points earned for this check |
285
+ | `maxScore` | `number` | Maximum points for this check |
283
286
 
284
287
  #### `AnalysisConfig`
285
288
 
@@ -289,15 +292,17 @@ function analyzeContent(
289
292
 
290
293
  ### Individual Check Functions
291
294
 
292
- | Function | Check ID(s) | Checks For |
293
- | ----------------------------- | -------------------------------------------------------------- | -------------------------------------------------- |
294
- | `checkTitle(input)` | `title-presence`, `title-keyphrase` | Title presence, length (30–60 chars), keyphrase |
295
- | `checkMetaDescription(input)` | `meta-description-presence`, `meta-description-keyphrase` | Description presence, length (120–160 chars), keyphrase |
296
- | `checkKeyphraseUsage(input)` | `keyphrase-density`, `keyphrase-distribution` | Density (0.5–2.5%) and occurrence in key areas |
297
- | `checkHeadings(input)` | `heading-structure`, `heading-keyphrase` | H1 presence, hierarchy, keyphrase in subheadings |
298
- | `checkWordCount(input)` | `word-count` | Min 300 words (good at 1,000+) |
299
- | `checkImages(input)` | `image-alt`, `image-keyphrase` | Alt text presence and keyphrase in alt |
300
- | `checkLinks(input)` | `internal-links`, `external-links` | Internal and external link presence |
295
+ | Function | Check ID(s) | Checks For |
296
+ | ----------------------------- | -------------------------------------------------------------- | ------------------------------------------------------------------------------------------- |
297
+ | `checkTitle(input)` | `title-presence`, `title-keyphrase` | Title presence **and** length (50–60 chars, validated inside `title-presence`), keyphrase |
298
+ | `checkMetaDescription(input)` | `meta-description-presence`, `meta-description-keyphrase` | Description presence, length (120–160 chars), keyphrase |
299
+ | `checkKeyphraseUsage(input)` | `keyphrase-density`, `keyphrase-distribution` | Density (0.5–2.5%) and occurrence in key areas |
300
+ | `checkHeadings(input)` | `heading-structure`, `heading-keyphrase` | H1 presence, hierarchy, keyphrase in subheadings |
301
+ | `checkWordCount(input)` | `word-count` | Min 300 words (good at 1,000+) |
302
+ | `checkImages(input)` | `image-alt`, `image-keyphrase` | Alt text presence and keyphrase in alt |
303
+ | `checkLinks(input)` | `internal-links`, `external-links` | Internal and external link presence |
304
+
305
+ > **Note:** There is no separate `title-length` check ID. Title length validation (50–60 chars) is evaluated inside the `title-presence` check — a title that exists but is outside the recommended range returns `status: 'ok'` rather than `'good'`.
301
306
 
302
307
  ### Types
303
308
 
@@ -305,10 +310,10 @@ function analyzeContent(
305
310
  | ----------------------- | --------------------------------------------------------- |
306
311
  | `CheckId` | Union of all 13 built-in check IDs |
307
312
  | `AnalysisConfig` | `{ disabledChecks?: CheckId[] }` |
308
- | `AnalysisStatus` | `'good' \| 'needs-improvement' \| 'poor'` |
313
+ | `AnalysisStatus` | `'good' \| 'ok' \| 'poor'` |
309
314
  | `ContentAnalysisInput` | Input shape for `analyzeContent()` |
310
315
  | `ContentAnalysisOutput` | Output shape from `analyzeContent()` |
311
- | `AnalysisResult` | Single check result with id, status, message, score |
316
+ | `AnalysisResult` | Single check result with id, title, description, status, score, maxScore |
312
317
 
313
318
  ---
314
319
 
@@ -326,7 +331,7 @@ function analyzeContent(
326
331
  ## Architecture Overview
327
332
 
328
333
  - **Pure TypeScript** — no compiled binary, no native modules
329
- - **Zero runtime dependencies** — only `@power-seo/core` as a peer dependency
334
+ - **Zero external runtime dependencies** — `@power-seo/core` ships as a direct dependency, no separate install
330
335
  - **Framework-agnostic** — works in any JavaScript environment
331
336
  - **SSR compatible** — safe to run in Next.js Server Components, Remix loaders, or Express handlers
332
337
  - **Edge runtime safe** — no Node.js-specific APIs; runs in Cloudflare Workers, Vercel Edge, Deno
package/dist/index.cjs CHANGED
@@ -1,8 +1,38 @@
1
- 'use strict';
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
2
19
 
3
- var core = require('@power-seo/core');
20
+ // src/index.ts
21
+ var src_exports = {};
22
+ __export(src_exports, {
23
+ analyzeContent: () => analyzeContent,
24
+ checkHeadings: () => checkHeadings,
25
+ checkImages: () => checkImages,
26
+ checkKeyphraseUsage: () => checkKeyphraseUsage,
27
+ checkLinks: () => checkLinks,
28
+ checkMetaDescription: () => checkMetaDescription,
29
+ checkTitle: () => checkTitle,
30
+ checkWordCount: () => checkWordCount
31
+ });
32
+ module.exports = __toCommonJS(src_exports);
4
33
 
5
34
  // src/checks/title.ts
35
+ var import_core = require("@power-seo/core");
6
36
  function checkTitle(input) {
7
37
  const results = [];
8
38
  const { title, focusKeyphrase } = input;
@@ -17,7 +47,7 @@ function checkTitle(input) {
17
47
  });
18
48
  return results;
19
49
  }
20
- const validation = core.validateTitle(title);
50
+ const validation = (0, import_core.validateTitle)(title);
21
51
  if (!validation.valid) {
22
52
  results.push({
23
53
  id: "title-presence",
@@ -71,6 +101,9 @@ function checkTitle(input) {
71
101
  }
72
102
  return results;
73
103
  }
104
+
105
+ // src/checks/meta-description.ts
106
+ var import_core2 = require("@power-seo/core");
74
107
  function checkMetaDescription(input) {
75
108
  const results = [];
76
109
  const { metaDescription, focusKeyphrase } = input;
@@ -85,7 +118,7 @@ function checkMetaDescription(input) {
85
118
  });
86
119
  return results;
87
120
  }
88
- const validation = core.validateMetaDescription(metaDescription);
121
+ const validation = (0, import_core2.validateMetaDescription)(metaDescription);
89
122
  if (!validation.valid) {
90
123
  results.push({
91
124
  id: "meta-description-presence",
@@ -139,6 +172,9 @@ function checkMetaDescription(input) {
139
172
  }
140
173
  return results;
141
174
  }
175
+
176
+ // src/checks/keyphrase-usage.ts
177
+ var import_core3 = require("@power-seo/core");
142
178
  function checkKeyphraseUsage(input) {
143
179
  const results = [];
144
180
  const { focusKeyphrase, title, metaDescription, content, slug, images } = input;
@@ -153,7 +189,7 @@ function checkKeyphraseUsage(input) {
153
189
  });
154
190
  return results;
155
191
  }
156
- const occurrences = core.analyzeKeyphraseOccurrences({
192
+ const occurrences = (0, import_core3.analyzeKeyphraseOccurrences)({
157
193
  keyphrase: focusKeyphrase,
158
194
  title,
159
195
  metaDescription,
@@ -161,27 +197,27 @@ function checkKeyphraseUsage(input) {
161
197
  slug,
162
198
  images
163
199
  });
164
- const densityResult = core.calculateKeywordDensity(focusKeyphrase, content);
165
- if (densityResult.density < core.KEYWORD_DENSITY.MIN) {
200
+ const densityResult = (0, import_core3.calculateKeywordDensity)(focusKeyphrase, content);
201
+ if (densityResult.density < import_core3.KEYWORD_DENSITY.MIN) {
166
202
  results.push({
167
203
  id: "keyphrase-density",
168
204
  title: "Keyphrase density",
169
- description: `Keyphrase density is ${densityResult.density}%, which is below the recommended minimum of ${core.KEYWORD_DENSITY.MIN}%. Use the keyphrase more often.`,
205
+ description: `Keyphrase density is ${densityResult.density}%, which is below the recommended minimum of ${import_core3.KEYWORD_DENSITY.MIN}%. Use the keyphrase more often.`,
170
206
  status: "poor",
171
207
  score: 1,
172
208
  maxScore: 5
173
209
  });
174
- } else if (densityResult.density > core.KEYWORD_DENSITY.MAX) {
210
+ } else if (densityResult.density > import_core3.KEYWORD_DENSITY.MAX) {
175
211
  results.push({
176
212
  id: "keyphrase-density",
177
213
  title: "Keyphrase density",
178
- description: `Keyphrase density is ${densityResult.density}%, which exceeds the recommended maximum of ${core.KEYWORD_DENSITY.MAX}%. Reduce usage to avoid keyword stuffing.`,
214
+ description: `Keyphrase density is ${densityResult.density}%, which exceeds the recommended maximum of ${import_core3.KEYWORD_DENSITY.MAX}%. Reduce usage to avoid keyword stuffing.`,
179
215
  status: "poor",
180
216
  score: 1,
181
217
  maxScore: 5
182
218
  });
183
- } else if (densityResult.density >= core.KEYWORD_DENSITY.MIN && densityResult.density <= core.KEYWORD_DENSITY.MAX) {
184
- const isOptimal = Math.abs(densityResult.density - core.KEYWORD_DENSITY.OPTIMAL) < 0.5;
219
+ } else if (densityResult.density >= import_core3.KEYWORD_DENSITY.MIN && densityResult.density <= import_core3.KEYWORD_DENSITY.MAX) {
220
+ const isOptimal = Math.abs(densityResult.density - import_core3.KEYWORD_DENSITY.OPTIMAL) < 0.5;
185
221
  results.push({
186
222
  id: "keyphrase-density",
187
223
  title: "Keyphrase density",
@@ -227,15 +263,37 @@ function checkKeyphraseUsage(input) {
227
263
  }
228
264
  return results;
229
265
  }
266
+
267
+ // src/checks/headings.ts
268
+ var import_core4 = require("@power-seo/core");
230
269
  function parseHeadings(html) {
231
270
  const headings = [];
232
- const regex = /<h([1-6])[^>]*>([\s\S]*?)<\/h\1>/gi;
233
- let match;
234
- while ((match = regex.exec(html)) !== null) {
271
+ const lc = html.toLowerCase();
272
+ let pos = 0;
273
+ while (pos < lc.length) {
274
+ let earliest = -1;
275
+ let earliestLevel = 0;
276
+ for (let level = 1; level <= 6; level++) {
277
+ const idx = lc.indexOf(`<h${level}`, pos);
278
+ if (idx !== -1 && (earliest === -1 || idx < earliest)) {
279
+ earliest = idx;
280
+ earliestLevel = level;
281
+ }
282
+ }
283
+ if (earliest === -1) break;
284
+ const contentStart = lc.indexOf(">", earliest);
285
+ if (contentStart === -1) break;
286
+ const closeTag = `</h${earliestLevel}>`;
287
+ const closeIdx = lc.indexOf(closeTag, contentStart + 1);
288
+ if (closeIdx === -1) {
289
+ pos = contentStart + 1;
290
+ continue;
291
+ }
235
292
  headings.push({
236
- level: parseInt(match[1], 10),
237
- text: core.stripHtml(match[2])
293
+ level: earliestLevel,
294
+ text: (0, import_core4.stripHtml)(html.slice(contentStart + 1, closeIdx))
238
295
  });
296
+ pos = closeIdx + closeTag.length;
239
297
  }
240
298
  return headings;
241
299
  }
@@ -327,24 +385,27 @@ function checkHeadings(input) {
327
385
  }
328
386
  return results;
329
387
  }
388
+
389
+ // src/checks/word-count.ts
390
+ var import_core5 = require("@power-seo/core");
330
391
  function checkWordCount(input) {
331
- const words = core.getWords(input.content);
392
+ const words = (0, import_core5.getWords)(input.content);
332
393
  const count = words.length;
333
- if (count < core.MIN_WORD_COUNT) {
394
+ if (count < import_core5.MIN_WORD_COUNT) {
334
395
  return {
335
396
  id: "word-count",
336
397
  title: "Word count",
337
- description: `The content is ${count} words, which is below the recommended minimum of ${core.MIN_WORD_COUNT}. Add more content to improve SEO.`,
398
+ description: `The content is ${count} words, which is below the recommended minimum of ${import_core5.MIN_WORD_COUNT}. Add more content to improve SEO.`,
338
399
  status: "poor",
339
400
  score: 1,
340
401
  maxScore: 5
341
402
  };
342
403
  }
343
- if (count < core.RECOMMENDED_WORD_COUNT) {
404
+ if (count < import_core5.RECOMMENDED_WORD_COUNT) {
344
405
  return {
345
406
  id: "word-count",
346
407
  title: "Word count",
347
- description: `The content is ${count} words. Consider expanding to at least ${core.RECOMMENDED_WORD_COUNT} words for more comprehensive coverage.`,
408
+ description: `The content is ${count} words. Consider expanding to at least ${import_core5.RECOMMENDED_WORD_COUNT} words for more comprehensive coverage.`,
348
409
  status: "ok",
349
410
  score: 3,
350
411
  maxScore: 5
@@ -512,14 +573,15 @@ function analyzeContent(input, config) {
512
573
  recommendations
513
574
  };
514
575
  }
515
-
516
- exports.analyzeContent = analyzeContent;
517
- exports.checkHeadings = checkHeadings;
518
- exports.checkImages = checkImages;
519
- exports.checkKeyphraseUsage = checkKeyphraseUsage;
520
- exports.checkLinks = checkLinks;
521
- exports.checkMetaDescription = checkMetaDescription;
522
- exports.checkTitle = checkTitle;
523
- exports.checkWordCount = checkWordCount;
524
- //# sourceMappingURL=index.cjs.map
576
+ // Annotate the CommonJS export names for ESM import in node:
577
+ 0 && (module.exports = {
578
+ analyzeContent,
579
+ checkHeadings,
580
+ checkImages,
581
+ checkKeyphraseUsage,
582
+ checkLinks,
583
+ checkMetaDescription,
584
+ checkTitle,
585
+ checkWordCount
586
+ });
525
587
  //# sourceMappingURL=index.cjs.map