Skip to content

Commit 556109c

Browse files
authored
Feature package adapter (#452)
1 parent 2cca893 commit 556109c

File tree

28 files changed

+556
-1
lines changed

28 files changed

+556
-1
lines changed

Diff for: .gitignore

+2
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ yarn-debug.log*
66
yarn-error.log*
77
lerna-debug.log*
88

9+
.DS_Store
10+
911
# Diagnostic reports (https://nodejs.org/api/report.html)
1012
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
1113

Diff for: transpiler/__tests__/ast/core/builders/evaluationDirector.ts

+15
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,21 @@ export class EvaluationBuilderDirector {
8787
},
8888
};
8989
}
90+
buildPackageEvaluation(
91+
packageIdentifier: string,
92+
methodName: string,
93+
argumentList: TArgumentList,
94+
): TEvaluation {
95+
return {
96+
evaluation: {
97+
packageEvaluation: {
98+
identifier: packageIdentifier,
99+
methodName,
100+
...argumentList,
101+
},
102+
},
103+
};
104+
}
90105
/**
91106
*
92107
* @param standardVOIdentifier e.g 'Currency'

Diff for: transpiler/__tests__/ast/core/mocks/evaluation/evaluation.ts

+10
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,16 @@ export const validEvaluationTestCases: Array<TestCase> = [
115115
[new EvaluationFieldBuilderDirector().buildStringEvaluationField('email', '[email protected]')],
116116
),
117117
},
118+
{
119+
description: 'valid package adapter evaluation',
120+
fileId: 'testFile.bl',
121+
inputBLString: 'JestTestEvaluation { GherkinPackage.encode(value) }',
122+
evaluation: new EvaluationBuilderDirector().buildPackageEvaluation(
123+
'GherkinPackage',
124+
'encode',
125+
new ArgumentListBuilderDirector().buildArgumentList(['value']),
126+
),
127+
},
118128
];
119129

120130
export const validStandardVOEvaluationTestCases: Array<TestCase> = [

Diff for: transpiler/__tests__/target/typescript/core/builders/evaluation.ts

+21
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,9 @@ import { DomainServiceEvaluationBuilderDirector } from './domainServiceEvaluatio
2929
import { ReadModelEvaluationBuilderDirector } from './domainEvaluation/readModelEvaluation.js';
3030
import { DomainEventIdentifierNode } from '../../../../../src/ast/core/intermediate-ast/nodes/DomainEvent/DomainEventIdentifierNode.js';
3131
import { DomainEventEvaluationNodeBuilder } from '../../../../../src/ast/core/intermediate-ast/builders/expressions/evaluation/DomainEventEvaluationNodeBuilder.js';
32+
import { IdentifierNodeBuilder } from '../../../../../src/ast/core/intermediate-ast/builders/identifier/IdentifierBuilder.js';
33+
import { PackageMethodNameBuilder } from '../../../../../src/ast/core/intermediate-ast/builders/expressions/evaluation/PackageMethodNameBuilder.js';
34+
import { PackageEvaluationNodeBuilder } from '../../../../../src/ast/core/intermediate-ast/builders/expressions/evaluation/PackageEvaluationNodeBuilder.js';
3235

3336
export class EvaluationBuilderDirector {
3437
buildStructEvaluation(identifier: string, evalFields: EvaluationFieldNode[]): EvaluationNode {
@@ -252,4 +255,22 @@ export class EvaluationBuilderDirector {
252255
.build();
253256
return evaluationNode;
254257
}
258+
259+
buildPackageEvaluation(
260+
packageIdentifier: string,
261+
methodName: string,
262+
argumentList: ArgumentListNode,
263+
): EvaluationNode {
264+
const identifier = new IdentifierNodeBuilder().withName(packageIdentifier).build();
265+
const methodNameNode = new PackageMethodNameBuilder(null).withName(methodName).build();
266+
return new EvaluationBuilder()
267+
.withEvaluation(
268+
new PackageEvaluationNodeBuilder()
269+
.withPackageIdentifier(identifier)
270+
.withMethodName(methodNameNode)
271+
.withArgumentsList(argumentList)
272+
.build(),
273+
)
274+
.build();
275+
}
255276
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import { MethodDefinitionListNodeBuilder } from '../../../../../src/ast/core/intermediate-ast/builders/methodDefinition/methodDefinitionListNodeBuilder.js';
2+
import { PackagePortIdentifierNodeBuilder } from '../../../../../src/ast/core/intermediate-ast/builders/package/packagePort/PackagePortIdentifierNodeBuilder.js';
3+
import { PackagePortNodeBuilder } from '../../../../../src/ast/core/intermediate-ast/builders/package/packagePort/PackagePortNodeBuilder.js';
4+
import { IntermediateASTTree } from '../../../../../src/ast/core/intermediate-ast/IntermediateASTTree.js';
5+
import { MethodDefinitionNode } from '../../../../../src/ast/core/intermediate-ast/nodes/method-definitions/MethodDefinitionNode.js';
6+
import { PackagePortNode } from '../../../../../src/ast/core/intermediate-ast/nodes/package/packagePort/PackagePortNode.js';
7+
import { IntermediateASTRootNode } from '../../../../../src/ast/core/intermediate-ast/nodes/RootNode.js';
8+
9+
export class PackagePortNodeDirector {
10+
private builder: PackagePortNodeBuilder;
11+
12+
constructor() {
13+
const tree = new IntermediateASTTree(new IntermediateASTRootNode());
14+
this.builder = new PackagePortNodeBuilder(tree);
15+
}
16+
17+
buildPortWithMethodDefinitions(
18+
packagePortName: string,
19+
methodDefinitions: MethodDefinitionNode[],
20+
): PackagePortNode {
21+
return this.builder
22+
.withIdentifier(new PackagePortIdentifierNodeBuilder().withName(packagePortName).build())
23+
.withMethodDefinitions(
24+
new MethodDefinitionListNodeBuilder().withMethodDefinitions(methodDefinitions).build(),
25+
)
26+
.build();
27+
}
28+
}

Diff for: transpiler/__tests__/target/typescript/core/mocks/commandHandler/SendEmailCommandHandler.mock.ts

+2
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { Inject } from '@nestjs/common';
55
import { EmailDomainServiceToken } from '../../constants';
66
import { EmailDomainService } from '../../domain/services/email.domain-service';
77
import { EmailToSend } from '../../structs/email-to-send.struct';
8+
import { GherkinPackage } from '@packages/gherkin.package';
89
export type SendEmailCommandHandlerResponse = Either<void, void>;
910
export class SendEmailCommandHandler
1011
implements Application.ICommandHandler<SendEmailCommand, void>
@@ -33,6 +34,7 @@ export class SendEmailCommandHandler
3334
content: command.content,
3435
};
3536
await this.emailService.send(emailToSend);
37+
const res = await GherkinPackage.encode('aloha');
3638
return ok();
3739
}
3840
}

Diff for: transpiler/__tests__/target/typescript/core/mocks/commandHandler/index.ts

+15
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import { ArgumentNodeBuilder } from '../../../../../../src/ast/core/intermediate
1212
import { StatementBuilderDirector } from '../../builders/statement/statementDirector.js';
1313
import { EvaluationFieldBuilderDirector } from '../../builders/evaluationFIeld.js';
1414
import { BitloopsPrimaryTypeNodeDirector } from '../../builders/bitloopsPrimaryTypeDirector.js';
15+
import { ArgumentDirector } from '../../builders/argument.js';
1516

1617
export const VALID_COMMAND_HANDLER_TEST_CASES = [
1718
{
@@ -178,6 +179,20 @@ export const VALID_COMMAND_HANDLER_TEST_CASES = [
178179
),
179180
new ArgumentListDirector().buildArgumentListWithIdentifierExpression('emailToSend'),
180181
),
182+
new ConstDeclarationBuilderDirector().buildConstDeclaration(
183+
'res',
184+
new ExpressionBuilderDirector().buildEvaluationExpression(
185+
new EvaluationBuilderDirector().buildPackageEvaluation(
186+
'GherkinPackage',
187+
'encode',
188+
new ArgumentListDirector().buildArgumentListWithArgs([
189+
new ArgumentDirector().buildArgument(
190+
new ExpressionBuilderDirector().buildStringLiteralExpression('aloha'),
191+
),
192+
]),
193+
),
194+
),
195+
),
181196
new ReturnStatementBuilderDirector().buildReturnOKEmpty(),
182197
],
183198
}),

Diff for: transpiler/__tests__/target/typescript/core/mocks/expression/evaluation.ts

+12
Original file line numberDiff line numberDiff line change
@@ -405,3 +405,15 @@ export const VALID_READ_MODEL_EVALUATION_TEST_CASES = [
405405
output: 'UserEmailReadModel.fromPrimitives(userEmail)',
406406
},
407407
];
408+
409+
export const VALID_PACKAGE_EVALUATION_TEST_CASES = [
410+
{
411+
description: 'Valid domain service evaluation',
412+
evaluation: new EvaluationBuilderDirector().buildPackageEvaluation(
413+
'GherkinPackage',
414+
'encode',
415+
new ArgumentListDirector().buildArgumentListWithIdentifierExpression('value'),
416+
),
417+
output: 'await GherkinPackage.encode(value)',
418+
},
419+
];
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import { BitloopsPrimaryTypeNodeDirector } from '../../builders/bitloopsPrimaryTypeDirector.js';
2+
import { FileUtil } from '../../../../../../src/utils/file.js';
3+
import { PackagePortNode } from '../../../../../../src/ast/core/intermediate-ast/nodes/package/packagePort/PackagePortNode.js';
4+
import { PackagePortNodeDirector } from '../../builders/packagePortNodeDirector.js';
5+
import { MethodDefinitionNodeBuilderDirector } from '../../builders/methodDefinitionNodeBuilderDirector.js';
6+
import { ParameterBuilderDirector } from '../../builders/parameterDirector.js';
7+
8+
type PackagePortTestCase = {
9+
description: string;
10+
packagePort: PackagePortNode;
11+
output: string;
12+
};
13+
14+
export const VALID_PACKAGE_PORT_TEST_CASES: PackagePortTestCase[] = [
15+
{
16+
description: 'an aggregate repo port with no definitions',
17+
packagePort: new PackagePortNodeDirector().buildPortWithMethodDefinitions(
18+
'GherkinPackagePort',
19+
[
20+
new MethodDefinitionNodeBuilderDirector().buildMethodDefinitionNode({
21+
methodName: 'encode',
22+
parameters: [new ParameterBuilderDirector().buildPrimitiveParameter('value', 'string')],
23+
type: new BitloopsPrimaryTypeNodeDirector().buildPrimitivePrimaryType('bytes'),
24+
}),
25+
],
26+
),
27+
output: FileUtil.readFileString(
28+
'transpiler/__tests__/target/typescript/core/mocks/packagePort/packagePort.mock.ts',
29+
),
30+
},
31+
];
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export interface GherkinPackagePort {
2+
encode(value: string): Promise<Uint8Array>;
3+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
/**
2+
* Bitloops Language CLI
3+
* Copyright (C) 2022 Bitloops S.A.
4+
*
5+
* This program is free software: you can redistribute it and/or modify
6+
* it under the terms of the GNU General Public License as published by
7+
* the Free Software Foundation, either version 3 of the License, or
8+
* (at your option) any later version.
9+
*
10+
* This program is distributed in the hope that it will be useful,
11+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
* GNU General Public License for more details.
14+
*
15+
* You should have received a copy of the GNU General Public License
16+
* along with this program. If not, see <https://www.gnu.org/licenses/>.
17+
*
18+
* For further information you can contact legal(at)bitloops.com.
19+
*/
20+
import { IntermediateASTTree } from '../../../../src/ast/core/intermediate-ast/IntermediateASTTree.js';
21+
import { IntermediateASTRootNode } from '../../../../src/ast/core/intermediate-ast/nodes/RootNode.js';
22+
import { TargetGenerator } from '../../../../src/target/index.js';
23+
import { SupportedLanguages } from '../../../../src/target/supportedLanguages.js';
24+
import { TTargetCoreFinalContent } from '../../../../src/target/types.js';
25+
import { formatString } from '../../../../src/target/typescript-nest/core/codeFormatting.js';
26+
import { isTargetGeneratorError } from '../../../../src/target/typescript-nest/guards/index.js';
27+
import { VALID_PACKAGE_EVALUATION_TEST_CASES } from './mocks/expression/evaluation.js';
28+
29+
describe('Valid package evaluation test cases', () => {
30+
const boundedContext = 'Hello world';
31+
const module = 'demo';
32+
const formatterConfig = null;
33+
const language = SupportedLanguages.TypeScriptNest;
34+
35+
VALID_PACKAGE_EVALUATION_TEST_CASES.forEach((testCase) => {
36+
it(`${testCase.description}`, () => {
37+
let resultCore: TTargetCoreFinalContent[];
38+
39+
// given
40+
const tree = new IntermediateASTTree(new IntermediateASTRootNode());
41+
const evaluation = testCase.evaluation;
42+
tree.insertChild(evaluation);
43+
44+
const intermediateAST = {
45+
core: { [boundedContext]: { [module]: tree } },
46+
};
47+
48+
// when
49+
const targetGenerator = new TargetGenerator();
50+
const result = targetGenerator.generate(intermediateAST, {
51+
formatterConfig,
52+
targetLanguage: language,
53+
});
54+
55+
if (!isTargetGeneratorError(result)) {
56+
resultCore = result.core;
57+
}
58+
59+
//then
60+
const formattedOutput = formatString(testCase.output as string, formatterConfig);
61+
if (result instanceof Error) {
62+
throw result;
63+
}
64+
expect(resultCore[0].fileContent).toEqual(formattedOutput);
65+
});
66+
});
67+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
/**
2+
* Bitloops Language CLI
3+
* Copyright (C) 2022 Bitloops S.A.
4+
*
5+
* This program is free software: you can redistribute it and/or modify
6+
* it under the terms of the GNU General Public License as published by
7+
* the Free Software Foundation, either version 3 of the License, or
8+
* (at your option) any later version.
9+
*
10+
* This program is distributed in the hope that it will be useful,
11+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
* GNU General Public License for more details.
14+
*
15+
* You should have received a copy of the GNU General Public License
16+
* along with this program. If not, see <https://www.gnu.org/licenses/>.
17+
*
18+
* For further information you can contact legal(at)bitloops.com.
19+
*/
20+
21+
import { IntermediateASTTree } from '../../../../src/ast/core/intermediate-ast/IntermediateASTTree.js';
22+
import { IntermediateASTRootNode } from '../../../../src/ast/core/intermediate-ast/nodes/RootNode.js';
23+
import { TargetGenerator } from '../../../../src/target/index.js';
24+
import { SupportedLanguages } from '../../../../src/target/supportedLanguages.js';
25+
import { TTargetCoreFinalContent } from '../../../../src/target/types.js';
26+
import { formatString } from '../../../../src/target/typescript-nest/core/codeFormatting.js';
27+
import { isTargetGeneratorError } from '../../../../src/target/typescript-nest/guards/index.js';
28+
import { VALID_PACKAGE_PORT_TEST_CASES } from './mocks/packagePort/index.js';
29+
30+
describe('Valid package port declaration test cases', () => {
31+
const boundedContext = 'Hello world';
32+
const module = 'demo';
33+
const formatterConfig = null;
34+
const language = SupportedLanguages.TypeScriptNest;
35+
VALID_PACKAGE_PORT_TEST_CASES.forEach((testCase) => {
36+
let resultCore: TTargetCoreFinalContent[];
37+
38+
it(`${testCase.description}`, () => {
39+
// given
40+
const tree = new IntermediateASTTree(new IntermediateASTRootNode());
41+
42+
tree.insertChild(testCase.packagePort);
43+
44+
const intermediateAST = {
45+
core: { [boundedContext]: { [module]: tree } },
46+
};
47+
48+
// when
49+
const targetGenerator = new TargetGenerator();
50+
const result = targetGenerator.generate(intermediateAST, {
51+
formatterConfig,
52+
targetLanguage: language,
53+
// setupData: null,
54+
});
55+
56+
if (!isTargetGeneratorError(result)) {
57+
resultCore = result.core;
58+
}
59+
60+
//then
61+
const formattedOutput = formatString(testCase.output as string, formatterConfig);
62+
if (result instanceof Error) {
63+
throw result;
64+
}
65+
expect(resultCore[0].fileContent).toEqual(formattedOutput);
66+
});
67+
});
68+
});

Diff for: transpiler/src/ast/core/BitloopsVisitor/BitloopsVisitor.ts

+12
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,7 @@ import {
144144
regexLiteralEvaluation,
145145
readModelEvaluationVisitor,
146146
domainEventEvaluationVisitor,
147+
packageEvaluationVisitor,
147148
} from './helpers/index.js';
148149
import { optionalVisitor } from './helpers/optional.js';
149150
import { produceMetadata } from './metadata.js';
@@ -655,6 +656,17 @@ export default class BitloopsVisitor extends BitloopsParserVisitor {
655656
return readModelEvaluationVisitor(this, ctx);
656657
}
657658

659+
visitPackageEvaluation(ctx: BitloopsParser.PackageEvaluationContext): any {
660+
return packageEvaluationVisitor(this, ctx);
661+
}
662+
663+
visitPackageIdentifier(ctx: BitloopsParser.PackageIdentifierContext): IdentifierNode {
664+
const packageName = ctx.PackageIdentifier().getText();
665+
const metadata = produceMetadata(ctx, this);
666+
const packageIdentifierNode = new IdentifierNodeBuilder(metadata).withName(packageName).build();
667+
return packageIdentifierNode;
668+
}
669+
658670
visitIntegrationEventEvaluation(ctx: BitloopsParser.IntegrationEventEvaluationContext): any {
659671
return integrationEventEvaluationVisitor(this, ctx);
660672
}

Diff for: transpiler/src/ast/core/BitloopsVisitor/helpers/index.ts

+1
Original file line numberDiff line numberDiff line change
@@ -143,3 +143,4 @@ export {
143143
} from './expression/evaluation/index.js';
144144
export { integrationEventEvaluationVisitor } from './integrationEventEvaluation.js';
145145
export { readModelEvaluationVisitor } from './readModelEvaluation.js';
146+
export { packageEvaluationVisitor } from './packageEvaluation.js';

0 commit comments

Comments
 (0)