seox 0.0.1 → 0.1.0

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/README.md CHANGED
@@ -1,8 +1,8 @@
1
- # 🧠 MetaNext
1
+ # 🧠 Seox
2
2
 
3
3
  > **Simplified SEO management for Next.js App Router**
4
4
 
5
- MetaNext is an **open source tool** that centralizes and automates **SEO management** (meta tags, Open Graph, JSON-LD...) in **Next.js** projects using the **App Router**.
5
+ Seox is an **open source tool** that centralizes and automates **SEO management** (meta tags, Open Graph, JSON-LD...) in **Next.js** projects using the **App Router**.
6
6
  It combines **TypeScript-typed configuration**, **automatic metadata injection**, and an **intuitive CLI** to guide developers.
7
7
 
8
8
  [![npm version](https://img.shields.io/npm/v/metanext.svg)](https://www.npmjs.com/package/@neysixx/metanext)
@@ -16,7 +16,7 @@ It combines **TypeScript-typed configuration**, **automatic metadata injection**
16
16
  In a typical Next.js project, each page manually repeats its `<Head>` tags, metadata, and JSON-LD.
17
17
  👉 This creates **duplication**, **inconsistencies**, and complicates maintenance.
18
18
 
19
- MetaNext provides:
19
+ Seox provides:
20
20
  - **TypeScript-typed configuration** (`lib/seo.ts`)
21
21
  - **Automatic metadata injection** into your Next.js files
22
22
  - **Simple API**: `seoConfig.configToMetadata()`
@@ -30,23 +30,23 @@ MetaNext provides:
30
30
 
31
31
  ```bash
32
32
  # Using Bun (recommended)
33
- bun i metanext
33
+ bun i seox
34
34
 
35
35
  # Using npm
36
- npm i metanext
36
+ npm i seox
37
37
 
38
38
  # Using pnpm
39
- pnpm i metanext
39
+ pnpm i seox
40
40
  ```
41
41
 
42
42
  ### 2. Initialize Configuration
43
43
 
44
44
  ```bash
45
45
  # Using Bun (recommended)
46
- bunx metanext init
46
+ bunx seox init
47
47
 
48
48
  # Using npx
49
- npx metanext init
49
+ npx seox init
50
50
  ```
51
51
 
52
52
  This creates a `lib/seo.ts` file with interactive setup.
@@ -55,14 +55,14 @@ This creates a `lib/seo.ts` file with interactive setup.
55
55
 
56
56
  ```bash
57
57
  # Scan and inject metadata into your Next.js files
58
- bunx metanext configure
58
+ bunx seox configure
59
59
  ```
60
60
 
61
61
  ### 4. Verify Configuration (In progress)
62
62
 
63
63
  ```bash
64
64
  # Check your SEO configuration
65
- bunx metanext doctor
65
+ bunx seox doctor
66
66
  ```
67
67
 
68
68
  ---
@@ -74,9 +74,9 @@ bunx metanext doctor
74
74
  Created via the `init` command:
75
75
 
76
76
  ```ts
77
- import { MetaNext } from "metanext/next";
77
+ import { Seox } from "seox/next";
78
78
 
79
- export const seoConfig = new MetaNext({
79
+ export const seoConfig = new Seox({
80
80
  name: "My Awesome Site",
81
81
  url: "https://mysite.com",
82
82
  title: {
@@ -114,7 +114,7 @@ Configuration is **centralized** and **reusable**.
114
114
  Once the file is completed:
115
115
 
116
116
  ```bash
117
- bunx metanext configure
117
+ bunx seox configure
118
118
  ```
119
119
 
120
120
  This command:
@@ -125,7 +125,7 @@ This command:
125
125
 
126
126
  ### 3. Usage in Your Pages
127
127
 
128
- After running `bunx metanext configure`, your files are automatically updated:
128
+ After running `bunx seox configure`, your files are automatically updated:
129
129
 
130
130
  ```tsx
131
131
  // app/layout.tsx (automatically generated)
@@ -185,28 +185,28 @@ export const metadata = seoConfig.configToMetadata({
185
185
  });
186
186
  ```
187
187
 
188
- MetaNext merges these fields with the global configuration.
188
+ Seox merges these fields with the global configuration.
189
189
 
190
190
  ---
191
191
 
192
192
  ## 🧰 Built-in CLI
193
193
 
194
- MetaNext provides an intuitive CLI:
194
+ Seox provides an intuitive CLI:
195
195
 
196
196
  | Command | Description |
197
197
  |---------|-------------|
198
- | `metanext init` | Creates `lib/seo.ts` with interactive setup |
199
- | `metanext configure` | Scans and injects metadata into your Next.js files |
200
- | `metanext doctor` (soon) | Validates your SEO configuration |
198
+ | `seox init` | Creates `lib/seo.ts` with interactive setup |
199
+ | `seox configure` | Scans and injects metadata into your Next.js files |
200
+ | `seox doctor` (soon) | Validates your SEO configuration |
201
201
 
202
202
  ### Advanced Options
203
203
 
204
204
  ```bash
205
205
  # Force overwrite existing metadata
206
- bunx metanext configure --force
206
+ bunx seox configure --force
207
207
 
208
208
  # Validation only (no generation)
209
- bunx metanext configure --validate
209
+ bunx seox configure --validate
210
210
  ```
211
211
 
212
212
  ---
@@ -233,7 +233,7 @@ bunx metanext configure --validate
233
233
 
234
234
  ## 📘 API & Helpers
235
235
 
236
- ### `MetaNext` (main class)
236
+ ### `Seox` (main class)
237
237
  Centralized SEO configuration with complete TypeScript typing.
238
238
 
239
239
  ### `configToMetadata(overrides?)`
@@ -276,16 +276,16 @@ Direct usage in your Next.js files to generate metadata.
276
276
 
277
277
  ```bash
278
278
  # Bun (recommended)
279
- bun add metanext
279
+ bun add seox
280
280
 
281
281
  # npm
282
- npm install metanext
282
+ npm install seox
283
283
 
284
284
  # pnpm
285
- pnpm add metanext
285
+ pnpm add seox
286
286
 
287
287
  # yarn
288
- yarn add metanext
288
+ yarn add seox
289
289
  ```
290
290
 
291
291
  ---
@@ -298,8 +298,8 @@ We welcome contributions! Please see our [Contributing Guide](CONTRIBUTING.md) f
298
298
 
299
299
  ```bash
300
300
  # Clone the repository
301
- git clone https://github.com/neysixx/metanext.git
302
- cd metanext
301
+ git clone https://github.com/neysixx/seox.git
302
+ cd seox
303
303
 
304
304
  # Install dependencies
305
305
  bun install
@@ -327,9 +327,9 @@ MIT © 2025 — Designed for modern Next.js developers 🧑‍💻
327
327
 
328
328
  ## 📞 Support
329
329
 
330
- - 📖 [Documentation](https://github.com/neysixx/metanext#readme)
331
- - 🐛 [Report Issues](https://github.com/neysixx/metanext/issues)
332
- - 💬 [Discussions](https://github.com/neysixx/metanext/discussions)
330
+ - 📖 [Documentation](https://github.com/neysixx/seox#readme)
331
+ - 🐛 [Report Issues](https://github.com/neysixx/seox/issues)
332
+ - 💬 [Discussions](https://github.com/neysixx/seox/discussions)
333
333
  - 📧 [Email](mailto:kylliansenrens3004@gmail.com)
334
334
 
335
335
  ---
@@ -338,6 +338,6 @@ MIT © 2025 — Designed for modern Next.js developers 🧑‍💻
338
338
 
339
339
  **Made with ❤️ for the Next.js community**
340
340
 
341
- [⭐ Star us on GitHub](https://github.com/neysixx/metanext) • [🐦 Follow on X](https://x.com/ks_nsx) • [📧 Contact](mailto:kylliansenrens3004@gmail.com)
341
+ [⭐ Star us on GitHub](https://github.com/neysixx/seox) • [🐦 Follow on X](https://x.com/ks_nsx) • [📧 Contact](mailto:kylliansenrens3004@gmail.com)
342
342
 
343
343
  </div>
package/dist/cli.cjs CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
- 'use strict';var commander=require('commander'),t=require('chalk'),m=require('fs-extra'),I=require('ora'),y=require('path'),v=require('prompts');function _interopDefault(e){return e&&e.__esModule?e:{default:e}}var t__default=/*#__PURE__*/_interopDefault(t);var m__default=/*#__PURE__*/_interopDefault(m);var I__default=/*#__PURE__*/_interopDefault(I);var y__default=/*#__PURE__*/_interopDefault(y);var v__default=/*#__PURE__*/_interopDefault(v);var p=new commander.Command().name("metanext").description("\u{1F9E0} MetaNext - Simplified SEO management for Next.js App Router").version("1.0.0");var $="SEOX";var c="seo.ts";var b={config:`import { MetaNext } from "metanext/next";
2
+ 'use strict';var commander=require('commander'),e=require('chalk'),u=require('fs-extra'),F=require('ora'),w=require('path'),v=require('prompts');function _interopDefault(e){return e&&e.__esModule?e:{default:e}}var e__default=/*#__PURE__*/_interopDefault(e);var u__default=/*#__PURE__*/_interopDefault(u);var F__default=/*#__PURE__*/_interopDefault(F);var w__default=/*#__PURE__*/_interopDefault(w);var v__default=/*#__PURE__*/_interopDefault(v);var m="SEOX";var c="seo.ts";var p=new commander.Command().name("seox").description(`\u{1F9E0} ${m} - Simplified SEO management for Next.js App Router`).version("1.0.0");var C={config:`import { Seox } from "seox/next";
3
3
 
4
- export const seoConfig = new MetaNext({
4
+ export const seoConfig = new Seox({
5
5
  name: "{{siteName}}",
6
6
  url: "{{baseUrl}}",
7
7
  title: {
@@ -19,39 +19,39 @@ export const seoConfig = new MetaNext({
19
19
  },
20
20
  ],
21
21
  manifest: "",
22
- })`};function g(a){return m__default.default.existsSync(process.cwd()+"/src")?y__default.default.join(process.cwd(),"src","lib",a):y__default.default.join(process.cwd(),"lib",a)}function O(a){let r={errors:[],warnings:[],suggestions:[]};return Object.entries(a.pages||{}).forEach(([o,e])=>{e.title?e.title.length>60&&r.warnings.push(`Page "${o}" : title too long (${e.title.length} > 60)`):r.errors.push(`Page "${o}" : title missing`),e.description?e.description.length>160&&r.warnings.push(`Page "${o}" : description too long (${e.description.length} > 160)`):r.errors.push(`Page "${o}" : description missing`),(!e.jsonld||e.jsonld.length===0)&&r.suggestions.push(`Page "${o}" : add JSON-LD to improve indexing`);}),r}async function S(){let a=[],r=m__default.default.existsSync(process.cwd()+"/src")?"src":"",o=y__default.default.join(process.cwd(),r,"app"),e=y__default.default.join(process.cwd(),r,"pages");return await m__default.default.pathExists(o)&&await E(o,a),await m__default.default.pathExists(e)&&await E(e,a),a}async function E(a,r,o){let e=await m__default.default.readdir(a,{withFileTypes:true});for(let s of e){let i=y__default.default.join(a,s.name);if(s.isDirectory())await E(i,r);else if(s.isFile()&&(s.name==="layout.tsx"||s.name==="page.tsx"||s.name==="layout.ts"||s.name==="page.ts")){let n=await m__default.default.readFile(i,"utf8"),l=n.includes("export const metadata"),f=l?F(n):void 0;r.push({path:i,hasMetadata:l,metadataContent:f});}}}function F(a){let r=a.split(`
23
- `),o=[],e=false,s=0;for(let i of r){if(i.includes("export const metadata")){e=true,o.push(i),s=(i.match(/\{/g)||[]).length-(i.match(/\}/g)||[]).length;continue}if(e&&(o.push(i),s+=(i.match(/\{/g)||[]).length-(i.match(/\}/g)||[]).length,s===0))break}return o.join(`
24
- `)}async function w(a,r=false){let o=await m__default.default.readFile(a,"utf8");if(o.includes("export const metadata")&&!r)return false;let e=o;if(r&&o.includes("export const metadata")&&(e=o.replace(/export const metadata[^;]+;?\s*/gs,"")),!e.includes("import { seoConfig } from '@/lib/seo'")){let l=`import { seoConfig } from '@/lib/seo';
25
- `,f=e.split(`
26
- `),x=0;for(let h=0;h<f.length;h++)if(f[h].startsWith("import "))x=h+1;else if(f[h].trim()===""&&x>0)break;f.splice(x,0,l),e=f.join(`
27
- `);}let s=`
22
+ })`};function g(a){return u__default.default.existsSync(process.cwd()+"/src")?w__default.default.join(process.cwd(),"src","lib",a):w__default.default.join(process.cwd(),"lib",a)}function b(a){let s={errors:[],warnings:[],suggestions:[]};return Object.entries(a.pages||{}).forEach(([t,o])=>{o.title?o.title.length>60&&s.warnings.push(`Page "${t}" : title too long (${o.title.length} > 60)`):s.errors.push(`Page "${t}" : title missing`),o.description?o.description.length>160&&s.warnings.push(`Page "${t}" : description too long (${o.description.length} > 160)`):s.errors.push(`Page "${t}" : description missing`),(!o.jsonld||o.jsonld.length===0)&&s.suggestions.push(`Page "${t}" : add JSON-LD to improve indexing`);}),s}async function O(){let a=[],s=u__default.default.existsSync(process.cwd()+"/src")?"src":"",t=w__default.default.join(process.cwd(),s,"app"),o=w__default.default.join(process.cwd(),s,"pages");return await u__default.default.pathExists(t)&&await $(t,a),await u__default.default.pathExists(o)&&await $(o,a),a}async function $(a,s,t){let o=await u__default.default.readdir(a,{withFileTypes:true});for(let n of o){let i=w__default.default.join(a,n.name);if(n.isDirectory())await $(i,s);else if(n.isFile()&&(n.name==="layout.tsx"||n.name==="page.tsx"||n.name==="layout.ts"||n.name==="page.ts")){let r=await u__default.default.readFile(i,"utf8"),l=r.includes("export const metadata"),f=l?M(r):void 0;s.push({path:i,hasMetadata:l,metadataContent:f});}}}function M(a){let s=a.split(`
23
+ `),t=[],o=false,n=0;for(let i of s){if(i.includes("export const metadata")){o=true,t.push(i),n=(i.match(/\{/g)||[]).length-(i.match(/\}/g)||[]).length;continue}if(o&&(t.push(i),n+=(i.match(/\{/g)||[]).length-(i.match(/\}/g)||[]).length,n===0))break}return t.join(`
24
+ `)}async function x(a,s=false){let t=await u__default.default.readFile(a,"utf8");if(t.includes("export const metadata")&&!s)return false;let o=t;if(s&&t.includes("export const metadata")&&(o=t.replace(/export const metadata[^;]+;?\s*/gs,"")),!o.includes("import { seoConfig } from '@/lib/seo'")){let l=`import { seoConfig } from '@/lib/seo';
25
+ `,f=o.split(`
26
+ `),E=0;for(let y=0;y<f.length;y++)if(f[y].startsWith("import "))E=y+1;else if(f[y].trim()===""&&E>0)break;f.splice(E,0,l),o=f.join(`
27
+ `);}let n=`
28
28
  export const metadata = seoConfig.configToMetadata();
29
- `,i=e.split(`
30
- `),n=i.length;for(let l=0;l<i.length;l++)if(i[l].startsWith("export default")||i[l].startsWith("export function")||i[l].startsWith("export const")&&!i[l].includes("metadata")){n=l;break}return i.splice(n,0,s),e=i.join(`
31
- `),await m__default.default.writeFile(a,e,"utf8"),true}p.command("init").description("Initialize the SEOX SEO configuration").action(async a=>{if(console.log(t__default.default.cyan.bold(`
32
- \u{1F9E0} MetaNext - Initialization
33
- `)),await m__default.default.pathExists(g(c))){let{overwrite:e}=await v__default.default({type:"confirm",name:"overwrite",message:`The ${g(c)} file already exists. Do you want to overwrite it?`,initial:false});if(!e){console.log(t__default.default.yellow("\u26A0\uFE0F Initialization canceled"));return}}let r=await v__default.default([{type:"text",name:"siteName",message:"Name of your site :",initial:"My Site"},{type:"text",name:"baseUrl",message:"Base URL (without trailing slash) :",initial:"https://mysite.com",validate:e=>e.startsWith("http")||"Invalid URL"},{type:"text",name:"siteDescription",message:"Default description :",initial:"A modern site built with Next.js"}]);if(!r.siteName){console.log(t__default.default.red("\u274C Initialization canceled"));return}let o=I__default.default("Creating files...").start();try{await m__default.default.ensureDir(y__default.default.join(process.cwd(),"lib"));let e=b.config;Object.entries(r).forEach(([s,i])=>{e=e.replace(new RegExp(`{{${s}}}`,"g"),i);}),await m__default.default.writeFile(g(c),e,"utf8"),o.succeed("Configuration created successfully!"),console.log(t__default.default.green(`
34
- \u2705 File created : `)+t__default.default.gray(g(c))),console.log(t__default.default.cyan(`
35
- \u{1F4DD} Next step :`)),console.log(t__default.default.white(" bunx metanext configure")),console.log();}catch(e){o.fail("Error creating the configuration"),console.error(t__default.default.red(e.message)),process.exit(1);}});p.command("configure").description("Apply SEO configuration to all Next.js pages and layouts").option("--validate","Validate only without generating",false).option("--force","Force overwrite existing metadata without asking",false).action(async a=>{console.log(t__default.default.cyan.bold(`
36
- \u2699\uFE0F ${$} - Configuration
37
- `));let r=I__default.default("Reading configuration...").start();try{if(!await m__default.default.pathExists(g(c))){r.fail(c+" file not found"),console.log(t__default.default.yellow(`
38
- \u{1F4A1} Run first: `)+t__default.default.white("bunx seox init"));return}r.text="Scanning Next.js files...";let o=await S();if(o.length===0){r.fail("No Next.js layout or page files found"),console.log(t__default.default.yellow(`
39
- \u{1F4A1} Make sure you have an app/ or pages/ directory with layout.tsx/page.tsx files`));return}r.succeed(`Found ${o.length} file(s) to process`),console.log(t__default.default.cyan(`
40
- \u{1F4C1} Files found:`)),o.forEach(n=>{let l=n.hasMetadata?t__default.default.yellow("(has metadata)"):t__default.default.green("(no metadata)");console.log(t__default.default.gray(` \u2022 ${n.path} ${l}`));});let e={added:0,overwritten:0,skipped:0,errors:[]},s=o.filter(n=>n.hasMetadata),i=o.filter(n=>!n.hasMetadata);console.log(t__default.default.cyan(`
41
- \u{1F504} Processing files without metadata...`));for(let n of i)try{await w(n.path,!1)&&(e.added++,console.log(t__default.default.green(` \u2713 Added metadata to ${n.path}`)));}catch(l){e.errors.push(`${n.path}: ${l.message}`),console.log(t__default.default.red(` \u2717 Error in ${n.path}`));}if(s.length>0)if(console.log(t__default.default.yellow(`
42
- \u26A0\uFE0F ${s.length} file(s) already have metadata exports`)),a.force){console.log(t__default.default.cyan(`
43
- \u{1F504} Overwriting all existing metadata (--force)...`));for(let n of s)try{await w(n.path,!0)&&(e.overwritten++,console.log(t__default.default.yellow(` \u2713 Overwritten ${n.path}`)));}catch(l){e.errors.push(`${n.path}: ${l.message}`),console.log(t__default.default.red(` \u2717 Error in ${n.path}`));}}else {console.log(t__default.default.cyan(`
44
- \u{1F504} Processing files with existing metadata...`));for(let n of s){let l=await v__default.default({type:"confirm",name:"overwrite",message:`Overwrite metadata in ${n.path}?`,initial:!1});if(l.overwrite===void 0){console.log(t__default.default.yellow(`
45
- \u274C Operation cancelled`));break}if(l.overwrite)try{await w(n.path,!0)&&(e.overwritten++,console.log(t__default.default.yellow(` \u2713 Overwritten ${n.path}`)));}catch(f){e.errors.push(`${n.path}: ${f.message}`),console.log(t__default.default.red(` \u2717 Error in ${n.path}`));}else e.skipped++,console.log(t__default.default.gray(` \u25CB Skipped ${n.path}`));}}console.log(t__default.default.green.bold(`
29
+ `,i=o.split(`
30
+ `),r=i.length;for(let l=0;l<i.length;l++)if(i[l].startsWith("export default")||i[l].startsWith("export function")||i[l].startsWith("export const")&&!i[l].includes("metadata")){r=l;break}return i.splice(r,0,n),o=i.join(`
31
+ `),await u__default.default.writeFile(a,o,"utf8"),true}p.command("init").description("Initialize the SEOX SEO configuration").action(async a=>{if(console.log(e__default.default.cyan.bold(`
32
+ \u{1F9E0} ${m} - Initialization
33
+ `)),await u__default.default.pathExists(g(c))){let{overwrite:o}=await v__default.default({type:"confirm",name:"overwrite",message:`The ${g(c)} file already exists. Do you want to overwrite it?`,initial:false});if(!o){console.log(e__default.default.yellow("\u26A0\uFE0F Initialization canceled"));return}}let s=await v__default.default([{type:"text",name:"siteName",message:"Name of your site :",initial:"My Site"},{type:"text",name:"baseUrl",message:"Base URL (without trailing slash) :",initial:"https://mysite.com",validate:o=>o.startsWith("http")||"Invalid URL"},{type:"text",name:"siteDescription",message:"Default description :",initial:"A modern site built with Next.js"}]);if(!s.siteName){console.log(e__default.default.red("\u274C Initialization canceled"));return}let t=F__default.default("Creating files...").start();try{await u__default.default.ensureDir(w__default.default.join(process.cwd(),"lib"));let o=C.config;Object.entries(s).forEach(([n,i])=>{o=o.replace(new RegExp(`{{${n}}}`,"g"),i);}),await u__default.default.writeFile(g(c),o,"utf8"),t.succeed("Configuration created successfully!"),console.log(e__default.default.green(`
34
+ \u2705 File created : `)+e__default.default.gray(g(c))),console.log(e__default.default.cyan(`
35
+ \u{1F4DD} Next step :`)),console.log(e__default.default.white(" bunx seox configure")),console.log();}catch(o){t.fail("Error creating the configuration"),console.error(e__default.default.red(o.message)),process.exit(1);}});p.command("configure").description("Apply SEO configuration to all Next.js pages and layouts").option("--validate","Validate only without generating",false).option("--force","Force overwrite existing metadata without asking",false).action(async a=>{console.log(e__default.default.cyan.bold(`
36
+ \u2699\uFE0F ${m} - Configuration
37
+ `));let s=F__default.default("Reading configuration...").start();try{if(!await u__default.default.pathExists(g(c))){s.fail(c+" file not found"),console.log(e__default.default.yellow(`
38
+ \u{1F4A1} Run first: `)+e__default.default.white("bunx seox init"));return}s.text="Scanning Next.js files...";let t=await O();if(t.length===0){s.fail("No Next.js layout or page files found"),console.log(e__default.default.yellow(`
39
+ \u{1F4A1} Make sure you have an app/ or pages/ directory with layout.tsx/page.tsx files`));return}s.succeed(`Found ${t.length} file(s) to process`),console.log(e__default.default.cyan(`
40
+ \u{1F4C1} Files found:`)),t.forEach(r=>{let l=r.hasMetadata?e__default.default.yellow("(has metadata)"):e__default.default.green("(no metadata)");console.log(e__default.default.gray(` \u2022 ${r.path} ${l}`));});let o={added:0,overwritten:0,skipped:0,errors:[]},n=t.filter(r=>r.hasMetadata),i=t.filter(r=>!r.hasMetadata);console.log(e__default.default.cyan(`
41
+ \u{1F504} Processing files without metadata...`));for(let r of i)try{await x(r.path,!1)&&(o.added++,console.log(e__default.default.green(` \u2713 Added metadata to ${r.path}`)));}catch(l){o.errors.push(`${r.path}: ${l.message}`),console.log(e__default.default.red(` \u2717 Error in ${r.path}`));}if(n.length>0)if(console.log(e__default.default.yellow(`
42
+ \u26A0\uFE0F ${n.length} file(s) already have metadata exports`)),a.force){console.log(e__default.default.cyan(`
43
+ \u{1F504} Overwriting all existing metadata (--force)...`));for(let r of n)try{await x(r.path,!0)&&(o.overwritten++,console.log(e__default.default.yellow(` \u2713 Overwritten ${r.path}`)));}catch(l){o.errors.push(`${r.path}: ${l.message}`),console.log(e__default.default.red(` \u2717 Error in ${r.path}`));}}else {console.log(e__default.default.cyan(`
44
+ \u{1F504} Processing files with existing metadata...`));for(let r of n){let l=await v__default.default({type:"confirm",name:"overwrite",message:`Overwrite metadata in ${r.path}?`,initial:!1});if(l.overwrite===void 0){console.log(e__default.default.yellow(`
45
+ \u274C Operation cancelled`));break}if(l.overwrite)try{await x(r.path,!0)&&(o.overwritten++,console.log(e__default.default.yellow(` \u2713 Overwritten ${r.path}`)));}catch(f){o.errors.push(`${r.path}: ${f.message}`),console.log(e__default.default.red(` \u2717 Error in ${r.path}`));}else o.skipped++,console.log(e__default.default.gray(` \u25CB Skipped ${r.path}`));}}console.log(e__default.default.green.bold(`
46
46
  \u2705 Configuration Summary:
47
- `)),console.log(t__default.default.gray(` \u2022 ${e.added} file(s) with metadata added`)),e.overwritten>0&&console.log(t__default.default.yellow(` \u2022 ${e.overwritten} file(s) overwritten`)),e.skipped>0&&console.log(t__default.default.gray(` \u2022 ${e.skipped} file(s) skipped`)),e.errors.length>0&&(console.log(t__default.default.red(` \u2022 ${e.errors.length} error(s):`)),e.errors.forEach(n=>{console.log(t__default.default.red(` - ${n}`));})),(e.added>0||e.overwritten>0)&&(console.log(t__default.default.cyan.bold(`
47
+ `)),console.log(e__default.default.gray(` \u2022 ${o.added} file(s) with metadata added`)),o.overwritten>0&&console.log(e__default.default.yellow(` \u2022 ${o.overwritten} file(s) overwritten`)),o.skipped>0&&console.log(e__default.default.gray(` \u2022 ${o.skipped} file(s) skipped`)),o.errors.length>0&&(console.log(e__default.default.red(` \u2022 ${o.errors.length} error(s):`)),o.errors.forEach(r=>{console.log(e__default.default.red(` - ${r}`));})),(o.added>0||o.overwritten>0)&&(console.log(e__default.default.cyan.bold(`
48
48
  \u{1F4DD} Next Steps:
49
- `)),console.log(t__default.default.white(" The following metadata export has been added to your files:")),console.log(t__default.default.gray(" import { seoConfig } from '@/lib/seo';")),console.log(t__default.default.gray(` export const metadata = seoConfig.configToMetadata();
50
- `)),console.log(t__default.default.white(" To customize metadata for specific pages, you can:")),console.log(t__default.default.gray(" 1. Pass overrides to configToMetadata():")),console.log(t__default.default.gray(" export const metadata = seoConfig.configToMetadata({")),console.log(t__default.default.gray(' title: "Custom Page Title",')),console.log(t__default.default.gray(' description: "Custom description"')),console.log(t__default.default.gray(` });
51
- `)),console.log(t__default.default.gray(" 2. Or manually modify the metadata object after generation")),console.log());}catch(o){r.fail(`Error during configuration. You may have to check your configuration file in ${g(c)}.`),console.error(t__default.default.red(o.message)),process.exit(1);}});p.command("doctor").description("Check the validity of your SEO configuration").action(async()=>{console.log(t__default.default.cyan.bold(`
52
- \u{1FA7A} MetaNext - Diagnostic SEO
53
- `));let a=I__default.default("Analyzing...").start();try{if(!await m__default.default.pathExists(g(c))){a.fail(c+" file not found");return}let o=(await import(g(c))).default;a.stop();let e=O(o);if(e.errors.length===0&&e.warnings.length===0){console.log(t__default.default.green(`\u2705 No issues detected ! Your SEO configuration is optimal.
54
- `));return}e.errors.length>0&&(console.log(t__default.default.red.bold(`\u274C ERRORS :
55
- `)),e.errors.map(s=>console.log(t__default.default.red(` \u2022 ${s}`))),console.log()),e.warnings.length>0&&(console.log(t__default.default.yellow.bold(`\u26A0\uFE0F WARNINGS :
56
- `)),e.warnings.map(s=>console.log(t__default.default.yellow(` \u2022 ${s}`))),console.log()),e.suggestions.length>0&&(console.log(t__default.default.cyan.bold(`\u{1F4A1} SUGGESTIONS :
57
- `)),e.suggestions.map(s=>console.log(t__default.default.cyan(` \u2022 ${s}`))),console.log());}catch(r){a.fail("Error during diagnosis"),console.error(t__default.default.red(r.message));}});p.parse(process.argv);var ye=p;module.exports=ye;
49
+ `)),console.log(e__default.default.white(" The following metadata export has been added to your files:")),console.log(e__default.default.gray(" import { seoConfig } from '@/lib/seo';")),console.log(e__default.default.gray(` export const metadata = seoConfig.configToMetadata();
50
+ `)),console.log(e__default.default.white(" To customize metadata for specific pages, you can:")),console.log(e__default.default.gray(" 1. Pass overrides to configToMetadata():")),console.log(e__default.default.gray(" export const metadata = seoConfig.configToMetadata({")),console.log(e__default.default.gray(' title: "Custom Page Title",')),console.log(e__default.default.gray(' description: "Custom description"')),console.log(e__default.default.gray(` });
51
+ `)),console.log(e__default.default.gray(" 2. Or manually modify the metadata object after generation")),console.log());}catch(t){s.fail(`Error during configuration. You may have to check your configuration file in ${g(c)}.`),console.error(e__default.default.red(t.message)),process.exit(1);}});p.command("doctor").description("Check the validity of your SEO configuration").action(async()=>{console.log(e__default.default.cyan.bold(`
52
+ \u{1FA7A} ${m} - SEO Diagnostic
53
+ `));let a=F__default.default("Analyzing...").start();try{if(!await u__default.default.pathExists(g(c))){a.fail(c+" file not found");return}let t=(await import(g(c))).default;a.stop();let o=b(t);if(o.errors.length===0&&o.warnings.length===0){console.log(e__default.default.green(`\u2705 No issues detected ! Your SEO configuration is optimal.
54
+ `));return}o.errors.length>0&&(console.log(e__default.default.red.bold(`\u274C ERRORS :
55
+ `)),o.errors.map(n=>console.log(e__default.default.red(` \u2022 ${n}`))),console.log()),o.warnings.length>0&&(console.log(e__default.default.yellow.bold(`\u26A0\uFE0F WARNINGS :
56
+ `)),o.warnings.map(n=>console.log(e__default.default.yellow(` \u2022 ${n}`))),console.log()),o.suggestions.length>0&&(console.log(e__default.default.cyan.bold(`\u{1F4A1} SUGGESTIONS :
57
+ `)),o.suggestions.map(n=>console.log(e__default.default.cyan(` \u2022 ${n}`))),console.log());}catch(s){a.fail("Error during diagnosis"),console.error(e__default.default.red(s.message));}});p.parse(process.argv);var xo=p;module.exports=xo;
package/dist/cli.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
- import {Command}from'commander';import t from'chalk';import m from'fs-extra';import I from'ora';import y from'path';import v from'prompts';var p=new Command().name("metanext").description("\u{1F9E0} MetaNext - Simplified SEO management for Next.js App Router").version("1.0.0");var $="SEOX";var c="seo.ts";var b={config:`import { MetaNext } from "metanext/next";
2
+ import {Command}from'commander';import e from'chalk';import u from'fs-extra';import F from'ora';import w from'path';import v from'prompts';var m="SEOX";var c="seo.ts";var p=new Command().name("seox").description(`\u{1F9E0} ${m} - Simplified SEO management for Next.js App Router`).version("1.0.0");var C={config:`import { Seox } from "seox/next";
3
3
 
4
- export const seoConfig = new MetaNext({
4
+ export const seoConfig = new Seox({
5
5
  name: "{{siteName}}",
6
6
  url: "{{baseUrl}}",
7
7
  title: {
@@ -19,39 +19,39 @@ export const seoConfig = new MetaNext({
19
19
  },
20
20
  ],
21
21
  manifest: "",
22
- })`};function g(a){return m.existsSync(process.cwd()+"/src")?y.join(process.cwd(),"src","lib",a):y.join(process.cwd(),"lib",a)}function O(a){let r={errors:[],warnings:[],suggestions:[]};return Object.entries(a.pages||{}).forEach(([o,e])=>{e.title?e.title.length>60&&r.warnings.push(`Page "${o}" : title too long (${e.title.length} > 60)`):r.errors.push(`Page "${o}" : title missing`),e.description?e.description.length>160&&r.warnings.push(`Page "${o}" : description too long (${e.description.length} > 160)`):r.errors.push(`Page "${o}" : description missing`),(!e.jsonld||e.jsonld.length===0)&&r.suggestions.push(`Page "${o}" : add JSON-LD to improve indexing`);}),r}async function S(){let a=[],r=m.existsSync(process.cwd()+"/src")?"src":"",o=y.join(process.cwd(),r,"app"),e=y.join(process.cwd(),r,"pages");return await m.pathExists(o)&&await E(o,a),await m.pathExists(e)&&await E(e,a),a}async function E(a,r,o){let e=await m.readdir(a,{withFileTypes:true});for(let s of e){let i=y.join(a,s.name);if(s.isDirectory())await E(i,r);else if(s.isFile()&&(s.name==="layout.tsx"||s.name==="page.tsx"||s.name==="layout.ts"||s.name==="page.ts")){let n=await m.readFile(i,"utf8"),l=n.includes("export const metadata"),f=l?F(n):void 0;r.push({path:i,hasMetadata:l,metadataContent:f});}}}function F(a){let r=a.split(`
23
- `),o=[],e=false,s=0;for(let i of r){if(i.includes("export const metadata")){e=true,o.push(i),s=(i.match(/\{/g)||[]).length-(i.match(/\}/g)||[]).length;continue}if(e&&(o.push(i),s+=(i.match(/\{/g)||[]).length-(i.match(/\}/g)||[]).length,s===0))break}return o.join(`
24
- `)}async function w(a,r=false){let o=await m.readFile(a,"utf8");if(o.includes("export const metadata")&&!r)return false;let e=o;if(r&&o.includes("export const metadata")&&(e=o.replace(/export const metadata[^;]+;?\s*/gs,"")),!e.includes("import { seoConfig } from '@/lib/seo'")){let l=`import { seoConfig } from '@/lib/seo';
25
- `,f=e.split(`
26
- `),x=0;for(let h=0;h<f.length;h++)if(f[h].startsWith("import "))x=h+1;else if(f[h].trim()===""&&x>0)break;f.splice(x,0,l),e=f.join(`
27
- `);}let s=`
22
+ })`};function g(a){return u.existsSync(process.cwd()+"/src")?w.join(process.cwd(),"src","lib",a):w.join(process.cwd(),"lib",a)}function b(a){let s={errors:[],warnings:[],suggestions:[]};return Object.entries(a.pages||{}).forEach(([t,o])=>{o.title?o.title.length>60&&s.warnings.push(`Page "${t}" : title too long (${o.title.length} > 60)`):s.errors.push(`Page "${t}" : title missing`),o.description?o.description.length>160&&s.warnings.push(`Page "${t}" : description too long (${o.description.length} > 160)`):s.errors.push(`Page "${t}" : description missing`),(!o.jsonld||o.jsonld.length===0)&&s.suggestions.push(`Page "${t}" : add JSON-LD to improve indexing`);}),s}async function O(){let a=[],s=u.existsSync(process.cwd()+"/src")?"src":"",t=w.join(process.cwd(),s,"app"),o=w.join(process.cwd(),s,"pages");return await u.pathExists(t)&&await $(t,a),await u.pathExists(o)&&await $(o,a),a}async function $(a,s,t){let o=await u.readdir(a,{withFileTypes:true});for(let n of o){let i=w.join(a,n.name);if(n.isDirectory())await $(i,s);else if(n.isFile()&&(n.name==="layout.tsx"||n.name==="page.tsx"||n.name==="layout.ts"||n.name==="page.ts")){let r=await u.readFile(i,"utf8"),l=r.includes("export const metadata"),f=l?M(r):void 0;s.push({path:i,hasMetadata:l,metadataContent:f});}}}function M(a){let s=a.split(`
23
+ `),t=[],o=false,n=0;for(let i of s){if(i.includes("export const metadata")){o=true,t.push(i),n=(i.match(/\{/g)||[]).length-(i.match(/\}/g)||[]).length;continue}if(o&&(t.push(i),n+=(i.match(/\{/g)||[]).length-(i.match(/\}/g)||[]).length,n===0))break}return t.join(`
24
+ `)}async function x(a,s=false){let t=await u.readFile(a,"utf8");if(t.includes("export const metadata")&&!s)return false;let o=t;if(s&&t.includes("export const metadata")&&(o=t.replace(/export const metadata[^;]+;?\s*/gs,"")),!o.includes("import { seoConfig } from '@/lib/seo'")){let l=`import { seoConfig } from '@/lib/seo';
25
+ `,f=o.split(`
26
+ `),E=0;for(let y=0;y<f.length;y++)if(f[y].startsWith("import "))E=y+1;else if(f[y].trim()===""&&E>0)break;f.splice(E,0,l),o=f.join(`
27
+ `);}let n=`
28
28
  export const metadata = seoConfig.configToMetadata();
29
- `,i=e.split(`
30
- `),n=i.length;for(let l=0;l<i.length;l++)if(i[l].startsWith("export default")||i[l].startsWith("export function")||i[l].startsWith("export const")&&!i[l].includes("metadata")){n=l;break}return i.splice(n,0,s),e=i.join(`
31
- `),await m.writeFile(a,e,"utf8"),true}p.command("init").description("Initialize the SEOX SEO configuration").action(async a=>{if(console.log(t.cyan.bold(`
32
- \u{1F9E0} MetaNext - Initialization
33
- `)),await m.pathExists(g(c))){let{overwrite:e}=await v({type:"confirm",name:"overwrite",message:`The ${g(c)} file already exists. Do you want to overwrite it?`,initial:false});if(!e){console.log(t.yellow("\u26A0\uFE0F Initialization canceled"));return}}let r=await v([{type:"text",name:"siteName",message:"Name of your site :",initial:"My Site"},{type:"text",name:"baseUrl",message:"Base URL (without trailing slash) :",initial:"https://mysite.com",validate:e=>e.startsWith("http")||"Invalid URL"},{type:"text",name:"siteDescription",message:"Default description :",initial:"A modern site built with Next.js"}]);if(!r.siteName){console.log(t.red("\u274C Initialization canceled"));return}let o=I("Creating files...").start();try{await m.ensureDir(y.join(process.cwd(),"lib"));let e=b.config;Object.entries(r).forEach(([s,i])=>{e=e.replace(new RegExp(`{{${s}}}`,"g"),i);}),await m.writeFile(g(c),e,"utf8"),o.succeed("Configuration created successfully!"),console.log(t.green(`
34
- \u2705 File created : `)+t.gray(g(c))),console.log(t.cyan(`
35
- \u{1F4DD} Next step :`)),console.log(t.white(" bunx metanext configure")),console.log();}catch(e){o.fail("Error creating the configuration"),console.error(t.red(e.message)),process.exit(1);}});p.command("configure").description("Apply SEO configuration to all Next.js pages and layouts").option("--validate","Validate only without generating",false).option("--force","Force overwrite existing metadata without asking",false).action(async a=>{console.log(t.cyan.bold(`
36
- \u2699\uFE0F ${$} - Configuration
37
- `));let r=I("Reading configuration...").start();try{if(!await m.pathExists(g(c))){r.fail(c+" file not found"),console.log(t.yellow(`
38
- \u{1F4A1} Run first: `)+t.white("bunx seox init"));return}r.text="Scanning Next.js files...";let o=await S();if(o.length===0){r.fail("No Next.js layout or page files found"),console.log(t.yellow(`
39
- \u{1F4A1} Make sure you have an app/ or pages/ directory with layout.tsx/page.tsx files`));return}r.succeed(`Found ${o.length} file(s) to process`),console.log(t.cyan(`
40
- \u{1F4C1} Files found:`)),o.forEach(n=>{let l=n.hasMetadata?t.yellow("(has metadata)"):t.green("(no metadata)");console.log(t.gray(` \u2022 ${n.path} ${l}`));});let e={added:0,overwritten:0,skipped:0,errors:[]},s=o.filter(n=>n.hasMetadata),i=o.filter(n=>!n.hasMetadata);console.log(t.cyan(`
41
- \u{1F504} Processing files without metadata...`));for(let n of i)try{await w(n.path,!1)&&(e.added++,console.log(t.green(` \u2713 Added metadata to ${n.path}`)));}catch(l){e.errors.push(`${n.path}: ${l.message}`),console.log(t.red(` \u2717 Error in ${n.path}`));}if(s.length>0)if(console.log(t.yellow(`
42
- \u26A0\uFE0F ${s.length} file(s) already have metadata exports`)),a.force){console.log(t.cyan(`
43
- \u{1F504} Overwriting all existing metadata (--force)...`));for(let n of s)try{await w(n.path,!0)&&(e.overwritten++,console.log(t.yellow(` \u2713 Overwritten ${n.path}`)));}catch(l){e.errors.push(`${n.path}: ${l.message}`),console.log(t.red(` \u2717 Error in ${n.path}`));}}else {console.log(t.cyan(`
44
- \u{1F504} Processing files with existing metadata...`));for(let n of s){let l=await v({type:"confirm",name:"overwrite",message:`Overwrite metadata in ${n.path}?`,initial:!1});if(l.overwrite===void 0){console.log(t.yellow(`
45
- \u274C Operation cancelled`));break}if(l.overwrite)try{await w(n.path,!0)&&(e.overwritten++,console.log(t.yellow(` \u2713 Overwritten ${n.path}`)));}catch(f){e.errors.push(`${n.path}: ${f.message}`),console.log(t.red(` \u2717 Error in ${n.path}`));}else e.skipped++,console.log(t.gray(` \u25CB Skipped ${n.path}`));}}console.log(t.green.bold(`
29
+ `,i=o.split(`
30
+ `),r=i.length;for(let l=0;l<i.length;l++)if(i[l].startsWith("export default")||i[l].startsWith("export function")||i[l].startsWith("export const")&&!i[l].includes("metadata")){r=l;break}return i.splice(r,0,n),o=i.join(`
31
+ `),await u.writeFile(a,o,"utf8"),true}p.command("init").description("Initialize the SEOX SEO configuration").action(async a=>{if(console.log(e.cyan.bold(`
32
+ \u{1F9E0} ${m} - Initialization
33
+ `)),await u.pathExists(g(c))){let{overwrite:o}=await v({type:"confirm",name:"overwrite",message:`The ${g(c)} file already exists. Do you want to overwrite it?`,initial:false});if(!o){console.log(e.yellow("\u26A0\uFE0F Initialization canceled"));return}}let s=await v([{type:"text",name:"siteName",message:"Name of your site :",initial:"My Site"},{type:"text",name:"baseUrl",message:"Base URL (without trailing slash) :",initial:"https://mysite.com",validate:o=>o.startsWith("http")||"Invalid URL"},{type:"text",name:"siteDescription",message:"Default description :",initial:"A modern site built with Next.js"}]);if(!s.siteName){console.log(e.red("\u274C Initialization canceled"));return}let t=F("Creating files...").start();try{await u.ensureDir(w.join(process.cwd(),"lib"));let o=C.config;Object.entries(s).forEach(([n,i])=>{o=o.replace(new RegExp(`{{${n}}}`,"g"),i);}),await u.writeFile(g(c),o,"utf8"),t.succeed("Configuration created successfully!"),console.log(e.green(`
34
+ \u2705 File created : `)+e.gray(g(c))),console.log(e.cyan(`
35
+ \u{1F4DD} Next step :`)),console.log(e.white(" bunx seox configure")),console.log();}catch(o){t.fail("Error creating the configuration"),console.error(e.red(o.message)),process.exit(1);}});p.command("configure").description("Apply SEO configuration to all Next.js pages and layouts").option("--validate","Validate only without generating",false).option("--force","Force overwrite existing metadata without asking",false).action(async a=>{console.log(e.cyan.bold(`
36
+ \u2699\uFE0F ${m} - Configuration
37
+ `));let s=F("Reading configuration...").start();try{if(!await u.pathExists(g(c))){s.fail(c+" file not found"),console.log(e.yellow(`
38
+ \u{1F4A1} Run first: `)+e.white("bunx seox init"));return}s.text="Scanning Next.js files...";let t=await O();if(t.length===0){s.fail("No Next.js layout or page files found"),console.log(e.yellow(`
39
+ \u{1F4A1} Make sure you have an app/ or pages/ directory with layout.tsx/page.tsx files`));return}s.succeed(`Found ${t.length} file(s) to process`),console.log(e.cyan(`
40
+ \u{1F4C1} Files found:`)),t.forEach(r=>{let l=r.hasMetadata?e.yellow("(has metadata)"):e.green("(no metadata)");console.log(e.gray(` \u2022 ${r.path} ${l}`));});let o={added:0,overwritten:0,skipped:0,errors:[]},n=t.filter(r=>r.hasMetadata),i=t.filter(r=>!r.hasMetadata);console.log(e.cyan(`
41
+ \u{1F504} Processing files without metadata...`));for(let r of i)try{await x(r.path,!1)&&(o.added++,console.log(e.green(` \u2713 Added metadata to ${r.path}`)));}catch(l){o.errors.push(`${r.path}: ${l.message}`),console.log(e.red(` \u2717 Error in ${r.path}`));}if(n.length>0)if(console.log(e.yellow(`
42
+ \u26A0\uFE0F ${n.length} file(s) already have metadata exports`)),a.force){console.log(e.cyan(`
43
+ \u{1F504} Overwriting all existing metadata (--force)...`));for(let r of n)try{await x(r.path,!0)&&(o.overwritten++,console.log(e.yellow(` \u2713 Overwritten ${r.path}`)));}catch(l){o.errors.push(`${r.path}: ${l.message}`),console.log(e.red(` \u2717 Error in ${r.path}`));}}else {console.log(e.cyan(`
44
+ \u{1F504} Processing files with existing metadata...`));for(let r of n){let l=await v({type:"confirm",name:"overwrite",message:`Overwrite metadata in ${r.path}?`,initial:!1});if(l.overwrite===void 0){console.log(e.yellow(`
45
+ \u274C Operation cancelled`));break}if(l.overwrite)try{await x(r.path,!0)&&(o.overwritten++,console.log(e.yellow(` \u2713 Overwritten ${r.path}`)));}catch(f){o.errors.push(`${r.path}: ${f.message}`),console.log(e.red(` \u2717 Error in ${r.path}`));}else o.skipped++,console.log(e.gray(` \u25CB Skipped ${r.path}`));}}console.log(e.green.bold(`
46
46
  \u2705 Configuration Summary:
47
- `)),console.log(t.gray(` \u2022 ${e.added} file(s) with metadata added`)),e.overwritten>0&&console.log(t.yellow(` \u2022 ${e.overwritten} file(s) overwritten`)),e.skipped>0&&console.log(t.gray(` \u2022 ${e.skipped} file(s) skipped`)),e.errors.length>0&&(console.log(t.red(` \u2022 ${e.errors.length} error(s):`)),e.errors.forEach(n=>{console.log(t.red(` - ${n}`));})),(e.added>0||e.overwritten>0)&&(console.log(t.cyan.bold(`
47
+ `)),console.log(e.gray(` \u2022 ${o.added} file(s) with metadata added`)),o.overwritten>0&&console.log(e.yellow(` \u2022 ${o.overwritten} file(s) overwritten`)),o.skipped>0&&console.log(e.gray(` \u2022 ${o.skipped} file(s) skipped`)),o.errors.length>0&&(console.log(e.red(` \u2022 ${o.errors.length} error(s):`)),o.errors.forEach(r=>{console.log(e.red(` - ${r}`));})),(o.added>0||o.overwritten>0)&&(console.log(e.cyan.bold(`
48
48
  \u{1F4DD} Next Steps:
49
- `)),console.log(t.white(" The following metadata export has been added to your files:")),console.log(t.gray(" import { seoConfig } from '@/lib/seo';")),console.log(t.gray(` export const metadata = seoConfig.configToMetadata();
50
- `)),console.log(t.white(" To customize metadata for specific pages, you can:")),console.log(t.gray(" 1. Pass overrides to configToMetadata():")),console.log(t.gray(" export const metadata = seoConfig.configToMetadata({")),console.log(t.gray(' title: "Custom Page Title",')),console.log(t.gray(' description: "Custom description"')),console.log(t.gray(` });
51
- `)),console.log(t.gray(" 2. Or manually modify the metadata object after generation")),console.log());}catch(o){r.fail(`Error during configuration. You may have to check your configuration file in ${g(c)}.`),console.error(t.red(o.message)),process.exit(1);}});p.command("doctor").description("Check the validity of your SEO configuration").action(async()=>{console.log(t.cyan.bold(`
52
- \u{1FA7A} MetaNext - Diagnostic SEO
53
- `));let a=I("Analyzing...").start();try{if(!await m.pathExists(g(c))){a.fail(c+" file not found");return}let o=(await import(g(c))).default;a.stop();let e=O(o);if(e.errors.length===0&&e.warnings.length===0){console.log(t.green(`\u2705 No issues detected ! Your SEO configuration is optimal.
54
- `));return}e.errors.length>0&&(console.log(t.red.bold(`\u274C ERRORS :
55
- `)),e.errors.map(s=>console.log(t.red(` \u2022 ${s}`))),console.log()),e.warnings.length>0&&(console.log(t.yellow.bold(`\u26A0\uFE0F WARNINGS :
56
- `)),e.warnings.map(s=>console.log(t.yellow(` \u2022 ${s}`))),console.log()),e.suggestions.length>0&&(console.log(t.cyan.bold(`\u{1F4A1} SUGGESTIONS :
57
- `)),e.suggestions.map(s=>console.log(t.cyan(` \u2022 ${s}`))),console.log());}catch(r){a.fail("Error during diagnosis"),console.error(t.red(r.message));}});p.parse(process.argv);var ye=p;export{ye as default};
49
+ `)),console.log(e.white(" The following metadata export has been added to your files:")),console.log(e.gray(" import { seoConfig } from '@/lib/seo';")),console.log(e.gray(` export const metadata = seoConfig.configToMetadata();
50
+ `)),console.log(e.white(" To customize metadata for specific pages, you can:")),console.log(e.gray(" 1. Pass overrides to configToMetadata():")),console.log(e.gray(" export const metadata = seoConfig.configToMetadata({")),console.log(e.gray(' title: "Custom Page Title",')),console.log(e.gray(' description: "Custom description"')),console.log(e.gray(` });
51
+ `)),console.log(e.gray(" 2. Or manually modify the metadata object after generation")),console.log());}catch(t){s.fail(`Error during configuration. You may have to check your configuration file in ${g(c)}.`),console.error(e.red(t.message)),process.exit(1);}});p.command("doctor").description("Check the validity of your SEO configuration").action(async()=>{console.log(e.cyan.bold(`
52
+ \u{1FA7A} ${m} - SEO Diagnostic
53
+ `));let a=F("Analyzing...").start();try{if(!await u.pathExists(g(c))){a.fail(c+" file not found");return}let t=(await import(g(c))).default;a.stop();let o=b(t);if(o.errors.length===0&&o.warnings.length===0){console.log(e.green(`\u2705 No issues detected ! Your SEO configuration is optimal.
54
+ `));return}o.errors.length>0&&(console.log(e.red.bold(`\u274C ERRORS :
55
+ `)),o.errors.map(n=>console.log(e.red(` \u2022 ${n}`))),console.log()),o.warnings.length>0&&(console.log(e.yellow.bold(`\u26A0\uFE0F WARNINGS :
56
+ `)),o.warnings.map(n=>console.log(e.yellow(` \u2022 ${n}`))),console.log()),o.suggestions.length>0&&(console.log(e.cyan.bold(`\u{1F4A1} SUGGESTIONS :
57
+ `)),o.suggestions.map(n=>console.log(e.cyan(` \u2022 ${n}`))),console.log());}catch(s){a.fail("Error during diagnosis"),console.error(e.red(s.message));}});p.parse(process.argv);var xo=p;export{xo as default};
package/dist/next.cjs CHANGED
@@ -1 +1 @@
1
- 'use strict';var n=class{config;constructor(t){this.config=t;}configToMetadata(t){let o={...this.config,...t},i={title:o.title,description:o.description,keywords:o.keywords,creator:o.creator,publisher:o.publisher,authors:o.authors?.map(e=>({name:e.name,url:e.url})),manifest:o.manifest,icons:o.icons?{...this.config.icons,...t?.icons}:void 0,formatDetection:o.formatDetection?{...this.config.formatDetection,...t?.formatDetection}:void 0,openGraph:o.openGraph?{...this.config.openGraph,...t?.openGraph,url:t?.openGraph?.url??this.config.openGraph?.url??this.config.url,siteName:t?.openGraph?.siteName??this.config.openGraph?.siteName??this.config.name}:void 0,twitter:o.twitter?{...this.config.twitter,...t?.twitter}:void 0,robots:o.robots?{...this.config.robots,...t?.robots,googleBot:t?.robots?.googleBot||this.config.robots?.googleBot?{...this.config.robots?.googleBot,...t?.robots?.googleBot}:void 0}:void 0};return Object.fromEntries(Object.entries(i).filter(([e,a])=>a!==void 0))}generatePageMetadata(t){return this.configToMetadata(t)}};exports.MetaNext=n;
1
+ 'use strict';var n=class{config;constructor(t){this.config=t;}configToMetadata(t){let o={...this.config,...t},i={title:o.title,description:o.description,keywords:o.keywords,creator:o.creator,publisher:o.publisher,authors:o.authors?.map(e=>({name:e.name,url:e.url})),manifest:o.manifest,icons:o.icons?{...this.config.icons,...t?.icons}:void 0,formatDetection:o.formatDetection?{...this.config.formatDetection,...t?.formatDetection}:void 0,openGraph:o.openGraph?{...this.config.openGraph,...t?.openGraph,url:t?.openGraph?.url??this.config.openGraph?.url??this.config.url,siteName:t?.openGraph?.siteName??this.config.openGraph?.siteName??this.config.name}:void 0,twitter:o.twitter?{...this.config.twitter,...t?.twitter}:void 0,robots:o.robots?{...this.config.robots,...t?.robots,googleBot:t?.robots?.googleBot||this.config.robots?.googleBot?{...this.config.robots?.googleBot,...t?.robots?.googleBot}:void 0}:void 0};return Object.fromEntries(Object.entries(i).filter(([e,a])=>a!==void 0))}generatePageMetadata(t){return this.configToMetadata(t)}};exports.Seox=n;
package/dist/next.d.cts CHANGED
@@ -3,11 +3,11 @@ import { Metadata } from 'next';
3
3
  import 'next/dist/lib/metadata/types/metadata-types';
