@webnumseoagent/next 0.1.14 → 0.1.15
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/bin/cli.mjs +7 -4
- package/bin/wrap.mjs +37 -19
- package/package.json +1 -1
package/bin/cli.mjs
CHANGED
|
@@ -319,7 +319,7 @@ async function init() {
|
|
|
319
319
|
log("\n Осталось вручную (замени `return { … }` на):");
|
|
320
320
|
for (const m of manual) {
|
|
321
321
|
log(` • ${path.relative(root, m.p)}`);
|
|
322
|
-
log(` \x1b[36mimport { seoMeta } from "${clientFor(path.relative(path.join(root, appDir), m.p))}";\n return seoMeta({ route: ${m.expr}, locale, fallback: { /* прежний объект */ } });\x1b[0m`);
|
|
322
|
+
log(` \x1b[36mimport { seoMeta } from "${clientFor(path.relative(path.join(root, appDir), m.p))}";\n return seoMeta({ route: ${paramsExpr(m.expr)}, locale, fallback: { /* прежний объект */ } });\x1b[0m`);
|
|
323
323
|
}
|
|
324
324
|
}
|
|
325
325
|
|
|
@@ -342,7 +342,7 @@ async function init() {
|
|
|
342
342
|
const rel = path.relative(path.join(root, appDir), p);
|
|
343
343
|
const { expr } = routeFromFile(rel);
|
|
344
344
|
log(`\n • \x1b[1m${path.relative(root, p)}\x1b[0m`);
|
|
345
|
-
log(` \x1b[36mreturn seoMeta({ route: ${expr}, locale, fallback: { /* твой прежний объект меты */ } });\x1b[0m`);
|
|
345
|
+
log(` \x1b[36mreturn seoMeta({ route: ${paramsExpr(expr)}, locale, fallback: { /* твой прежний объект меты */ } });\x1b[0m`);
|
|
346
346
|
}
|
|
347
347
|
}
|
|
348
348
|
|
|
@@ -382,14 +382,17 @@ function routeFromFile(relFromApp) {
|
|
|
382
382
|
if (!segs.length) return { expr: '"/"', dynamic: false };
|
|
383
383
|
let dynamic = false;
|
|
384
384
|
const parts = segs.map((seg) => {
|
|
385
|
-
const m = seg.match(/^\[(?:\.\.\.)?(
|
|
386
|
-
if (m) { dynamic = true; return "${" + m[1] + "}"; }
|
|
385
|
+
const m = seg.match(/^\[+(?:\.\.\.)?(.+?)\]+$/); // [slug], [...slug], [[...slug]]
|
|
386
|
+
if (m) { dynamic = true; return "${" + m[1].replace(/[.\[\]]/g, "") + "}"; }
|
|
387
387
|
return seg;
|
|
388
388
|
});
|
|
389
389
|
const pathStr = "/" + parts.join("/");
|
|
390
390
|
return { expr: dynamic ? "`" + pathStr + "`" : `"${pathStr}"`, dynamic };
|
|
391
391
|
}
|
|
392
392
|
|
|
393
|
+
// Ручной сниппет вставляется в generateMetadata({ params }) — сегменты идут через params.
|
|
394
|
+
const paramsExpr = (expr) => expr.replace(/\$\{(\w+)\}/g, "${params.$1}");
|
|
395
|
+
|
|
393
396
|
async function findMetadataPages(dir, acc = []) {
|
|
394
397
|
for (const e of await fs.readdir(dir, { withFileTypes: true })) {
|
|
395
398
|
const p = path.join(dir, e.name);
|
package/bin/wrap.mjs
CHANGED
|
@@ -104,27 +104,45 @@ export async function wrapFile(code, routeExpr, importSpec) {
|
|
|
104
104
|
// locale опционально (мультиязычные — есть, одноязычные — нет).
|
|
105
105
|
const hasLocale = /\blocale\b/.test(code);
|
|
106
106
|
|
|
107
|
-
//
|
|
108
|
-
//
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
107
|
+
// Строим корректные обращения к динамическим сегментам. В generateMetadata сегмент
|
|
108
|
+
// ВСЕГДА доступен через объект params (Next всегда передаёт { params }); голое имя
|
|
109
|
+
// корректно ТОЛЬКО если сегмент явно деструктурирован в сигнатуре. Опираемся на САМУ
|
|
110
|
+
// сигнатуру (а не на скан всего файла — там `id` мог встретиться где угодно) и, если
|
|
111
|
+
// нужно, нормализуем сигнатуру, чтобы params/сегменты гарантированно были в области видимости.
|
|
112
|
+
const segNames = [...routeExpr.matchAll(/\$\{(\w+)\}/g)].map((m) => m[1]);
|
|
113
|
+
let effRoute = routeExpr;
|
|
114
|
+
if (segNames.length) {
|
|
115
|
+
const mkPat = (src) => babelParser.parseExpression(src, { plugins }).params[0]; // паттерн-параметр стрелки
|
|
116
|
+
const destructured = new Set(); // сегменты, связанные как отдельные переменные в сигнатуре
|
|
117
|
+
let base = "params";
|
|
118
|
+
const p0 = fn.params && fn.params[0];
|
|
119
|
+
if (!p0) {
|
|
120
|
+
fn.params = fn.params || [];
|
|
121
|
+
fn.params[0] = mkPat("({ params }) => 0"); // нет параметра → добавляем { params }
|
|
115
122
|
} else if (p0.type === "Identifier") {
|
|
116
|
-
|
|
123
|
+
base = p0.name + ".params"; // generateMetadata(props) → props.params
|
|
124
|
+
} else if (p0.type === "ObjectPattern") {
|
|
125
|
+
const pp = p0.properties.find((x) => x.key && x.key.name === "params");
|
|
126
|
+
if (!pp) {
|
|
127
|
+
p0.properties.unshift(mkPat("({ params }) => 0").properties[0]); // { searchParams } → добавляем params
|
|
128
|
+
} else if (pp.value && pp.value.type === "Identifier") {
|
|
129
|
+
base = pp.value.name; // { params } или { params: p }
|
|
130
|
+
} else if (pp.value && pp.value.type === "ObjectPattern") {
|
|
131
|
+
// Вложенная деструктуризация { params: { id } } — сегменты как отдельные переменные;
|
|
132
|
+
// недостающие добавляем в паттерн, чтобы они были в области видимости.
|
|
133
|
+
for (const prop of pp.value.properties) if (prop.key) destructured.add(prop.key.name);
|
|
134
|
+
for (const seg of segNames) if (!destructured.has(seg)) {
|
|
135
|
+
pp.value.properties.push(mkPat(`({ ${seg} }) => 0`).properties[0]);
|
|
136
|
+
destructured.add(seg);
|
|
137
|
+
}
|
|
138
|
+
base = null; // используем голое имя для всех сегментов
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
for (const seg of segNames) {
|
|
142
|
+
if (base !== null && !destructured.has(seg)) {
|
|
143
|
+
effRoute = effRoute.replace("${" + seg + "}", "${" + base + "." + seg + "}");
|
|
144
|
+
}
|
|
117
145
|
}
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
// Динамические параметры маршрута: если параметр деструктурирован (есть как
|
|
121
|
-
// отдельная переменная) — используем его напрямую (${slug}); иначе — через
|
|
122
|
-
// объект params (${params.slug}). Это чинит страницы, где обращаются как params.X.
|
|
123
|
-
let effRoute = routeExpr;
|
|
124
|
-
for (const m of [...routeExpr.matchAll(/\$\{(\w+)\}/g)]) {
|
|
125
|
-
const name = m[1];
|
|
126
|
-
const standalone = new RegExp("(?<!\\.)\\b" + name + "\\b").test(code);
|
|
127
|
-
if (!standalone) effRoute = effRoute.replace("${" + name + "}", "${" + paramsBase + "." + name + "}");
|
|
128
146
|
}
|
|
129
147
|
|
|
130
148
|
const returns = collectReturns(fn.body, fn);
|
package/package.json
CHANGED