fall back to English on corrupt content files (#32629)
This commit is contained in:
@@ -1,6 +1,20 @@
|
||||
import path from 'path'
|
||||
import fs from 'fs/promises'
|
||||
import Page from './page.js'
|
||||
|
||||
import languages from './languages.js'
|
||||
import Page, { FrontmatterErrorsError } from './page.js'
|
||||
|
||||
// If you run `export DEBUG_TRANSLATION_FALLBACKS=true` in your terminal,
|
||||
// every time a translation file fails to initialize we fall back to English
|
||||
// and write a warning to stdout.
|
||||
const DEBUG_TRANSLATION_FALLBACKS = Boolean(
|
||||
JSON.parse(process.env.DEBUG_TRANSLATION_FALLBACKS || 'false')
|
||||
)
|
||||
// If you don't want to fall back to English automatically on corrupt
|
||||
// translation files, set `export THROW_TRANSLATION_ERRORS=true`
|
||||
const THROW_TRANSLATION_ERRORS = Boolean(
|
||||
JSON.parse(process.env.THROW_TRANSLATION_ERRORS || 'false')
|
||||
)
|
||||
|
||||
// Module level cache
|
||||
const _basePaths = new Map()
|
||||
@@ -30,11 +44,39 @@ export default async function createTree(originalPath, langObj) {
|
||||
const relativePath = filepath.replace(`${basePath}/`, '')
|
||||
|
||||
// Initialize the Page! This is where the file reads happen.
|
||||
const page = await Page.init({
|
||||
let page
|
||||
try {
|
||||
page = await Page.init({
|
||||
basePath,
|
||||
relativePath,
|
||||
languageCode: langObj.code,
|
||||
})
|
||||
} catch (err) {
|
||||
if (
|
||||
!THROW_TRANSLATION_ERRORS &&
|
||||
err instanceof FrontmatterErrorsError &&
|
||||
langObj.code !== 'en'
|
||||
) {
|
||||
// Something corrupt in the `.md` file caused it to throw an
|
||||
// error from reading it in. Let's "gracefully" recover by
|
||||
// swapping this one out for the English content and pretend it
|
||||
// exists in this other language.
|
||||
const englishBasePath = getBasePath(languages.en.dir)
|
||||
page = await Page.init({
|
||||
basePath: englishBasePath,
|
||||
relativePath,
|
||||
languageCode: langObj.code,
|
||||
})
|
||||
if (DEBUG_TRANSLATION_FALLBACKS) {
|
||||
console.warn(
|
||||
`Unable to initialized ${path.join(basePath, relativePath)} due to frontmatter errors. ` +
|
||||
`Will proceed with using ${path.join(englishBasePath, relativePath)} instead.`
|
||||
)
|
||||
}
|
||||
} else {
|
||||
throw err
|
||||
}
|
||||
}
|
||||
|
||||
if (!page) {
|
||||
// Do not throw an error if Early Access is not available.
|
||||
|
||||
12
lib/page.js
12
lib/page.js
@@ -25,6 +25,13 @@ import { allTools } from './all-tools.js'
|
||||
// every single time, we turn it into a Set once.
|
||||
const productMapKeysAsSet = new Set(Object.keys(productMap))
|
||||
|
||||
export class FrontmatterErrorsError extends Error {
|
||||
constructor(message, frontmatterErrors) {
|
||||
super(message)
|
||||
this.frontmatterErrors = frontmatterErrors
|
||||
}
|
||||
}
|
||||
|
||||
class Page {
|
||||
static async init(opts) {
|
||||
opts = await Page.read(opts)
|
||||
@@ -61,7 +68,10 @@ class Page {
|
||||
|
||||
constructor(opts) {
|
||||
if (opts.frontmatterErrors.length) {
|
||||
throw new Error(JSON.stringify(opts.frontmatterErrors, null, 2))
|
||||
throw new FrontmatterErrorsError(
|
||||
`${opts.frontmatterErrors.length} frontmatter errors trying to load ${opts.fullPath}`,
|
||||
opts.frontmatterErrors
|
||||
)
|
||||
}
|
||||
delete opts.frontmatterErrors
|
||||
Object.assign(this, { ...opts })
|
||||
|
||||
@@ -3,7 +3,7 @@ import path from 'path'
|
||||
import cheerio from 'cheerio'
|
||||
import { describe, expect } from '@jest/globals'
|
||||
|
||||
import Page from '../../lib/page.js'
|
||||
import Page, { FrontmatterErrorsError } from '../../lib/page.js'
|
||||
import { allVersions } from '../../lib/all-versions.js'
|
||||
import enterpriseServerReleases, { latest } from '../../lib/enterprise-server-releases.js'
|
||||
import nonEnterpriseDefaultVersion from '../../lib/non-enterprise-default-version.js'
|
||||
@@ -727,7 +727,7 @@ describe('catches errors thrown in Page class', () => {
|
||||
})
|
||||
}
|
||||
|
||||
await expect(getPage).rejects.toThrowError('invalid frontmatter entry')
|
||||
await expect(getPage).rejects.toThrow(FrontmatterErrorsError)
|
||||
})
|
||||
|
||||
test('missing versions frontmatter', async () => {
|
||||
|
||||
Reference in New Issue
Block a user