@jsverse/transloco-keys-manager
Version:
Extract translatable keys from projects that uses Transloco
70 lines • 3.25 kB
JavaScript
import { ScriptKind, tsquery } from '@phenomnomnominal/tsquery';
import ts from 'typescript';
import { addScope, hasScope } from '../keys-builder/utils/scope.utils.js';
import { readFile } from './file.utils.js';
import { toCamelCase } from './string.utils.js';
import { normalizedGlob } from './normalize-glob-path.js';
const tokenProviderQuery = `ObjectLiteralExpression:has(PropertyAssignment > Identifier[name=TRANSLOCO_SCOPE]) > PropertyAssignment > Identifier[name=/useValue|useFactory/]`;
const functionProviderQuery = `CallExpression > Identifier[name=provideTranslocoScope]`;
function stringQueryDef(rootNode) {
return (tsquery(rootNode, `StringLiteral`)
// Since we are querying for StringLiteral we might pickup nested nodes from
// the scope def and cause duplications, we only want direct children from the root node
.filter((node) => node.parent === rootNode)
.map((node) => ({ scope: node.text })));
}
function objectQueryDef(rootNode) {
return tsquery(rootNode, 'ObjectLiteralExpression:has(Identifier[name=scope])').map((node) => {
const result = {};
for (const prop of node
.properties) {
if (prop.initializer) {
const key = prop.name.getText();
if (key === 'scope' || key === 'alias') {
result[key] = prop.initializer.getText().replace(/['"]/g, '');
}
}
}
return result;
});
}
// Order is important, we check if it's an object first, then string
const scopeValueQueries = [objectQueryDef, stringQueryDef];
const translocoProvider = /(TRANSLOCO_SCOPE|provideTranslocoScope)/;
export function updateScopesMap({ input, files, }) {
const tsFiles = files || input.map((path) => normalizedGlob(`${path}/**/*.ts`)).flat();
// Return only the new scopes (for the plugin)
const aliasToScope = {};
for (const file of tsFiles) {
const content = readFile(file);
if (!translocoProvider.test(content))
continue;
let result = [];
const ast = tsquery.ast(content, undefined, ScriptKind.TS);
const tokenAndProviderNodes = tsquery(ast, `${tokenProviderQuery}, ${functionProviderQuery}`);
for (let node of tokenAndProviderNodes) {
// :has(> child) is not supported ... So we need to use a workaround, select child and make second query for parent
node = node.parent;
if (ts.isCallExpression(node)) {
const [providersArray] = tsquery(node, 'ArrayLiteralExpression');
if (providersArray) {
result.push(...resolveScopeProvider(providersArray));
continue;
}
}
result.push(...resolveScopeProvider(node));
}
for (let { scope, alias } of result) {
if (scope && !hasScope(scope)) {
alias ??= toCamelCase(scope);
addScope(scope, alias);
aliasToScope[alias] = scope;
}
}
}
return aliasToScope;
}
function resolveScopeProvider(node) {
return scopeValueQueries.map((resolver) => resolver(node)).flat();
}
//# sourceMappingURL=update-scopes-map.js.map