优化
This commit is contained in:
@@ -13,6 +13,7 @@ const internalPrefix = 'com.baiyue.firstleg.';
|
||||
|
||||
const sliceRules = [
|
||||
['customer-statistics', /(?:^|\.)(?:customerstatistics)(?:\.|$)/],
|
||||
['pricebook-query', /(?:^|\.)(?:pricebookquery)(?:\.|$)/],
|
||||
['finance-integration', /(?:InternalFinance|FinanceFeeSource|FinanceCostSnapshot|FeePaymentVoucher|FeePaymentSnapshot|ContainerFeeSourceSnapshot)/],
|
||||
['shipping-nodes', /(?:CarrierScheduleQuery|CarrierScheduleNode|CarrierScheduleAdapter|CarrierScheduleAttempt|CarrierScheduleException)/],
|
||||
['booking-customs-trucking', /(?:^|\.)(?:oceanbooking|customs)(?:\.|$)|(?:TruckAppointment|WarehouseSupplier|PortSchedule|DispatchGate)/],
|
||||
@@ -273,8 +274,9 @@ function checkContract(report, contractPath) {
|
||||
if (!actualClass) violations.push(`required class missing: ${fqcn}`);
|
||||
else if (actualClass.file !== expectedFile) violations.push(`class location changed: ${fqcn} (${actualClass.file})`);
|
||||
}
|
||||
const applicationRule = contract.applicationDependencyRule;
|
||||
if (applicationRule) {
|
||||
const applicationRules = contract.applicationDependencyRules
|
||||
?? (contract.applicationDependencyRule ? [contract.applicationDependencyRule] : []);
|
||||
for (const applicationRule of applicationRules) {
|
||||
const applicationClasses = report.classes.filter(entry => entry.packageName.startsWith(applicationRule.packagePrefix));
|
||||
for (const entry of applicationClasses) {
|
||||
for (const imported of entry.imports) {
|
||||
@@ -291,6 +293,15 @@ function checkContract(report, contractPath) {
|
||||
}
|
||||
}
|
||||
}
|
||||
for (const exposureRule of contract.sliceExposureRules ?? []) {
|
||||
for (const edge of report.classDependencies) {
|
||||
if (!edge.source.startsWith(exposureRule.slicePrefix)
|
||||
&& edge.target.startsWith(exposureRule.slicePrefix)
|
||||
&& !(exposureRule.allowedTargetPrefixes ?? []).some(prefix => edge.target.startsWith(prefix))) {
|
||||
violations.push(`forbidden slice implementation dependency: ${edge.source} -> ${edge.target}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (const [slice, rule] of Object.entries(contract.sliceSpecificRules ?? {})) {
|
||||
const outgoing = report.sliceEdges.filter(edge => edge.source === slice).map(edge => edge.target).sort();
|
||||
const incoming = report.sliceEdges.filter(edge => edge.target === slice).map(edge => edge.source).sort();
|
||||
|
||||
@@ -52,3 +52,43 @@ test('customer statistics application layer only depends inward', () => {
|
||||
&& edge.target.startsWith('com.baiyue.firstleg.') && !edge.target.startsWith(prefix));
|
||||
assert.deepEqual(outwardDependencies, []);
|
||||
});
|
||||
|
||||
test('price book query is a leaf slice and removes the package cycle', () => {
|
||||
const report = analyze();
|
||||
const classes = report.classes.filter(entry => entry.slice === 'pricebook-query');
|
||||
assert.deepEqual(classes.map(entry => entry.fqcn).sort(), [
|
||||
'com.baiyue.firstleg.pricebookquery.adapter.out.persistence.PriceBookQueryMapper',
|
||||
'com.baiyue.firstleg.pricebookquery.application.PriceBookQueryService',
|
||||
'com.baiyue.firstleg.pricebookquery.application.model.PriceBookQueryRows',
|
||||
'com.baiyue.firstleg.pricebookquery.application.port.in.PriceBookQueryUseCase',
|
||||
'com.baiyue.firstleg.pricebookquery.application.port.out.PriceBookQueryReader',
|
||||
]);
|
||||
assert.deepEqual(report.sliceEdges.filter(edge => edge.source === 'pricebook-query'), []);
|
||||
assert.deepEqual(report.sliceEdges.filter(edge => edge.target === 'pricebook-query')
|
||||
.map(edge => edge.source).sort(), ['booking-customs-trucking', 'measurement-pricing', 'split-loading']);
|
||||
assert.equal(report.sliceSccs.some(component => component.includes('pricebook-query')), false);
|
||||
assert.deepEqual(report.packageSccs, []);
|
||||
});
|
||||
|
||||
test('price book query application and consumers respect ports', () => {
|
||||
const report = analyze();
|
||||
const prefix = 'com.baiyue.firstleg.pricebookquery.application';
|
||||
const applicationClasses = report.classes.filter(entry => entry.packageName.startsWith(prefix));
|
||||
assert.equal(applicationClasses.length, 4);
|
||||
for (const entry of applicationClasses) {
|
||||
assert.equal(entry.imports.some(imported => imported.startsWith('org.springframework.web')), false);
|
||||
assert.equal(entry.imports.some(imported => imported.startsWith('org.apache.ibatis')), false);
|
||||
assert.equal(entry.imports.some(imported => imported.startsWith('com.baomidou.mybatisplus')), false);
|
||||
}
|
||||
const outwardDependencies = report.classDependencies.filter(edge => edge.source.startsWith(prefix)
|
||||
&& edge.target.startsWith('com.baiyue.firstleg.') && !edge.target.startsWith(prefix));
|
||||
assert.deepEqual(outwardDependencies, []);
|
||||
const allowedTargets = [
|
||||
'com.baiyue.firstleg.pricebookquery.application.model.',
|
||||
'com.baiyue.firstleg.pricebookquery.application.port.in.',
|
||||
];
|
||||
const implementationLeaks = report.classDependencies.filter(edge => !edge.source.startsWith('com.baiyue.firstleg.pricebookquery.')
|
||||
&& edge.target.startsWith('com.baiyue.firstleg.pricebookquery.')
|
||||
&& !allowedTargets.some(prefixValue => edge.target.startsWith(prefixValue)));
|
||||
assert.deepEqual(implementationLeaks, []);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user