@seo-partner/adapters 0.0.0-stage → 1.0.3
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 +21 -0
- package/dist/ast-merger.d.ts +24 -0
- package/dist/ast-merger.d.ts.map +1 -0
- package/dist/ast-merger.js +85 -0
- package/dist/ast-merger.js.map +1 -0
- package/dist/astro-adapter.d.ts +19 -0
- package/dist/astro-adapter.d.ts.map +1 -0
- package/dist/astro-adapter.js +114 -0
- package/dist/astro-adapter.js.map +1 -0
- package/dist/blog-scaffold-generator.d.ts +8 -0
- package/dist/blog-scaffold-generator.d.ts.map +1 -0
- package/dist/blog-scaffold-generator.js +138 -0
- package/dist/blog-scaffold-generator.js.map +1 -0
- package/dist/contract.d.ts +21 -0
- package/dist/contract.d.ts.map +1 -0
- package/dist/contract.js +2 -0
- package/dist/contract.js.map +1 -0
- package/dist/detector.d.ts +15 -0
- package/dist/detector.d.ts.map +1 -0
- package/dist/detector.js +40 -0
- package/dist/detector.js.map +1 -0
- package/dist/django-adapter.d.ts +13 -0
- package/dist/django-adapter.d.ts.map +1 -0
- package/dist/django-adapter.js +133 -0
- package/dist/django-adapter.js.map +1 -0
- package/dist/index.d.ts +32 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +32 -0
- package/dist/index.js.map +1 -0
- package/dist/laravel-adapter.d.ts +7 -0
- package/dist/laravel-adapter.d.ts.map +1 -0
- package/dist/laravel-adapter.js +35 -0
- package/dist/laravel-adapter.js.map +1 -0
- package/dist/layout-title-resolver.d.ts +8 -0
- package/dist/layout-title-resolver.d.ts.map +1 -0
- package/dist/layout-title-resolver.js +28 -0
- package/dist/layout-title-resolver.js.map +1 -0
- package/dist/nextjs-adapter.d.ts +15 -0
- package/dist/nextjs-adapter.d.ts.map +1 -0
- package/dist/nextjs-adapter.js +83 -0
- package/dist/nextjs-adapter.js.map +1 -0
- package/dist/nuxt-adapter.d.ts +19 -0
- package/dist/nuxt-adapter.d.ts.map +1 -0
- package/dist/nuxt-adapter.js +108 -0
- package/dist/nuxt-adapter.js.map +1 -0
- package/dist/parsers/astro-parser.d.ts +8 -0
- package/dist/parsers/astro-parser.d.ts.map +1 -0
- package/dist/parsers/astro-parser.js +218 -0
- package/dist/parsers/astro-parser.js.map +1 -0
- package/dist/parsers/dtl-parser.d.ts +7 -0
- package/dist/parsers/dtl-parser.d.ts.map +1 -0
- package/dist/parsers/dtl-parser.js +143 -0
- package/dist/parsers/dtl-parser.js.map +1 -0
- package/dist/parsers/html-parser.d.ts +3 -0
- package/dist/parsers/html-parser.d.ts.map +1 -0
- package/dist/parsers/html-parser.js +195 -0
- package/dist/parsers/html-parser.js.map +1 -0
- package/dist/parsers/layout-resolver.d.ts +44 -0
- package/dist/parsers/layout-resolver.d.ts.map +1 -0
- package/dist/parsers/layout-resolver.js +85 -0
- package/dist/parsers/layout-resolver.js.map +1 -0
- package/dist/parsers/php-route-parser.d.ts +11 -0
- package/dist/parsers/php-route-parser.d.ts.map +1 -0
- package/dist/parsers/php-route-parser.js +194 -0
- package/dist/parsers/php-route-parser.js.map +1 -0
- package/dist/parsers/php-template-parser.d.ts +3 -0
- package/dist/parsers/php-template-parser.d.ts.map +1 -0
- package/dist/parsers/php-template-parser.js +230 -0
- package/dist/parsers/php-template-parser.js.map +1 -0
- package/dist/parsers/python-url-parser.d.ts +19 -0
- package/dist/parsers/python-url-parser.d.ts.map +1 -0
- package/dist/parsers/python-url-parser.js +69 -0
- package/dist/parsers/python-url-parser.js.map +1 -0
- package/dist/parsers/remix-parser.d.ts +3 -0
- package/dist/parsers/remix-parser.d.ts.map +1 -0
- package/dist/parsers/remix-parser.js +139 -0
- package/dist/parsers/remix-parser.js.map +1 -0
- package/dist/parsers/robots-sitemap-parser.d.ts +15 -0
- package/dist/parsers/robots-sitemap-parser.d.ts.map +1 -0
- package/dist/parsers/robots-sitemap-parser.js +100 -0
- package/dist/parsers/robots-sitemap-parser.js.map +1 -0
- package/dist/parsers/route-normalizer.d.ts +11 -0
- package/dist/parsers/route-normalizer.d.ts.map +1 -0
- package/dist/parsers/route-normalizer.js +59 -0
- package/dist/parsers/route-normalizer.js.map +1 -0
- package/dist/parsers/svelte-parser.d.ts +3 -0
- package/dist/parsers/svelte-parser.d.ts.map +1 -0
- package/dist/parsers/svelte-parser.js +148 -0
- package/dist/parsers/svelte-parser.js.map +1 -0
- package/dist/parsers/tsx-ast-parser.d.ts +4 -0
- package/dist/parsers/tsx-ast-parser.d.ts.map +1 -0
- package/dist/parsers/tsx-ast-parser.js +380 -0
- package/dist/parsers/tsx-ast-parser.js.map +1 -0
- package/dist/parsers/vue-sfc-parser.d.ts +3 -0
- package/dist/parsers/vue-sfc-parser.d.ts.map +1 -0
- package/dist/parsers/vue-sfc-parser.js +183 -0
- package/dist/parsers/vue-sfc-parser.js.map +1 -0
- package/dist/php-adapter.d.ts +12 -0
- package/dist/php-adapter.d.ts.map +1 -0
- package/dist/php-adapter.js +42 -0
- package/dist/php-adapter.js.map +1 -0
- package/dist/php-native-adapter.d.ts +7 -0
- package/dist/php-native-adapter.d.ts.map +1 -0
- package/dist/php-native-adapter.js +31 -0
- package/dist/php-native-adapter.js.map +1 -0
- package/dist/remix-adapter.d.ts +13 -0
- package/dist/remix-adapter.d.ts.map +1 -0
- package/dist/remix-adapter.js +91 -0
- package/dist/remix-adapter.js.map +1 -0
- package/dist/sitemap-builder.d.ts +10 -0
- package/dist/sitemap-builder.d.ts.map +1 -0
- package/dist/sitemap-builder.js +37 -0
- package/dist/sitemap-builder.js.map +1 -0
- package/dist/skeleton-detector.d.ts +14 -0
- package/dist/skeleton-detector.d.ts.map +1 -0
- package/dist/skeleton-detector.js +33 -0
- package/dist/skeleton-detector.js.map +1 -0
- package/dist/static-adapter.d.ts +12 -0
- package/dist/static-adapter.d.ts.map +1 -0
- package/dist/static-adapter.js +44 -0
- package/dist/static-adapter.js.map +1 -0
- package/dist/sveltekit-adapter.d.ts +19 -0
- package/dist/sveltekit-adapter.d.ts.map +1 -0
- package/dist/sveltekit-adapter.js +115 -0
- package/dist/sveltekit-adapter.js.map +1 -0
- package/dist/symfony-adapter.d.ts +7 -0
- package/dist/symfony-adapter.d.ts.map +1 -0
- package/dist/symfony-adapter.js +23 -0
- package/dist/symfony-adapter.js.map +1 -0
- package/package.json +23 -3
- package/src/ast-merger.ts +123 -0
- package/src/astro-adapter.ts +155 -0
- package/src/blog-scaffold-generator.ts +153 -0
- package/src/contract.ts +40 -0
- package/src/detector.ts +46 -0
- package/src/django-adapter.ts +173 -0
- package/src/index.ts +31 -0
- package/src/laravel-adapter.ts +45 -0
- package/src/layout-title-resolver.ts +37 -0
- package/src/nextjs-adapter.ts +116 -0
- package/src/nuxt-adapter.ts +148 -0
- package/src/parsers/astro-parser.ts +249 -0
- package/src/parsers/dtl-parser.ts +166 -0
- package/src/parsers/html-parser.ts +214 -0
- package/src/parsers/layout-resolver.ts +112 -0
- package/src/parsers/php-route-parser.ts +254 -0
- package/src/parsers/php-template-parser.ts +303 -0
- package/src/parsers/python-url-parser.ts +92 -0
- package/src/parsers/remix-parser.ts +161 -0
- package/src/parsers/robots-sitemap-parser.ts +128 -0
- package/src/parsers/route-normalizer.ts +70 -0
- package/src/parsers/svelte-parser.ts +167 -0
- package/src/parsers/tsx-ast-parser.ts +404 -0
- package/src/parsers/vue-sfc-parser.ts +207 -0
- package/src/php-adapter.ts +68 -0
- package/src/php-native-adapter.ts +46 -0
- package/src/remix-adapter.ts +123 -0
- package/src/sitemap-builder.ts +57 -0
- package/src/skeleton-detector.ts +56 -0
- package/src/static-adapter.ts +62 -0
- package/src/sveltekit-adapter.ts +160 -0
- package/src/symfony-adapter.ts +33 -0
- package/tsconfig.json +9 -0
- package/README.md +0 -3
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { isPrivateRoutePattern } from './nextjs-adapter.js';
|
|
2
|
+
import { detectPhpFlavor, discoverNativePhpRoutes, parseLaravelRoutes, parseSymfonyRoutes, } from './parsers/php-route-parser.js';
|
|
3
|
+
import { parsePhpOrTemplateFile } from './parsers/php-template-parser.js';
|
|
4
|
+
export class PhpAdapter {
|
|
5
|
+
id = 'php';
|
|
6
|
+
name = 'PHP Ecosystem (Laravel / Blade, Symfony / Twig, Native PHP / Laragon)';
|
|
7
|
+
version = '1.0';
|
|
8
|
+
capabilities = {
|
|
9
|
+
routes: true,
|
|
10
|
+
metadata: true,
|
|
11
|
+
headings: true,
|
|
12
|
+
internalLinks: true,
|
|
13
|
+
jsonLd: true,
|
|
14
|
+
images: true,
|
|
15
|
+
robotsAndSitemap: true,
|
|
16
|
+
};
|
|
17
|
+
async detect(_projectRoot, filePaths, contentsByPath) {
|
|
18
|
+
return detectPhpFlavor(filePaths, contentsByPath) !== null;
|
|
19
|
+
}
|
|
20
|
+
async discoverRoutes(_projectRoot, filePaths, contentsByPath, sitemapPaths) {
|
|
21
|
+
const flavor = detectPhpFlavor(filePaths, contentsByPath);
|
|
22
|
+
if (!flavor)
|
|
23
|
+
return [];
|
|
24
|
+
const entries = flavor === 'laravel'
|
|
25
|
+
? parseLaravelRoutes(filePaths, contentsByPath)
|
|
26
|
+
: flavor === 'symfony'
|
|
27
|
+
? parseSymfonyRoutes(filePaths, contentsByPath)
|
|
28
|
+
: discoverNativePhpRoutes(filePaths);
|
|
29
|
+
return entries.map((entry) => ({
|
|
30
|
+
pattern: entry.pattern,
|
|
31
|
+
filePath: entry.filePath,
|
|
32
|
+
routerKind: entry.flavor,
|
|
33
|
+
renderingMode: 'ssr-ssg',
|
|
34
|
+
isPrivate: isPrivateRoutePattern(entry.pattern),
|
|
35
|
+
inSitemap: sitemapPaths.has(entry.pattern),
|
|
36
|
+
}));
|
|
37
|
+
}
|
|
38
|
+
async extractRoute(projectRoot, route, fileContent) {
|
|
39
|
+
return parsePhpOrTemplateFile(projectRoot, route, fileContent);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=php-adapter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"php-adapter.js","sourceRoot":"","sources":["../src/php-adapter.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,EACL,eAAe,EACf,uBAAuB,EACvB,kBAAkB,EAClB,kBAAkB,GACnB,MAAM,+BAA+B,CAAC;AACvC,OAAO,EAAE,sBAAsB,EAAE,MAAM,kCAAkC,CAAC;AAE1E,MAAM,OAAO,UAAU;IACL,EAAE,GAAG,KAAK,CAAC;IACX,IAAI,GAAG,uEAAuE,CAAC;IAC/E,OAAO,GAAG,KAAc,CAAC;IACzB,YAAY,GAAwB;QAClD,MAAM,EAAE,IAAI;QACZ,QAAQ,EAAE,IAAI;QACd,QAAQ,EAAE,IAAI;QACd,aAAa,EAAE,IAAI;QACnB,MAAM,EAAE,IAAI;QACZ,MAAM,EAAE,IAAI;QACZ,gBAAgB,EAAE,IAAI;KACvB,CAAC;IAEK,KAAK,CAAC,MAAM,CACjB,YAAoB,EACpB,SAAgC,EAChC,cAA2C;QAE3C,OAAO,eAAe,CAAC,SAAS,EAAE,cAAc,CAAC,KAAK,IAAI,CAAC;IAC7D,CAAC;IAEM,KAAK,CAAC,cAAc,CACzB,YAAoB,EACpB,SAAgC,EAChC,cAA2C,EAC3C,YAAiC;QAEjC,MAAM,MAAM,GAAG,eAAe,CAAC,SAAS,EAAE,cAAc,CAAC,CAAC;QAC1D,IAAI,CAAC,MAAM;YAAE,OAAO,EAAE,CAAC;QAEvB,MAAM,OAAO,GACX,MAAM,KAAK,SAAS;YAClB,CAAC,CAAC,kBAAkB,CAAC,SAAS,EAAE,cAAc,CAAC;YAC/C,CAAC,CAAC,MAAM,KAAK,SAAS;gBACpB,CAAC,CAAC,kBAAkB,CAAC,SAAS,EAAE,cAAc,CAAC;gBAC/C,CAAC,CAAC,uBAAuB,CAAC,SAAS,CAAC,CAAC;QAE3C,OAAO,OAAO,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;YAC7B,OAAO,EAAE,KAAK,CAAC,OAAO;YACtB,QAAQ,EAAE,KAAK,CAAC,QAAQ;YACxB,UAAU,EAAE,KAAK,CAAC,MAAM;YACxB,aAAa,EAAE,SAAS;YACxB,SAAS,EAAE,qBAAqB,CAAC,KAAK,CAAC,OAAO,CAAC;YAC/C,SAAS,EAAE,YAAY,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC;SAC3C,CAAC,CAAC,CAAC;IACN,CAAC;IAEM,KAAK,CAAC,YAAY,CACvB,WAAmB,EACnB,KAAsB,EACtB,WAAmB;QAEnB,OAAO,sBAAsB,CAAC,WAAW,EAAE,KAAK,EAAE,WAAW,CAAC,CAAC;IACjE,CAAC;CACF"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"php-native-adapter.d.ts","sourceRoot":"","sources":["../src/php-native-adapter.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,mBAAmB;IAClC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,wBAAgB,sBAAsB,CACpC,UAAU,EAAE,MAAM,EAClB,IAAI,EAAE,mBAAmB,GACxB,MAAM,CAmCR"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
export function patchPhpNativeTemplate(sourceCode, meta) {
|
|
2
|
+
let result = sourceCode;
|
|
3
|
+
const vars = [];
|
|
4
|
+
if (meta.title && !/\$pageTitle\s*=/i.test(result)) {
|
|
5
|
+
vars.push(`$pageTitle = '${meta.title.replace(/'/g, "\\'")}';`);
|
|
6
|
+
}
|
|
7
|
+
if (meta.description && !/\$metaDescription\s*=/i.test(result)) {
|
|
8
|
+
vars.push(`$metaDescription = '${meta.description.replace(/'/g, "\\'")}';`);
|
|
9
|
+
}
|
|
10
|
+
if (meta.canonical && !/\$canonicalUrl\s*=/i.test(result)) {
|
|
11
|
+
vars.push(`$canonicalUrl = '${meta.canonical.replace(/'/g, "\\'")}';`);
|
|
12
|
+
}
|
|
13
|
+
if (vars.length === 0) {
|
|
14
|
+
return result;
|
|
15
|
+
}
|
|
16
|
+
const varsBlock = vars.join('\n') + '\n';
|
|
17
|
+
// If file starts with <?php, inject before any header include
|
|
18
|
+
if (/<\?php/i.test(result)) {
|
|
19
|
+
if (/(include|require|include_once|require_once)\s*['"][^'"]*header[^'"]*['"]/i.test(result)) {
|
|
20
|
+
result = result.replace(/((?:include|require|include_once|require_once)\s*['"][^'"]*header[^'"]*['"])/i, `${varsBlock}$1`);
|
|
21
|
+
}
|
|
22
|
+
else {
|
|
23
|
+
result = result.replace(/(<\?php\s*\n)/i, `$1${varsBlock}`);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
else {
|
|
27
|
+
result = `<?php\n${varsBlock}?>\n` + result;
|
|
28
|
+
}
|
|
29
|
+
return result;
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=php-native-adapter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"php-native-adapter.js","sourceRoot":"","sources":["../src/php-native-adapter.ts"],"names":[],"mappings":"AAMA,MAAM,UAAU,sBAAsB,CACpC,UAAkB,EAClB,IAAyB;IAEzB,IAAI,MAAM,GAAG,UAAU,CAAC;IAExB,MAAM,IAAI,GAAa,EAAE,CAAC;IAC1B,IAAI,IAAI,CAAC,KAAK,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;QACnD,IAAI,CAAC,IAAI,CAAC,iBAAiB,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;IAClE,CAAC;IACD,IAAI,IAAI,CAAC,WAAW,IAAI,CAAC,wBAAwB,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;QAC/D,IAAI,CAAC,IAAI,CAAC,uBAAuB,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;IAC9E,CAAC;IACD,IAAI,IAAI,CAAC,SAAS,IAAI,CAAC,qBAAqB,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;QAC1D,IAAI,CAAC,IAAI,CAAC,oBAAoB,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;IACzE,CAAC;IAED,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACtB,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IAEzC,8DAA8D;IAC9D,IAAI,SAAS,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;QAC3B,IAAI,2EAA2E,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;YAC7F,MAAM,GAAG,MAAM,CAAC,OAAO,CACrB,+EAA+E,EAC/E,GAAG,SAAS,IAAI,CACjB,CAAC;QACJ,CAAC;aAAM,CAAC;YACN,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC,gBAAgB,EAAE,KAAK,SAAS,EAAE,CAAC,CAAC;QAC9D,CAAC;IACH,CAAC;SAAM,CAAC;QACN,MAAM,GAAG,UAAU,SAAS,MAAM,GAAG,MAAM,CAAC;IAC9C,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { DiscoveredRoute, ExtractedRouteData } from '@seo-partner/core';
|
|
2
|
+
import type { AdapterCapabilities, AdapterVersion, FrameworkAdapter } from './contract.js';
|
|
3
|
+
export declare class RemixAdapter implements FrameworkAdapter {
|
|
4
|
+
readonly id = "remix";
|
|
5
|
+
readonly name = "Remix / React Router v7";
|
|
6
|
+
readonly version: AdapterVersion;
|
|
7
|
+
readonly capabilities: AdapterCapabilities;
|
|
8
|
+
private readonly layoutResolver;
|
|
9
|
+
detect(projectRoot: string, filePaths: ReadonlyArray<string>, contentsByPath: ReadonlyMap<string, string>): Promise<boolean>;
|
|
10
|
+
discoverRoutes(projectRoot: string, filePaths: ReadonlyArray<string>, contentsByPath: ReadonlyMap<string, string>, sitemapPaths: ReadonlySet<string>): Promise<ReadonlyArray<DiscoveredRoute>>;
|
|
11
|
+
extractRoute(projectRoot: string, route: DiscoveredRoute, fileContent: string): Promise<ExtractedRouteData>;
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=remix-adapter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"remix-adapter.d.ts","sourceRoot":"","sources":["../src/remix-adapter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAC7E,OAAO,KAAK,EAAE,mBAAmB,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAK3F,qBAAa,YAAa,YAAW,gBAAgB;IACnD,SAAgB,EAAE,WAAW;IAC7B,SAAgB,IAAI,6BAA6B;IACjD,SAAgB,OAAO,EAAE,cAAc,CAAS;IAChD,SAAgB,YAAY,EAAE,mBAAmB,CAQ/C;IAEF,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAwB;IAE1C,MAAM,CACjB,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,aAAa,CAAC,MAAM,CAAC,EAChC,cAAc,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,GAC1C,OAAO,CAAC,OAAO,CAAC;IAyBN,cAAc,CACzB,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,aAAa,CAAC,MAAM,CAAC,EAChC,cAAc,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,EAC3C,YAAY,EAAE,WAAW,CAAC,MAAM,CAAC,GAChC,OAAO,CAAC,aAAa,CAAC,eAAe,CAAC,CAAC;IAoD7B,YAAY,CACvB,WAAW,EAAE,MAAM,EACnB,KAAK,EAAE,eAAe,EACtB,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,kBAAkB,CAAC;CAS/B"}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { parseRemixRoute } from './parsers/remix-parser.js';
|
|
2
|
+
import { normalizeRoutePattern } from './parsers/route-normalizer.js';
|
|
3
|
+
import { LayoutResolver } from './parsers/layout-resolver.js';
|
|
4
|
+
export class RemixAdapter {
|
|
5
|
+
id = 'remix';
|
|
6
|
+
name = 'Remix / React Router v7';
|
|
7
|
+
version = '1.0';
|
|
8
|
+
capabilities = {
|
|
9
|
+
routes: true,
|
|
10
|
+
metadata: true,
|
|
11
|
+
headings: true,
|
|
12
|
+
internalLinks: true,
|
|
13
|
+
jsonLd: true,
|
|
14
|
+
images: true,
|
|
15
|
+
robotsAndSitemap: true,
|
|
16
|
+
};
|
|
17
|
+
layoutResolver = new LayoutResolver();
|
|
18
|
+
async detect(projectRoot, filePaths, contentsByPath) {
|
|
19
|
+
for (const filePath of filePaths) {
|
|
20
|
+
const normalized = filePath.replace(/\\/g, '/');
|
|
21
|
+
if (normalized === 'remix.config.js' ||
|
|
22
|
+
normalized === 'remix.config.ts' ||
|
|
23
|
+
normalized === 'remix.config.mjs' ||
|
|
24
|
+
normalized === 'react-router.config.ts' ||
|
|
25
|
+
normalized === 'react-router.config.js') {
|
|
26
|
+
return true;
|
|
27
|
+
}
|
|
28
|
+
if (normalized === 'package.json') {
|
|
29
|
+
const content = contentsByPath.get(filePath) ?? '';
|
|
30
|
+
if (content.includes('"@remix-run/') ||
|
|
31
|
+
content.includes('"react-router"')) {
|
|
32
|
+
return true;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
return false;
|
|
37
|
+
}
|
|
38
|
+
async discoverRoutes(projectRoot, filePaths, contentsByPath, sitemapPaths) {
|
|
39
|
+
const routes = [];
|
|
40
|
+
// Pre-cache root layout from app/root.tsx
|
|
41
|
+
for (const filePath of filePaths) {
|
|
42
|
+
const normalized = filePath.replace(/\\/g, '/');
|
|
43
|
+
if (normalized === 'app/root.tsx' || normalized === 'app/root.jsx') {
|
|
44
|
+
const content = contentsByPath.get(filePath) ?? '';
|
|
45
|
+
const parsed = parseRemixRoute({
|
|
46
|
+
pattern: '',
|
|
47
|
+
filePath,
|
|
48
|
+
routerKind: 'remix',
|
|
49
|
+
renderingMode: 'ssr-ssg',
|
|
50
|
+
isPrivate: false,
|
|
51
|
+
inSitemap: false,
|
|
52
|
+
}, content);
|
|
53
|
+
this.layoutResolver.registerLayout({
|
|
54
|
+
filePath,
|
|
55
|
+
htmlLang: parsed.htmlLang,
|
|
56
|
+
title: parsed.title,
|
|
57
|
+
description: parsed.description,
|
|
58
|
+
canonical: parsed.canonical,
|
|
59
|
+
robots: parsed.robots,
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
for (const filePath of filePaths) {
|
|
64
|
+
const normalized = filePath.replace(/\\/g, '/');
|
|
65
|
+
if (!normalized.startsWith('app/routes/'))
|
|
66
|
+
continue;
|
|
67
|
+
if (!/\.(tsx|jsx|ts|js)$/i.test(normalized))
|
|
68
|
+
continue;
|
|
69
|
+
const relativeInsideRoutes = normalized.slice('app/routes/'.length);
|
|
70
|
+
const pattern = normalizeRoutePattern(relativeInsideRoutes, 'remix');
|
|
71
|
+
const inSitemap = sitemapPaths.has(pattern);
|
|
72
|
+
routes.push({
|
|
73
|
+
pattern,
|
|
74
|
+
filePath,
|
|
75
|
+
routerKind: 'remix',
|
|
76
|
+
renderingMode: 'ssr-ssg',
|
|
77
|
+
isPrivate: false,
|
|
78
|
+
inSitemap,
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
return routes;
|
|
82
|
+
}
|
|
83
|
+
async extractRoute(projectRoot, route, fileContent) {
|
|
84
|
+
let extracted = parseRemixRoute(route, fileContent);
|
|
85
|
+
// Apply root layout inheritance
|
|
86
|
+
const layoutCandidates = ['app/root.tsx', 'app/root.jsx'];
|
|
87
|
+
extracted = this.layoutResolver.applyInheritance(extracted, layoutCandidates);
|
|
88
|
+
return extracted;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
//# sourceMappingURL=remix-adapter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"remix-adapter.js","sourceRoot":"","sources":["../src/remix-adapter.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export interface SitemapRouteEntry {
|
|
2
|
+
pattern: string;
|
|
3
|
+
isPrivate: boolean;
|
|
4
|
+
lastmod?: string;
|
|
5
|
+
changefreq?: 'always' | 'hourly' | 'daily' | 'weekly' | 'monthly' | 'yearly' | 'never';
|
|
6
|
+
priority?: number;
|
|
7
|
+
}
|
|
8
|
+
export declare function buildSitemapXml(routes: ReadonlyArray<SitemapRouteEntry>, siteUrl: string): string;
|
|
9
|
+
export declare function buildNextJsAppSitemap(routes: ReadonlyArray<SitemapRouteEntry>, siteUrl: string): string;
|
|
10
|
+
//# sourceMappingURL=sitemap-builder.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sitemap-builder.d.ts","sourceRoot":"","sources":["../src/sitemap-builder.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,OAAO,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,QAAQ,GAAG,QAAQ,GAAG,OAAO,GAAG,QAAQ,GAAG,SAAS,GAAG,QAAQ,GAAG,OAAO,CAAC;IACvF,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,wBAAgB,eAAe,CAC7B,MAAM,EAAE,aAAa,CAAC,iBAAiB,CAAC,EACxC,OAAO,EAAE,MAAM,GACd,MAAM,CAoBR;AAED,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,aAAa,CAAC,iBAAiB,CAAC,EACxC,OAAO,EAAE,MAAM,GACd,MAAM,CAmBR"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
export function buildSitemapXml(routes, siteUrl) {
|
|
2
|
+
const cleanBase = siteUrl.replace(/\/+$/, '');
|
|
3
|
+
const publicRoutes = routes.filter((r) => !r.isPrivate);
|
|
4
|
+
const urlEntries = publicRoutes.map((r) => {
|
|
5
|
+
const cleanPattern = r.pattern.startsWith('/') ? r.pattern : `/${r.pattern}`;
|
|
6
|
+
const loc = `${cleanBase}${cleanPattern === '/' ? '' : cleanPattern}`;
|
|
7
|
+
const lastmodTag = r.lastmod ? `\n <lastmod>${r.lastmod}</lastmod>` : '';
|
|
8
|
+
const changefreqTag = r.changefreq ? `\n <changefreq>${r.changefreq}</changefreq>` : '';
|
|
9
|
+
const priorityTag = typeof r.priority === 'number' ? `\n <priority>${r.priority.toFixed(1)}</priority>` : '';
|
|
10
|
+
return ` <url>\n <loc>${loc}</loc>${lastmodTag}${changefreqTag}${priorityTag}\n </url>`;
|
|
11
|
+
});
|
|
12
|
+
return [
|
|
13
|
+
'<?xml version="1.0" encoding="UTF-8"?>',
|
|
14
|
+
'<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">',
|
|
15
|
+
...urlEntries,
|
|
16
|
+
'</urlset>',
|
|
17
|
+
].join('\n');
|
|
18
|
+
}
|
|
19
|
+
export function buildNextJsAppSitemap(routes, siteUrl) {
|
|
20
|
+
const cleanBase = siteUrl.replace(/\/+$/, '');
|
|
21
|
+
const publicRoutes = routes.filter((r) => !r.isPrivate);
|
|
22
|
+
const items = publicRoutes.map((r) => {
|
|
23
|
+
const cleanPattern = r.pattern.startsWith('/') ? r.pattern : `/${r.pattern}`;
|
|
24
|
+
const loc = `${cleanBase}${cleanPattern === '/' ? '' : cleanPattern}`;
|
|
25
|
+
return ` {\n url: '${loc}',\n lastModified: new Date(),\n changeFrequency: 'weekly',\n priority: ${cleanPattern === '/' ? '1.0' : '0.8'},\n },`;
|
|
26
|
+
});
|
|
27
|
+
return [
|
|
28
|
+
"import type { MetadataRoute } from 'next';",
|
|
29
|
+
'',
|
|
30
|
+
'export default function sitemap(): MetadataRoute.Sitemap {',
|
|
31
|
+
' return [',
|
|
32
|
+
...items,
|
|
33
|
+
' ];',
|
|
34
|
+
'}',
|
|
35
|
+
].join('\n');
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=sitemap-builder.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sitemap-builder.js","sourceRoot":"","sources":["../src/sitemap-builder.ts"],"names":[],"mappings":"AAQA,MAAM,UAAU,eAAe,CAC7B,MAAwC,EACxC,OAAe;IAEf,MAAM,SAAS,GAAG,OAAO,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IAC9C,MAAM,YAAY,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;IAExD,MAAM,UAAU,GAAG,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;QACxC,MAAM,YAAY,GAAG,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,CAAC;QAC7E,MAAM,GAAG,GAAG,GAAG,SAAS,GAAG,YAAY,KAAK,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,YAAY,EAAE,CAAC;QACtE,MAAM,UAAU,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,kBAAkB,CAAC,CAAC,OAAO,YAAY,CAAC,CAAC,CAAC,EAAE,CAAC;QAC5E,MAAM,aAAa,GAAG,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,qBAAqB,CAAC,CAAC,UAAU,eAAe,CAAC,CAAC,CAAC,EAAE,CAAC;QAC3F,MAAM,WAAW,GAAG,OAAO,CAAC,CAAC,QAAQ,KAAK,QAAQ,CAAC,CAAC,CAAC,mBAAmB,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,CAAC;QAEhH,OAAO,qBAAqB,GAAG,SAAS,UAAU,GAAG,aAAa,GAAG,WAAW,YAAY,CAAC;IAC/F,CAAC,CAAC,CAAC;IAEH,OAAO;QACL,wCAAwC;QACxC,8DAA8D;QAC9D,GAAG,UAAU;QACb,WAAW;KACZ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACf,CAAC;AAED,MAAM,UAAU,qBAAqB,CACnC,MAAwC,EACxC,OAAe;IAEf,MAAM,SAAS,GAAG,OAAO,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IAC9C,MAAM,YAAY,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;IAExD,MAAM,KAAK,GAAG,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;QACnC,MAAM,YAAY,GAAG,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,CAAC;QAC7E,MAAM,GAAG,GAAG,GAAG,SAAS,GAAG,YAAY,KAAK,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,YAAY,EAAE,CAAC;QACtE,OAAO,sBAAsB,GAAG,0FAA0F,YAAY,KAAK,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,WAAW,CAAC;IAC5K,CAAC,CAAC,CAAC;IAEH,OAAO;QACL,4CAA4C;QAC5C,EAAE;QACF,4DAA4D;QAC5D,YAAY;QACZ,GAAG,KAAK;QACR,MAAM;QACN,GAAG;KACJ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACf,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export interface SeoFileInventory {
|
|
2
|
+
robots: {
|
|
3
|
+
appRobotsTs?: string;
|
|
4
|
+
publicRobotsTxt?: string;
|
|
5
|
+
hasConflict: boolean;
|
|
6
|
+
};
|
|
7
|
+
sitemap: {
|
|
8
|
+
appSitemapTs?: string;
|
|
9
|
+
publicSitemapXml?: string;
|
|
10
|
+
hasConflict: boolean;
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
export declare function detectSeoFileInventory(projectRoot: string): SeoFileInventory;
|
|
14
|
+
//# sourceMappingURL=skeleton-detector.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skeleton-detector.d.ts","sourceRoot":"","sources":["../src/skeleton-detector.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE;QACN,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,eAAe,CAAC,EAAE,MAAM,CAAC;QACzB,WAAW,EAAE,OAAO,CAAC;KACtB,CAAC;IACF,OAAO,EAAE;QACP,YAAY,CAAC,EAAE,MAAM,CAAC;QACtB,gBAAgB,CAAC,EAAE,MAAM,CAAC;QAC1B,WAAW,EAAE,OAAO,CAAC;KACtB,CAAC;CACH;AAED,wBAAgB,sBAAsB,CAAC,WAAW,EAAE,MAAM,GAAG,gBAAgB,CAsC5E"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
export function detectSeoFileInventory(projectRoot) {
|
|
4
|
+
const checkExists = (rel) => {
|
|
5
|
+
const full = path.join(projectRoot, rel);
|
|
6
|
+
return fs.existsSync(full) ? rel : undefined;
|
|
7
|
+
};
|
|
8
|
+
const appRobotsTs = checkExists('app/robots.ts') ||
|
|
9
|
+
checkExists('app/robots.js') ||
|
|
10
|
+
checkExists('src/app/robots.ts') ||
|
|
11
|
+
checkExists('src/app/robots.js');
|
|
12
|
+
const publicRobotsTxt = checkExists('public/robots.txt') ||
|
|
13
|
+
checkExists('robots.txt');
|
|
14
|
+
const appSitemapTs = checkExists('app/sitemap.ts') ||
|
|
15
|
+
checkExists('app/sitemap.js') ||
|
|
16
|
+
checkExists('src/app/sitemap.ts') ||
|
|
17
|
+
checkExists('src/app/sitemap.js');
|
|
18
|
+
const publicSitemapXml = checkExists('public/sitemap.xml') ||
|
|
19
|
+
checkExists('sitemap.xml');
|
|
20
|
+
return {
|
|
21
|
+
robots: {
|
|
22
|
+
appRobotsTs,
|
|
23
|
+
publicRobotsTxt,
|
|
24
|
+
hasConflict: Boolean(appRobotsTs && publicRobotsTxt),
|
|
25
|
+
},
|
|
26
|
+
sitemap: {
|
|
27
|
+
appSitemapTs,
|
|
28
|
+
publicSitemapXml,
|
|
29
|
+
hasConflict: Boolean(appSitemapTs && publicSitemapXml),
|
|
30
|
+
},
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=skeleton-detector.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skeleton-detector.js","sourceRoot":"","sources":["../src/skeleton-detector.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAe7B,MAAM,UAAU,sBAAsB,CAAC,WAAmB;IACxD,MAAM,WAAW,GAAG,CAAC,GAAW,EAAE,EAAE;QAClC,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,GAAG,CAAC,CAAC;QACzC,OAAO,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC;IAC/C,CAAC,CAAC;IAEF,MAAM,WAAW,GACf,WAAW,CAAC,eAAe,CAAC;QAC5B,WAAW,CAAC,eAAe,CAAC;QAC5B,WAAW,CAAC,mBAAmB,CAAC;QAChC,WAAW,CAAC,mBAAmB,CAAC,CAAC;IAEnC,MAAM,eAAe,GACnB,WAAW,CAAC,mBAAmB,CAAC;QAChC,WAAW,CAAC,YAAY,CAAC,CAAC;IAE5B,MAAM,YAAY,GAChB,WAAW,CAAC,gBAAgB,CAAC;QAC7B,WAAW,CAAC,gBAAgB,CAAC;QAC7B,WAAW,CAAC,oBAAoB,CAAC;QACjC,WAAW,CAAC,oBAAoB,CAAC,CAAC;IAEpC,MAAM,gBAAgB,GACpB,WAAW,CAAC,oBAAoB,CAAC;QACjC,WAAW,CAAC,aAAa,CAAC,CAAC;IAE7B,OAAO;QACL,MAAM,EAAE;YACN,WAAW;YACX,eAAe;YACf,WAAW,EAAE,OAAO,CAAC,WAAW,IAAI,eAAe,CAAC;SACrD;QACD,OAAO,EAAE;YACP,YAAY;YACZ,gBAAgB;YAChB,WAAW,EAAE,OAAO,CAAC,YAAY,IAAI,gBAAgB,CAAC;SACvD;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { DiscoveredRoute, ExtractedRouteData } from '@seo-partner/core';
|
|
2
|
+
import type { AdapterCapabilities, FrameworkAdapter } from './contract.js';
|
|
3
|
+
export declare class StaticAdapter implements FrameworkAdapter {
|
|
4
|
+
readonly id = "static-html";
|
|
5
|
+
readonly name = "Static HTML & Markdown";
|
|
6
|
+
readonly version: "1.0";
|
|
7
|
+
readonly capabilities: AdapterCapabilities;
|
|
8
|
+
detect(_projectRoot: string, filePaths: ReadonlyArray<string>): Promise<boolean>;
|
|
9
|
+
discoverRoutes(_projectRoot: string, filePaths: ReadonlyArray<string>, _contentsByPath: ReadonlyMap<string, string>, sitemapPaths: ReadonlySet<string>): Promise<ReadonlyArray<DiscoveredRoute>>;
|
|
10
|
+
extractRoute(_projectRoot: string, route: DiscoveredRoute, fileContent: string): Promise<ExtractedRouteData>;
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=static-adapter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"static-adapter.d.ts","sourceRoot":"","sources":["../src/static-adapter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAC7E,OAAO,KAAK,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAI3E,qBAAa,aAAc,YAAW,gBAAgB;IACpD,SAAgB,EAAE,iBAAiB;IACnC,SAAgB,IAAI,4BAA4B;IAChD,SAAgB,OAAO,EAAG,KAAK,CAAU;IACzC,SAAgB,YAAY,EAAE,mBAAmB,CAQ/C;IAEW,MAAM,CACjB,YAAY,EAAE,MAAM,EACpB,SAAS,EAAE,aAAa,CAAC,MAAM,CAAC,GAC/B,OAAO,CAAC,OAAO,CAAC;IAIN,cAAc,CACzB,YAAY,EAAE,MAAM,EACpB,SAAS,EAAE,aAAa,CAAC,MAAM,CAAC,EAChC,eAAe,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,EAC5C,YAAY,EAAE,WAAW,CAAC,MAAM,CAAC,GAChC,OAAO,CAAC,aAAa,CAAC,eAAe,CAAC,CAAC;IAsB7B,YAAY,CACvB,YAAY,EAAE,MAAM,EACpB,KAAK,EAAE,eAAe,EACtB,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,kBAAkB,CAAC;CAG/B"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { isPrivateRoutePattern } from './nextjs-adapter.js';
|
|
2
|
+
import { parseStaticHtmlOrMarkdown } from './parsers/html-parser.js';
|
|
3
|
+
export class StaticAdapter {
|
|
4
|
+
id = 'static-html';
|
|
5
|
+
name = 'Static HTML & Markdown';
|
|
6
|
+
version = '1.0';
|
|
7
|
+
capabilities = {
|
|
8
|
+
routes: true,
|
|
9
|
+
metadata: true,
|
|
10
|
+
headings: true,
|
|
11
|
+
internalLinks: true,
|
|
12
|
+
jsonLd: true,
|
|
13
|
+
images: true,
|
|
14
|
+
robotsAndSitemap: true,
|
|
15
|
+
};
|
|
16
|
+
async detect(_projectRoot, filePaths) {
|
|
17
|
+
return filePaths.some((p) => p.endsWith('.html'));
|
|
18
|
+
}
|
|
19
|
+
async discoverRoutes(_projectRoot, filePaths, _contentsByPath, sitemapPaths) {
|
|
20
|
+
const routes = [];
|
|
21
|
+
for (const filePath of filePaths) {
|
|
22
|
+
if (filePath.endsWith('.html')) {
|
|
23
|
+
const clean = filePath
|
|
24
|
+
.replace(/^public\//, '')
|
|
25
|
+
.replace(/index\.html$/, '')
|
|
26
|
+
.replace(/\.html$/, '');
|
|
27
|
+
const pattern = clean.startsWith('/') ? clean : `/${clean}`;
|
|
28
|
+
routes.push({
|
|
29
|
+
pattern: pattern === '' ? '/' : pattern,
|
|
30
|
+
filePath,
|
|
31
|
+
routerKind: 'static-html',
|
|
32
|
+
renderingMode: 'static',
|
|
33
|
+
isPrivate: isPrivateRoutePattern(pattern),
|
|
34
|
+
inSitemap: sitemapPaths.has(pattern),
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return routes;
|
|
39
|
+
}
|
|
40
|
+
async extractRoute(_projectRoot, route, fileContent) {
|
|
41
|
+
return parseStaticHtmlOrMarkdown(route, fileContent);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
//# sourceMappingURL=static-adapter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"static-adapter.js","sourceRoot":"","sources":["../src/static-adapter.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,EAAE,yBAAyB,EAAE,MAAM,0BAA0B,CAAC;AAErE,MAAM,OAAO,aAAa;IACR,EAAE,GAAG,aAAa,CAAC;IACnB,IAAI,GAAG,wBAAwB,CAAC;IAChC,OAAO,GAAG,KAAc,CAAC;IACzB,YAAY,GAAwB;QAClD,MAAM,EAAE,IAAI;QACZ,QAAQ,EAAE,IAAI;QACd,QAAQ,EAAE,IAAI;QACd,aAAa,EAAE,IAAI;QACnB,MAAM,EAAE,IAAI;QACZ,MAAM,EAAE,IAAI;QACZ,gBAAgB,EAAE,IAAI;KACvB,CAAC;IAEK,KAAK,CAAC,MAAM,CACjB,YAAoB,EACpB,SAAgC;QAEhC,OAAO,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC;IACpD,CAAC;IAEM,KAAK,CAAC,cAAc,CACzB,YAAoB,EACpB,SAAgC,EAChC,eAA4C,EAC5C,YAAiC;QAEjC,MAAM,MAAM,GAAsB,EAAE,CAAC;QACrC,KAAK,MAAM,QAAQ,IAAI,SAAS,EAAE,CAAC;YACjC,IAAI,QAAQ,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;gBAC/B,MAAM,KAAK,GAAG,QAAQ;qBACnB,OAAO,CAAC,WAAW,EAAE,EAAE,CAAC;qBACxB,OAAO,CAAC,cAAc,EAAE,EAAE,CAAC;qBAC3B,OAAO,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC;gBAC1B,MAAM,OAAO,GAAG,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,KAAK,EAAE,CAAC;gBAC5D,MAAM,CAAC,IAAI,CAAC;oBACV,OAAO,EAAE,OAAO,KAAK,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO;oBACvC,QAAQ;oBACR,UAAU,EAAE,aAAa;oBACzB,aAAa,EAAE,QAAQ;oBACvB,SAAS,EAAE,qBAAqB,CAAC,OAAO,CAAC;oBACzC,SAAS,EAAE,YAAY,CAAC,GAAG,CAAC,OAAO,CAAC;iBACrC,CAAC,CAAC;YACL,CAAC;QACH,CAAC;QACD,OAAO,MAAM,CAAC;IAChB,CAAC;IAEM,KAAK,CAAC,YAAY,CACvB,YAAoB,EACpB,KAAsB,EACtB,WAAmB;QAEnB,OAAO,yBAAyB,CAAC,KAAK,EAAE,WAAW,CAAC,CAAC;IACvD,CAAC;CACF"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { DiscoveredRoute, ExtractedRouteData } from '@seo-partner/core';
|
|
2
|
+
import type { AdapterCapabilities, AdapterVersion, FrameworkAdapter } from './contract.js';
|
|
3
|
+
export declare class SvelteKitAdapter implements FrameworkAdapter {
|
|
4
|
+
readonly id = "sveltekit";
|
|
5
|
+
readonly name = "SvelteKit";
|
|
6
|
+
readonly version: AdapterVersion;
|
|
7
|
+
readonly capabilities: AdapterCapabilities;
|
|
8
|
+
private readonly layoutResolver;
|
|
9
|
+
detect(projectRoot: string, filePaths: ReadonlyArray<string>, contentsByPath: ReadonlyMap<string, string>): Promise<boolean>;
|
|
10
|
+
discoverRoutes(projectRoot: string, filePaths: ReadonlyArray<string>, contentsByPath: ReadonlyMap<string, string>, sitemapPaths: ReadonlySet<string>): Promise<ReadonlyArray<DiscoveredRoute>>;
|
|
11
|
+
extractRoute(projectRoot: string, route: DiscoveredRoute, fileContent: string): Promise<ExtractedRouteData>;
|
|
12
|
+
}
|
|
13
|
+
export interface SvelteKitMetaFields {
|
|
14
|
+
title?: string;
|
|
15
|
+
description?: string;
|
|
16
|
+
canonical?: string;
|
|
17
|
+
}
|
|
18
|
+
export declare function patchSvelteKitTemplate(sourceCode: string, meta: SvelteKitMetaFields): string;
|
|
19
|
+
//# sourceMappingURL=sveltekit-adapter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sveltekit-adapter.d.ts","sourceRoot":"","sources":["../src/sveltekit-adapter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAC7E,OAAO,KAAK,EAAE,mBAAmB,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAK3F,qBAAa,gBAAiB,YAAW,gBAAgB;IACvD,SAAgB,EAAE,eAAe;IACjC,SAAgB,IAAI,eAAe;IACnC,SAAgB,OAAO,EAAE,cAAc,CAAS;IAChD,SAAgB,YAAY,EAAE,mBAAmB,CAQ/C;IAEF,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAwB;IAE1C,MAAM,CACjB,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,aAAa,CAAC,MAAM,CAAC,EAChC,cAAc,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,GAC1C,OAAO,CAAC,OAAO,CAAC;IAqBN,cAAc,CACzB,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,aAAa,CAAC,MAAM,CAAC,EAChC,cAAc,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,EAC3C,YAAY,EAAE,WAAW,CAAC,MAAM,CAAC,GAChC,OAAO,CAAC,aAAa,CAAC,eAAe,CAAC,CAAC;IAoD7B,YAAY,CACvB,WAAW,EAAE,MAAM,EACnB,KAAK,EAAE,eAAe,EACtB,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,kBAAkB,CAAC;CAS/B;AAGD,MAAM,WAAW,mBAAmB;IAClC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,wBAAgB,sBAAsB,CACpC,UAAU,EAAE,MAAM,EAClB,IAAI,EAAE,mBAAmB,GACxB,MAAM,CA8BR"}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { parseSvelteComponent } from './parsers/svelte-parser.js';
|
|
2
|
+
import { normalizeRoutePattern } from './parsers/route-normalizer.js';
|
|
3
|
+
import { LayoutResolver } from './parsers/layout-resolver.js';
|
|
4
|
+
export class SvelteKitAdapter {
|
|
5
|
+
id = 'sveltekit';
|
|
6
|
+
name = 'SvelteKit';
|
|
7
|
+
version = '1.0';
|
|
8
|
+
capabilities = {
|
|
9
|
+
routes: true,
|
|
10
|
+
metadata: true,
|
|
11
|
+
headings: true,
|
|
12
|
+
internalLinks: true,
|
|
13
|
+
jsonLd: true,
|
|
14
|
+
images: true,
|
|
15
|
+
robotsAndSitemap: true,
|
|
16
|
+
};
|
|
17
|
+
layoutResolver = new LayoutResolver();
|
|
18
|
+
async detect(projectRoot, filePaths, contentsByPath) {
|
|
19
|
+
for (const filePath of filePaths) {
|
|
20
|
+
const normalized = filePath.replace(/\\/g, '/');
|
|
21
|
+
if (normalized === 'svelte.config.js' ||
|
|
22
|
+
normalized === 'svelte.config.ts' ||
|
|
23
|
+
normalized === 'svelte.config.mjs' ||
|
|
24
|
+
normalized === 'svelte.config.cjs') {
|
|
25
|
+
return true;
|
|
26
|
+
}
|
|
27
|
+
if (normalized === 'package.json') {
|
|
28
|
+
const content = contentsByPath.get(filePath) ?? '';
|
|
29
|
+
if (content.includes('"@sveltejs/kit"')) {
|
|
30
|
+
return true;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return false;
|
|
35
|
+
}
|
|
36
|
+
async discoverRoutes(projectRoot, filePaths, contentsByPath, sitemapPaths) {
|
|
37
|
+
const routes = [];
|
|
38
|
+
// Pre-cache layouts from src/routes/**/+layout.svelte
|
|
39
|
+
for (const filePath of filePaths) {
|
|
40
|
+
const normalized = filePath.replace(/\\/g, '/');
|
|
41
|
+
if (normalized.startsWith('src/routes/') && normalized.endsWith('+layout.svelte')) {
|
|
42
|
+
const content = contentsByPath.get(filePath) ?? '';
|
|
43
|
+
const parsed = parseSvelteComponent({
|
|
44
|
+
pattern: '',
|
|
45
|
+
filePath,
|
|
46
|
+
routerKind: 'sveltekit',
|
|
47
|
+
renderingMode: 'ssr-ssg',
|
|
48
|
+
isPrivate: false,
|
|
49
|
+
inSitemap: false,
|
|
50
|
+
}, content);
|
|
51
|
+
this.layoutResolver.registerLayout({
|
|
52
|
+
filePath,
|
|
53
|
+
htmlLang: parsed.htmlLang,
|
|
54
|
+
title: parsed.title,
|
|
55
|
+
description: parsed.description,
|
|
56
|
+
canonical: parsed.canonical,
|
|
57
|
+
robots: parsed.robots,
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
for (const filePath of filePaths) {
|
|
62
|
+
const normalized = filePath.replace(/\\/g, '/');
|
|
63
|
+
if (!normalized.startsWith('src/routes/'))
|
|
64
|
+
continue;
|
|
65
|
+
if (!normalized.endsWith('+page.svelte'))
|
|
66
|
+
continue;
|
|
67
|
+
const relativeInsideRoutes = normalized.slice('src/routes/'.length);
|
|
68
|
+
const pattern = normalizeRoutePattern(relativeInsideRoutes, 'sveltekit');
|
|
69
|
+
const inSitemap = sitemapPaths.has(pattern);
|
|
70
|
+
routes.push({
|
|
71
|
+
pattern,
|
|
72
|
+
filePath,
|
|
73
|
+
routerKind: 'sveltekit',
|
|
74
|
+
renderingMode: 'ssr-ssg',
|
|
75
|
+
isPrivate: false,
|
|
76
|
+
inSitemap,
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
return routes;
|
|
80
|
+
}
|
|
81
|
+
async extractRoute(projectRoot, route, fileContent) {
|
|
82
|
+
let extracted = parseSvelteComponent(route, fileContent);
|
|
83
|
+
// Apply hierarchical layout inheritance from leaf up to root
|
|
84
|
+
const parentLayouts = this.layoutResolver.findSvelteKitLayoutPaths(route.filePath);
|
|
85
|
+
extracted = this.layoutResolver.applyInheritance(extracted, parentLayouts);
|
|
86
|
+
return extracted;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
export function patchSvelteKitTemplate(sourceCode, meta) {
|
|
90
|
+
let result = sourceCode;
|
|
91
|
+
if (/<svelte:head>/i.test(result)) {
|
|
92
|
+
if (meta.title && !/<title>/i.test(result)) {
|
|
93
|
+
result = result.replace(/(<svelte:head>\s*\n)/i, `$1 <title>${meta.title}</title>\n`);
|
|
94
|
+
}
|
|
95
|
+
if (meta.description && !/<meta\s+name=["']description["']/i.test(result)) {
|
|
96
|
+
result = result.replace(/(<svelte:head>\s*\n)/i, `$1 <meta name="description" content="${meta.description.replace(/"/g, '"')}" />\n`);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
else {
|
|
100
|
+
const headLines = ['<svelte:head>'];
|
|
101
|
+
if (meta.title) {
|
|
102
|
+
headLines.push(` <title>${meta.title}</title>`);
|
|
103
|
+
}
|
|
104
|
+
if (meta.description) {
|
|
105
|
+
headLines.push(` <meta name="description" content="${meta.description.replace(/"/g, '"')}" />`);
|
|
106
|
+
}
|
|
107
|
+
if (meta.canonical) {
|
|
108
|
+
headLines.push(` <link rel="canonical" href="${meta.canonical}" />`);
|
|
109
|
+
}
|
|
110
|
+
headLines.push('</svelte:head>\n\n');
|
|
111
|
+
result = headLines.join('\n') + result;
|
|
112
|
+
}
|
|
113
|
+
return result;
|
|
114
|
+
}
|
|
115
|
+
//# sourceMappingURL=sveltekit-adapter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sveltekit-adapter.js","sourceRoot":"","sources":["../src/sveltekit-adapter.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"symfony-adapter.d.ts","sourceRoot":"","sources":["../src/symfony-adapter.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,iBAAiB;IAChC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,wBAAgB,wBAAwB,CACtC,UAAU,EAAE,MAAM,EAClB,IAAI,EAAE,iBAAiB,GACtB,MAAM,CAsBR"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export function patchSymfonyTwigTemplate(sourceCode, meta) {
|
|
2
|
+
let result = sourceCode;
|
|
3
|
+
if (meta.title && !/{%\s*block\s+title\s*%}/i.test(result)) {
|
|
4
|
+
const titleBlock = `{% block title %}${meta.title}{% endblock %}\n`;
|
|
5
|
+
if (/{%\s*extends[^%]+%}/i.test(result)) {
|
|
6
|
+
result = result.replace(/({%\s*extends[^%]+%}\s*\n)/i, `$1${titleBlock}`);
|
|
7
|
+
}
|
|
8
|
+
else {
|
|
9
|
+
result = titleBlock + result;
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
if (meta.description && !/<meta\s+name=["']description["']/i.test(result)) {
|
|
13
|
+
const descTag = `<meta name="description" content="${meta.description.replace(/"/g, '"')}">\n`;
|
|
14
|
+
if (/{%\s*block\s+title\s*%}[\s\S]*?{%\s*endblock\s*%}/i.test(result)) {
|
|
15
|
+
result = result.replace(/({%\s*block\s+title\s*%}[\s\S]*?{%\s*endblock\s*%}\s*\n)/i, `$1${descTag}`);
|
|
16
|
+
}
|
|
17
|
+
else {
|
|
18
|
+
result = descTag + result;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
return result;
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=symfony-adapter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"symfony-adapter.js","sourceRoot":"","sources":["../src/symfony-adapter.ts"],"names":[],"mappings":"AAMA,MAAM,UAAU,wBAAwB,CACtC,UAAkB,EAClB,IAAuB;IAEvB,IAAI,MAAM,GAAG,UAAU,CAAC;IAExB,IAAI,IAAI,CAAC,KAAK,IAAI,CAAC,0BAA0B,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;QAC3D,MAAM,UAAU,GAAG,oBAAoB,IAAI,CAAC,KAAK,kBAAkB,CAAC;QACpE,IAAI,sBAAsB,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;YACxC,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC,6BAA6B,EAAE,KAAK,UAAU,EAAE,CAAC,CAAC;QAC5E,CAAC;aAAM,CAAC;YACN,MAAM,GAAG,UAAU,GAAG,MAAM,CAAC;QAC/B,CAAC;IACH,CAAC;IAED,IAAI,IAAI,CAAC,WAAW,IAAI,CAAC,mCAAmC,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;QAC1E,MAAM,OAAO,GAAG,qCAAqC,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,IAAI,EAAE,QAAQ,CAAC,MAAM,CAAC;QACpG,IAAI,oDAAoD,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;YACtE,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC,2DAA2D,EAAE,KAAK,OAAO,EAAE,CAAC,CAAC;QACvG,CAAC;aAAM,CAAC;YACN,MAAM,GAAG,OAAO,GAAG,MAAM,CAAC;QAC5B,CAAC;IACH,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,26 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@seo-partner/adapters",
|
|
3
|
-
"version": "
|
|
4
|
-
"
|
|
5
|
-
"
|
|
3
|
+
"version": "1.0.3",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"main": "./dist/index.js",
|
|
6
|
+
"types": "./dist/index.d.ts",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": {
|
|
9
|
+
"types": "./dist/index.d.ts",
|
|
10
|
+
"default": "./dist/index.js"
|
|
11
|
+
}
|
|
12
|
+
},
|
|
13
|
+
"dependencies": {
|
|
14
|
+
"typescript": "^5.7.2",
|
|
15
|
+
"@seo-partner/core": "1.0.3"
|
|
16
|
+
},
|
|
17
|
+
"publishConfig": {
|
|
18
|
+
"access": "public"
|
|
19
|
+
},
|
|
20
|
+
"license": "MIT",
|
|
21
|
+
"author": "Firinze Gbènito Dossou",
|
|
22
|
+
"scripts": {
|
|
23
|
+
"build": "tsc -p tsconfig.json",
|
|
24
|
+
"typecheck": "tsc -p tsconfig.json --noEmit"
|
|
25
|
+
}
|
|
6
26
|
}
|