mnfst-render 0.4.6 → 0.4.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
File without changes
@@ -1144,6 +1144,9 @@ function loadAllLocaleContentData(manifest, rootDir, locales) {
1144
1144
  target[key] = (target[key] && typeof target[key] === 'object') ? target[key] : {};
1145
1145
  deepMerge(target[key], source[key]);
1146
1146
  } else {
1147
+ // Don't overwrite an existing nested object with a primitive — that creates
1148
+ // type asymmetry across locales and causes '[object Object]' in substitution pairs
1149
+ if (target[key] && typeof target[key] === 'object') continue;
1147
1150
  target[key] = source[key];
1148
1151
  }
1149
1152
  }
@@ -1152,12 +1155,25 @@ function loadAllLocaleContentData(manifest, rootDir, locales) {
1152
1155
  const result = new Map();
1153
1156
  for (const locale of locales) result.set(locale, {});
1154
1157
 
1158
+ // Read just the header row of a CSV to check which locale columns it contains.
1159
+ function csvLocaleColumns(csvPath) {
1160
+ if (!existsSync(csvPath)) return new Set();
1161
+ try {
1162
+ const firstLine = readFileSync(csvPath, 'utf8').split(/\r?\n/)[0] || '';
1163
+ return new Set(splitCsvLine(firstLine).slice(1)); // skip key column
1164
+ } catch { return new Set(); }
1165
+ }
1166
+
1155
1167
  for (const [, value] of Object.entries(data)) {
1156
1168
  if (typeof value === 'string') {
1157
1169
  // Single CSV with locale columns (all locales in one file)
1158
1170
  if (value.endsWith('.csv')) {
1159
1171
  const csvPath = join(rootDir, value.startsWith('/') ? value.slice(1) : value);
1172
+ const cols = csvLocaleColumns(csvPath);
1160
1173
  for (const locale of locales) {
1174
+ // Only include locales the CSV actually declares; falling back to the English
1175
+ // column for a missing locale silently poisons substitution pairs with English values.
1176
+ if (!cols.has(locale)) continue;
1161
1177
  deepMerge(result.get(locale), parseCsvToKeyValue(csvPath, locale));
1162
1178
  }
1163
1179
  }
@@ -1168,7 +1184,9 @@ function loadAllLocaleContentData(manifest, rootDir, locales) {
1168
1184
  for (const ref of refs) {
1169
1185
  if (typeof ref !== 'string' || !ref.endsWith('.csv')) continue;
1170
1186
  const csvPath = join(rootDir, ref.startsWith('/') ? ref.slice(1) : ref);
1187
+ const cols = csvLocaleColumns(csvPath);
1171
1188
  for (const locale of locales) {
1189
+ if (!cols.has(locale)) continue;
1172
1190
  deepMerge(result.get(locale), parseCsvToKeyValue(csvPath, locale));
1173
1191
  }
1174
1192
  }
@@ -1215,6 +1233,8 @@ function buildSubstitutionPairs(defaultLocaleData, targetLocaleData) {
1215
1233
  // Recurse into nested objects (produced by setNestedKey for dotted CSV keys)
1216
1234
  collectPairs(defaultVal, targetVal && typeof targetVal === 'object' ? targetVal : {});
1217
1235
  } else {
1236
+ // Skip if target is a non-primitive — String(obj) === '[object Object]' is never useful
1237
+ if (targetVal !== null && typeof targetVal === 'object') continue;
1218
1238
  const from = String(defaultVal ?? '').trim();
1219
1239
  const to = String(targetVal ?? '').trim();
1220
1240
  if (!from || from === to) continue;
@@ -2179,10 +2199,20 @@ async function runPrerender(config) {
2179
2199
  ) {
2180
2200
  try {
2181
2201
  const A = window.Alpine;
2182
- if (A && typeof A.$data === 'function') {
2183
- const scope = A.$data(n);
2184
- if (scope && Object.prototype.hasOwnProperty.call(scope, itemVar)) {
2185
- const raw = scope[itemVar];
2202
+ if (A) {
2203
+ // Alpine.evaluate(el, expr) evaluates in the full scope chain including
2204
+ // x-for loop variables, unlike Alpine.$data() which only sees x-data attrs.
2205
+ let raw = undefined;
2206
+ if (typeof A.evaluate === 'function') {
2207
+ raw = A.evaluate(n, itemVar);
2208
+ } else if (typeof A.$data === 'function') {
2209
+ // Fallback: $data only sees x-data scopes, not x-for vars
2210
+ const scope = A.$data(n);
2211
+ if (scope && Object.prototype.hasOwnProperty.call(scope, itemVar)) {
2212
+ raw = scope[itemVar];
2213
+ }
2214
+ }
2215
+ if (raw !== undefined && raw !== null) {
2186
2216
  // Serialize only own-enumerable properties to avoid circular refs / proxies
2187
2217
  const snapshot = JSON.parse(JSON.stringify(raw));
2188
2218
  n.setAttribute('x-data', JSON.stringify({ [itemVar]: snapshot }));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mnfst-render",
3
- "version": "0.4.6",
3
+ "version": "0.4.8",
4
4
  "description": "Render Manifest sites to static HTML for SEO",
5
5
  "type": "module",
6
6
  "bin": {