Skip to content

Commit

Permalink
feat: 🎸 support pipe params extraction
Browse files Browse the repository at this point in the history
  • Loading branch information
shaharkazaz committed Aug 3, 2024
1 parent 0ccbe95 commit d867d5c
Show file tree
Hide file tree
Showing 4 changed files with 88 additions and 26 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import {
defaultValue,
generateKeys,
mockResolveProjectBasePath,
resolveValueWithParams,
setParamsInput,
} from '../../../spec-utils';
import { Config } from '../../../../src/types';

Expand Down Expand Up @@ -50,5 +52,14 @@ export function testPipeExtraction(fileFormat: Config['fileFormat']) {
buildTranslationFiles(config);
assertTranslation({ type, expected, fileFormat });
});

it('should extract params', () => {
const expected = {
...generateKeys({ end: 2, withParams: true }),
'admin.1': resolveValueWithParams(['someKey']),
};
buildTranslationFiles(setParamsInput(config));
assertTranslation({ type, expected, fileFormat });
});
});
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<div>
{{ '1' | transloco:{'1': ''} }}
<p [title]="'2' | transloco:{'2': 123}"></p>
</div>

<a [title]="'admin.1' | lowercase
| transloco:{someKey: 'asd'}"
[routerLink]="'admin' | lowercase">
</a>
90 changes: 64 additions & 26 deletions src/keys-builder/template/pipe.extractor.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@
import { AST, ASTWithSource, TmplAstNode } from '@angular/compiler';
import {
AST,
ASTWithSource,
BindingPipe,
LiteralMap,
LiteralPrimitive,
TmplAstNode,
} from '@angular/compiler';

import { ExtractorConfig } from '../../types';
import { addKey } from '../add-key';
Expand All @@ -21,6 +28,7 @@ import {
isBlockNode,
resolveBlockChildNodes,
} from './utils';
import { notNil } from '../../utils/validators.utils';

export function pipeExtractor(config: TemplateExtractorConfig) {
const ast = parseTemplate(config);
Expand All @@ -44,7 +52,12 @@ function traverse(nodes: TmplAstNode[], config: ExtractorConfig) {
}

for (const ast of astTrees) {
addKeysFromAst(getPipeValuesFromAst(ast), config);
const pipes = getTranslocoPipeAst(ast) as BindingPipe[];
const keysWithParams = pipes
.map((p) => resolveKeyAndParam(p))
.flat()
.filter(notNil);
addKeysFromAst(keysWithParams, config);
}
}
}
Expand All @@ -60,21 +73,10 @@ function isTranslocoPipe(ast: any): boolean {
return isTransloco || (isPipeChaining && isTranslocoPipe(ast.exp));
}

function getPipeValuesFromAst(ast: AST): AST[] {
function getTranslocoPipeAst(ast: AST): AST[] {
let exp = [];
if (isBindingPipe(ast) && isTranslocoPipe(ast)) {
if (isLiteralExpression(ast.exp)) {
return [ast.exp];
} else if (isConditionalExpression(ast.exp)) {
return [ast.exp.trueExp, ast.exp.falseExp];
} else {
let pipe = ast;
while (isBindingPipe(pipe.exp)) {
pipe = pipe.exp;
}

return [pipe.exp];
}
return [ast];
} else if (isBindingPipe(ast)) {
exp = [...ast.args, ast.exp];
} else if (isLiteralMap(ast)) {
Expand All @@ -91,20 +93,56 @@ function getPipeValuesFromAst(ast: AST): AST[] {
exp = [ast.receiver];
}

return exp.map(getPipeValuesFromAst).flat();
return exp.map(getTranslocoPipeAst).flat();
}

function addKeysFromAst(expressions: AST[], config: ExtractorConfig): void {
for (const exp of expressions) {
if (isConditionalExpression(exp)) {
addKeysFromAst([exp.trueExp, exp.falseExp], config);
} else if (isLiteralExpression(exp)) {
const [key, scopeAlias] = resolveAliasAndKey(exp.value, config.scopes);
addKey({
...config,
keyWithoutScope: key,
scopeAlias,
interface KeyWithParam {
keyNode: LiteralPrimitive;
paramsNode: AST;
}

function resolveKeyAndParam(
pipe: BindingPipe,
paramsNode?: AST,
): KeyWithParam | KeyWithParam[] | null {
const resolvedParams: AST = paramsNode ?? pipe.args[0];
if (isConditionalExpression(pipe.exp)) {
return [pipe.exp.trueExp, pipe.exp.falseExp]
.filter(isLiteralExpression)
.map((keyNode) => {
return {
keyNode,
paramsNode: resolvedParams,
};
});
} else if (isLiteralExpression(pipe.exp)) {
return {
keyNode: pipe.exp,
paramsNode: resolvedParams,
};
} else if (isBindingPipe(pipe.exp)) {
let nestedPipe = pipe;
while (isBindingPipe(nestedPipe.exp)) {
nestedPipe = nestedPipe.exp;
}

return resolveKeyAndParam(nestedPipe, resolvedParams);
}

return null;
}

function addKeysFromAst(keys: KeyWithParam[], config: ExtractorConfig): void {
for (const { keyNode, paramsNode } of keys) {
const [key, scopeAlias] = resolveAliasAndKey(keyNode.value, config.scopes);
const params = isLiteralMap(paramsNode)
? paramsNode.keys.map((k) => k.key)
: [];
addKey({
...config,
keyWithoutScope: key,
scopeAlias,
params,
});
}
}
4 changes: 4 additions & 0 deletions src/utils/validators.utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ export function isNil(value: unknown): value is undefined | null {
return isUndefined(value) || value === null;
}

export function notNil<T>(value: T | undefined | null): value is T {
return !isNil(value);
}

export function isDirectory(path: string): boolean {
return existsSync(path) && lstatSync(path).isDirectory();
}
Expand Down

0 comments on commit d867d5c

Please sign in to comment.