Complete statical parsing of withExtraLanguages
This commit is contained in:
parent
10d4da9fbf
commit
c07af8491c
@ -1,6 +1,6 @@
|
|||||||
import { type ThemeType, FALLBACK_LANGUAGE_TAG } from "../../shared/constants";
|
import { type ThemeType, FALLBACK_LANGUAGE_TAG } from "../../shared/constants";
|
||||||
import { crawl } from "../../tools/crawl";
|
import { crawl } from "../../tools/crawl";
|
||||||
import { join as pathJoin } from "path";
|
import { join as pathJoin, dirname as pathDirname } from "path";
|
||||||
import { symToStr } from "tsafe/symToStr";
|
import { symToStr } from "tsafe/symToStr";
|
||||||
import * as recast from "recast";
|
import * as recast from "recast";
|
||||||
import * as babelParser from "@babel/parser";
|
import * as babelParser from "@babel/parser";
|
||||||
@ -11,6 +11,7 @@ import { getThisCodebaseRootDirPath } from "../../tools/getThisCodebaseRootDirPa
|
|||||||
import * as fs from "fs";
|
import * as fs from "fs";
|
||||||
import { assert } from "tsafe/assert";
|
import { assert } from "tsafe/assert";
|
||||||
import type { BuildContext } from "../../shared/buildContext";
|
import type { BuildContext } from "../../shared/buildContext";
|
||||||
|
import { getAbsoluteAndInOsFormatPath } from "../../tools/getAbsoluteAndInOsFormatPath";
|
||||||
|
|
||||||
export type BuildContextLike = {
|
export type BuildContextLike = {
|
||||||
themeNames: string[];
|
themeNames: string[];
|
||||||
@ -112,20 +113,7 @@ export function generateMessageProperties(params: {
|
|||||||
if (i18nTsFilePath === undefined) {
|
if (i18nTsFilePath === undefined) {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
const root: recast.types.ASTNode = recast.parse(
|
const root = recastParseTs(i18nTsFilePath);
|
||||||
fs.readFileSync(i18nTsFilePath).toString("utf8"),
|
|
||||||
{
|
|
||||||
parser: {
|
|
||||||
parse: (code: string) =>
|
|
||||||
babelParser.parse(code, {
|
|
||||||
sourceType: "module",
|
|
||||||
plugins: ["typescript"]
|
|
||||||
}),
|
|
||||||
generator: babelGenerate,
|
|
||||||
types: babelTypes
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
return root;
|
return root;
|
||||||
})();
|
})();
|
||||||
|
|
||||||
@ -136,7 +124,10 @@ export function generateMessageProperties(params: {
|
|||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
let out: Record<string, { label: string; path: string }> = {};
|
let extraLanguageEntryByLanguageTag: Record<
|
||||||
|
string,
|
||||||
|
{ label: string; path: string }
|
||||||
|
> = {};
|
||||||
|
|
||||||
recast.visit(i18nTsRoot, {
|
recast.visit(i18nTsRoot, {
|
||||||
visitCallExpression: function (path) {
|
visitCallExpression: function (path) {
|
||||||
@ -225,7 +216,10 @@ export function generateMessageProperties(params: {
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (label && pathStr) {
|
if (label && pathStr) {
|
||||||
out[lang] = { label, path: pathStr };
|
extraLanguageEntryByLanguageTag[lang] = {
|
||||||
|
label,
|
||||||
|
path: pathStr
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -239,9 +233,69 @@ export function generateMessageProperties(params: {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
console.log(out);
|
const messages_defaultSet_by_languageTag_notInDefaultSet = Object.fromEntries(
|
||||||
|
Object.entries(extraLanguageEntryByLanguageTag).map(
|
||||||
|
([languageTag, { path: relativePathWithoutExt }]) => [
|
||||||
|
languageTag,
|
||||||
|
(() => {
|
||||||
|
const filePath = getAbsoluteAndInOsFormatPath({
|
||||||
|
pathIsh: relativePathWithoutExt.endsWith(".ts")
|
||||||
|
? relativePathWithoutExt
|
||||||
|
: `${relativePathWithoutExt}.ts`,
|
||||||
|
cwd: pathDirname(i18nTsFilePath)
|
||||||
|
});
|
||||||
|
|
||||||
return {};
|
const root = recastParseTs(filePath);
|
||||||
|
|
||||||
|
let declarationCode: string | undefined = "";
|
||||||
|
|
||||||
|
recast.visit(root, {
|
||||||
|
visitVariableDeclarator: function (path) {
|
||||||
|
const node = path.node;
|
||||||
|
|
||||||
|
// Check if the variable name is 'messages'
|
||||||
|
if (
|
||||||
|
node.id.type === "Identifier" &&
|
||||||
|
node.id.name === "messages"
|
||||||
|
) {
|
||||||
|
// Ensure there is an initializer
|
||||||
|
if (node.init) {
|
||||||
|
// Generate code from the initializer, preserving comments
|
||||||
|
declarationCode = recast
|
||||||
|
.print(node.init)
|
||||||
|
.code.replace(/}.*$/, "}");
|
||||||
|
}
|
||||||
|
return false; // Stop traversing this path
|
||||||
|
}
|
||||||
|
|
||||||
|
this.traverse(path); // Continue traversing other paths
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
assert(
|
||||||
|
declarationCode !== undefined,
|
||||||
|
`${filePath} does not contain a 'messages' variable declaration`
|
||||||
|
);
|
||||||
|
|
||||||
|
let messages: Record<string, string> = {};
|
||||||
|
|
||||||
|
try {
|
||||||
|
eval(`${symToStr({ messages })} = ${declarationCode};`);
|
||||||
|
} catch {
|
||||||
|
throw new Error(
|
||||||
|
`The declaration of 'message' in ${filePath} cannot be statically evaluated: ${declarationCode}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return messages;
|
||||||
|
})()
|
||||||
|
]
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
console.log(messages_defaultSet_by_languageTag_notInDefaultSet);
|
||||||
|
|
||||||
|
return messages_defaultSet_by_languageTag_notInDefaultSet;
|
||||||
})();
|
})();
|
||||||
|
|
||||||
const messages_defaultSet_by_languageTag = {
|
const messages_defaultSet_by_languageTag = {
|
||||||
@ -294,12 +348,8 @@ export function generateMessageProperties(params: {
|
|||||||
} catch {
|
} catch {
|
||||||
console.warn(
|
console.warn(
|
||||||
[
|
[
|
||||||
"WARNING: Make sure the messageBundle your provided as argument of createUseI18n can be statically evaluated.",
|
"WARNING: The argument of withCustomTranslations can't be statically evaluated!",
|
||||||
"This is important because we need to put your i18n messages in messages_*.properties files",
|
"This needs to be fixed refer to the documentation: https://docs.keycloakify.dev/i18n",
|
||||||
"or they won't be available server side.",
|
|
||||||
"\n",
|
|
||||||
"The following code could not be evaluated:",
|
|
||||||
"\n",
|
|
||||||
firstArgumentCode
|
firstArgumentCode
|
||||||
].join(" ")
|
].join(" ")
|
||||||
);
|
);
|
||||||
@ -376,3 +426,17 @@ export function generateMessageProperties(params: {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function recastParseTs(filePath: string): recast.types.ASTNode {
|
||||||
|
return recast.parse(fs.readFileSync(filePath).toString("utf8"), {
|
||||||
|
parser: {
|
||||||
|
parse: (code: string) =>
|
||||||
|
babelParser.parse(code, {
|
||||||
|
sourceType: "module",
|
||||||
|
plugins: ["typescript"]
|
||||||
|
}),
|
||||||
|
generator: babelGenerate,
|
||||||
|
types: babelTypes
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user