4
4
  import 'next/dist/lib/metadata/types/opengraph-types';
5
5
 
6
- declare class MetaNext {
6
+ declare class Seox {
7
7
  private config;
8
8
  constructor(config: SEOConfig);
9
9
  configToMetadata(overrides?: Partial<SEOConfig>): Metadata;
10
10
  generatePageMetadata(overrides?: Partial<SEOConfig>): Metadata;
11
11
  }
12
12
 
13
- export { MetaNext, SEOConfig };
13
+ export { SEOConfig, Seox };
package/dist/next.d.ts CHANGED
@@ -3,11 +3,11 @@ import { Metadata } from 'next';
3
3
  import 'next/dist/lib/metadata/types/metadata-types';
4
4
  import 'next/dist/lib/metadata/types/opengraph-types';
5
5
 
6
- declare class MetaNext {
6
+ declare class Seox {
7
7
  private config;
8
8
  constructor(config: SEOConfig);
9
9
  configToMetadata(overrides?: Partial<SEOConfig>): Metadata;
10
10
  generatePageMetadata(overrides?: Partial<SEOConfig>): Metadata;
11
11
  }
12
12
 
13
- export { MetaNext, SEOConfig };
13
+ export { SEOConfig, Seox };
package/dist/next.js CHANGED
@@ -1 +1 @@
1
- var n=class{config;constructor(t){this.config=t;}configToMetadata(t){let o={...this.config,...t},i={title:o.title,description:o.description,keywords:o.keywords,creator:o.creator,publisher:o.publisher,authors:o.authors?.map(e=>({name:e.name,url:e.url})),manifest:o.manifest,icons:o.icons?{...this.config.icons,...t?.icons}:void 0,formatDetection:o.formatDetection?{...this.config.formatDetection,...t?.formatDetection}:void 0,openGraph:o.openGraph?{...this.config.openGraph,...t?.openGraph,url:t?.openGraph?.url??this.config.openGraph?.url??this.config.url,siteName:t?.openGraph?.siteName??this.config.openGraph?.siteName??this.config.name}:void 0,twitter:o.twitter?{...this.config.twitter,...t?.twitter}:void 0,robots:o.robots?{...this.config.robots,...t?.robots,googleBot:t?.robots?.googleBot||this.config.robots?.googleBot?{...this.config.robots?.googleBot,...t?.robots?.googleBot}:void 0}:void 0};return Object.fromEntries(Object.entries(i).filter(([e,a])=>a!==void 0))}generatePageMetadata(t){return this.configToMetadata(t)}};export{n as MetaNext};
1
+ var n=class{config;constructor(t){this.config=t;}configToMetadata(t){let o={...this.config,...t},i={title:o.title,description:o.description,keywords:o.keywords,creator:o.creator,publisher:o.publisher,authors:o.authors?.map(e=>({name:e.name,url:e.url})),manifest:o.manifest,icons:o.icons?{...this.config.icons,...t?.icons}:void 0,formatDetection:o.formatDetection?{...this.config.formatDetection,...t?.formatDetection}:void 0,openGraph:o.openGraph?{...this.config.openGraph,...t?.openGraph,url:t?.openGraph?.url??this.config.openGraph?.url??this.config.url,siteName:t?.openGraph?.siteName??this.config.openGraph?.siteName??this.config.name}:void 0,twitter:o.twitter?{...this.config.twitter,...t?.twitter}:void 0,robots:o.robots?{...this.config.robots,...t?.robots,googleBot:t?.robots?.googleBot||this.config.robots?.googleBot?{...this.config.robots?.googleBot,...t?.robots?.googleBot}:void 0}:void 0};return Object.fromEntries(Object.entries(i).filter(([e,a])=>a!==void 0))}generatePageMetadata(t){return this.configToMetadata(t)}};export{n as Seox};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "seox",
3
- "version": "0.0.1",
3
+ "version": "0.1.0",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },