integration tests
This commit is contained in:
@@ -4,8 +4,9 @@
|
|||||||
* View Data Builders must:
|
* View Data Builders must:
|
||||||
* 1. Be classes named *ViewDataBuilder
|
* 1. Be classes named *ViewDataBuilder
|
||||||
* 2. Have a static build() method
|
* 2. Have a static build() method
|
||||||
* 3. Accept API DTO as parameter (named 'apiDto', NOT 'pageDto')
|
* 3. Use 'satisfies ViewDataBuilder<...>' for static enforcement
|
||||||
* 4. Return View Data
|
* 4. Accept API DTO as parameter (named 'apiDto')
|
||||||
|
* 5. Return View Data
|
||||||
*/
|
*/
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
@@ -20,7 +21,8 @@ module.exports = {
|
|||||||
schema: [],
|
schema: [],
|
||||||
messages: {
|
messages: {
|
||||||
notAClass: 'View Data Builders must be classes named *ViewDataBuilder',
|
notAClass: 'View Data Builders must be classes named *ViewDataBuilder',
|
||||||
missingBuildMethod: 'View Data Builders must have a static build() method',
|
missingStaticBuild: 'View Data Builders must have a static build() method',
|
||||||
|
missingSatisfies: 'View Data Builders must use "satisfies ViewDataBuilder<...>" for static type enforcement',
|
||||||
invalidBuildSignature: 'build() method must accept API DTO and return View Data',
|
invalidBuildSignature: 'build() method must accept API DTO and return View Data',
|
||||||
wrongParameterName: 'Parameter must be named "apiDto", not "pageDto" or other names',
|
wrongParameterName: 'Parameter must be named "apiDto", not "pageDto" or other names',
|
||||||
},
|
},
|
||||||
@@ -32,7 +34,8 @@ module.exports = {
|
|||||||
|
|
||||||
if (!isInViewDataBuilders) return {};
|
if (!isInViewDataBuilders) return {};
|
||||||
|
|
||||||
let hasBuildMethod = false;
|
let hasStaticBuild = false;
|
||||||
|
let hasSatisfies = false;
|
||||||
let hasCorrectSignature = false;
|
let hasCorrectSignature = false;
|
||||||
let hasCorrectParameterName = false;
|
let hasCorrectParameterName = false;
|
||||||
|
|
||||||
@@ -49,28 +52,28 @@ module.exports = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check for static build method
|
// Check for static build method
|
||||||
const buildMethod = node.body.body.find(member =>
|
const staticBuild = node.body.body.find(member =>
|
||||||
member.type === 'MethodDefinition' &&
|
member.type === 'MethodDefinition' &&
|
||||||
member.key.type === 'Identifier' &&
|
member.key.type === 'Identifier' &&
|
||||||
member.key.name === 'build' &&
|
member.key.name === 'build' &&
|
||||||
member.static === true
|
member.static === true
|
||||||
);
|
);
|
||||||
|
|
||||||
if (buildMethod) {
|
if (staticBuild) {
|
||||||
hasBuildMethod = true;
|
hasStaticBuild = true;
|
||||||
|
|
||||||
// Check signature - should have at least one parameter
|
// Check signature - should have at least one parameter
|
||||||
if (buildMethod.value &&
|
if (staticBuild.value &&
|
||||||
buildMethod.value.params &&
|
staticBuild.value.params &&
|
||||||
buildMethod.value.params.length > 0) {
|
staticBuild.value.params.length > 0) {
|
||||||
hasCorrectSignature = true;
|
hasCorrectSignature = true;
|
||||||
|
|
||||||
// Check parameter name
|
// Check parameter name
|
||||||
const firstParam = buildMethod.value.params[0];
|
const firstParam = staticBuild.value.params[0];
|
||||||
if (firstParam.type === 'Identifier' && firstParam.name === 'apiDto') {
|
if (firstParam.type === 'Identifier' && firstParam.name === 'apiDto') {
|
||||||
hasCorrectParameterName = true;
|
hasCorrectParameterName = true;
|
||||||
} else if (firstParam.type === 'Identifier' && firstParam.name === 'pageDto') {
|
} else if (firstParam.type === 'Identifier' && (firstParam.name === 'pageDto' || firstParam.name === 'dto')) {
|
||||||
// Report specific error for pageDto
|
// Report specific error for wrong names
|
||||||
context.report({
|
context.report({
|
||||||
node: firstParam,
|
node: firstParam,
|
||||||
messageId: 'wrongParameterName',
|
messageId: 'wrongParameterName',
|
||||||
@@ -80,23 +83,35 @@ module.exports = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// Check for satisfies expression
|
||||||
|
TSSatisfiesExpression(node) {
|
||||||
|
if (node.typeAnnotation &&
|
||||||
|
node.typeAnnotation.type === 'TSTypeReference' &&
|
||||||
|
node.typeAnnotation.typeName.name === 'ViewDataBuilder') {
|
||||||
|
hasSatisfies = true;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
'Program:exit'() {
|
'Program:exit'() {
|
||||||
if (!hasBuildMethod) {
|
if (!hasStaticBuild) {
|
||||||
context.report({
|
context.report({
|
||||||
node: context.getSourceCode().ast,
|
node: context.getSourceCode().ast,
|
||||||
messageId: 'missingBuildMethod',
|
messageId: 'missingStaticBuild',
|
||||||
});
|
});
|
||||||
} else if (!hasCorrectSignature) {
|
}
|
||||||
|
|
||||||
|
if (!hasSatisfies) {
|
||||||
|
context.report({
|
||||||
|
node: context.getSourceCode().ast,
|
||||||
|
messageId: 'missingSatisfies',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasStaticBuild && !hasCorrectSignature) {
|
||||||
context.report({
|
context.report({
|
||||||
node: context.getSourceCode().ast,
|
node: context.getSourceCode().ast,
|
||||||
messageId: 'invalidBuildSignature',
|
messageId: 'invalidBuildSignature',
|
||||||
});
|
});
|
||||||
} else if (!hasCorrectParameterName) {
|
|
||||||
// Only report if not already reported for pageDto
|
|
||||||
context.report({
|
|
||||||
node: context.getSourceCode().ast,
|
|
||||||
messageId: 'wrongParameterName',
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -3,8 +3,9 @@
|
|||||||
*
|
*
|
||||||
* View Data Builders in lib/builders/view-data/ must:
|
* View Data Builders in lib/builders/view-data/ must:
|
||||||
* 1. Be classes named *ViewDataBuilder
|
* 1. Be classes named *ViewDataBuilder
|
||||||
* 2. Implement the ViewDataBuilder<TInput, TOutput> interface
|
* 2. Have a static build() method
|
||||||
* 3. Have a static build() method
|
*
|
||||||
|
* Note: 'implements' is deprecated in favor of 'satisfies' checked in view-data-builder-contract.js
|
||||||
*/
|
*/
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
@@ -19,7 +20,6 @@ module.exports = {
|
|||||||
schema: [],
|
schema: [],
|
||||||
messages: {
|
messages: {
|
||||||
notAClass: 'View Data Builders must be classes named *ViewDataBuilder',
|
notAClass: 'View Data Builders must be classes named *ViewDataBuilder',
|
||||||
missingImplements: 'View Data Builders must implement ViewDataBuilder<TInput, TOutput> interface',
|
|
||||||
missingBuildMethod: 'View Data Builders must have a static build() method',
|
missingBuildMethod: 'View Data Builders must have a static build() method',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -30,7 +30,6 @@ module.exports = {
|
|||||||
|
|
||||||
if (!isInViewDataBuilders) return {};
|
if (!isInViewDataBuilders) return {};
|
||||||
|
|
||||||
let hasImplements = false;
|
|
||||||
let hasBuildMethod = false;
|
let hasBuildMethod = false;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@@ -45,24 +44,6 @@ module.exports = {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if class implements ViewDataBuilder interface
|
|
||||||
if (node.implements && node.implements.length > 0) {
|
|
||||||
for (const impl of node.implements) {
|
|
||||||
// Handle GenericTypeAnnotation for ViewDataBuilder<TInput, TOutput>
|
|
||||||
if (impl.expression.type === 'TSInstantiationExpression') {
|
|
||||||
const expr = impl.expression.expression;
|
|
||||||
if (expr.type === 'Identifier' && expr.name === 'ViewDataBuilder') {
|
|
||||||
hasImplements = true;
|
|
||||||
}
|
|
||||||
} else if (impl.expression.type === 'Identifier') {
|
|
||||||
// Handle simple ViewDataBuilder (without generics)
|
|
||||||
if (impl.expression.name === 'ViewDataBuilder') {
|
|
||||||
hasImplements = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check for static build method
|
// Check for static build method
|
||||||
const buildMethod = node.body.body.find(member =>
|
const buildMethod = node.body.body.find(member =>
|
||||||
member.type === 'MethodDefinition' &&
|
member.type === 'MethodDefinition' &&
|
||||||
@@ -77,13 +58,6 @@ module.exports = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
'Program:exit'() {
|
'Program:exit'() {
|
||||||
if (!hasImplements) {
|
|
||||||
context.report({
|
|
||||||
node: context.getSourceCode().ast,
|
|
||||||
messageId: 'missingImplements',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!hasBuildMethod) {
|
if (!hasBuildMethod) {
|
||||||
context.report({
|
context.report({
|
||||||
node: context.getSourceCode().ast,
|
node: context.getSourceCode().ast,
|
||||||
|
|||||||
@@ -4,8 +4,9 @@
|
|||||||
* View Model Builders must:
|
* View Model Builders must:
|
||||||
* 1. Be classes named *ViewModelBuilder
|
* 1. Be classes named *ViewModelBuilder
|
||||||
* 2. Have a static build() method
|
* 2. Have a static build() method
|
||||||
* 3. Accept View Data as parameter
|
* 3. Use 'satisfies ViewModelBuilder<...>' for static enforcement
|
||||||
* 4. Return View Model
|
* 4. Accept View Data as parameter
|
||||||
|
* 5. Return View Model
|
||||||
*/
|
*/
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
@@ -20,7 +21,8 @@ module.exports = {
|
|||||||
schema: [],
|
schema: [],
|
||||||
messages: {
|
messages: {
|
||||||
notAClass: 'View Model Builders must be classes named *ViewModelBuilder',
|
notAClass: 'View Model Builders must be classes named *ViewModelBuilder',
|
||||||
missingBuildMethod: 'View Model Builders must have a static build() method',
|
missingStaticBuild: 'View Model Builders must have a static build() method',
|
||||||
|
missingSatisfies: 'View Model Builders must use "satisfies ViewModelBuilder<...>" for static type enforcement',
|
||||||
invalidBuildSignature: 'build() method must accept View Data and return View Model',
|
invalidBuildSignature: 'build() method must accept View Data and return View Model',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -31,7 +33,8 @@ module.exports = {
|
|||||||
|
|
||||||
if (!isInViewModelBuilders) return {};
|
if (!isInViewModelBuilders) return {};
|
||||||
|
|
||||||
let hasBuildMethod = false;
|
let hasStaticBuild = false;
|
||||||
|
let hasSatisfies = false;
|
||||||
let hasCorrectSignature = false;
|
let hasCorrectSignature = false;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@@ -47,32 +50,50 @@ module.exports = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check for static build method
|
// Check for static build method
|
||||||
const buildMethod = node.body.body.find(member =>
|
const staticBuild = node.body.body.find(member =>
|
||||||
member.type === 'MethodDefinition' &&
|
member.type === 'MethodDefinition' &&
|
||||||
member.key.type === 'Identifier' &&
|
member.key.type === 'Identifier' &&
|
||||||
member.key.name === 'build' &&
|
member.key.name === 'build' &&
|
||||||
member.static === true
|
member.static === true
|
||||||
);
|
);
|
||||||
|
|
||||||
if (buildMethod) {
|
if (staticBuild) {
|
||||||
hasBuildMethod = true;
|
hasStaticBuild = true;
|
||||||
|
|
||||||
// Check signature - should have at least one parameter
|
// Check signature - should have at least one parameter
|
||||||
if (buildMethod.value &&
|
if (staticBuild.value &&
|
||||||
buildMethod.value.params &&
|
staticBuild.value.params &&
|
||||||
buildMethod.value.params.length > 0) {
|
staticBuild.value.params.length > 0) {
|
||||||
hasCorrectSignature = true;
|
hasCorrectSignature = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// Check for satisfies expression
|
||||||
|
TSSatisfiesExpression(node) {
|
||||||
|
if (node.typeAnnotation &&
|
||||||
|
node.typeAnnotation.type === 'TSTypeReference' &&
|
||||||
|
node.typeAnnotation.typeName.name === 'ViewModelBuilder') {
|
||||||
|
hasSatisfies = true;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
'Program:exit'() {
|
'Program:exit'() {
|
||||||
if (!hasBuildMethod) {
|
if (!hasStaticBuild) {
|
||||||
context.report({
|
context.report({
|
||||||
node: context.getSourceCode().ast,
|
node: context.getSourceCode().ast,
|
||||||
messageId: 'missingBuildMethod',
|
messageId: 'missingStaticBuild',
|
||||||
});
|
});
|
||||||
} else if (!hasCorrectSignature) {
|
}
|
||||||
|
|
||||||
|
if (!hasSatisfies) {
|
||||||
|
context.report({
|
||||||
|
node: context.getSourceCode().ast,
|
||||||
|
messageId: 'missingSatisfies',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasStaticBuild && !hasCorrectSignature) {
|
||||||
context.report({
|
context.report({
|
||||||
node: context.getSourceCode().ast,
|
node: context.getSourceCode().ast,
|
||||||
messageId: 'invalidBuildSignature',
|
messageId: 'invalidBuildSignature',
|
||||||
|
|||||||
Reference in New Issue
Block a user