packages/awslint/lib/rules/durations.ts (46 lines of code) (raw):

import { Property } from 'jsii-reflect'; import { Linter } from '../linter'; const DURATION_FQN = 'aws-cdk-lib.Duration'; const DURATION_SUFFIX = /(Days|Milli(?:(?:S|s)econd)?s?|Sec(?:ond)?s?)$/; const EXCLUDE_ANNOTATION_DURATION_PROP_TYPE = '[disable-awslint:duration-prop-type]'; export const durationsLinter = new Linter(assm => { const result = new Array<Property>(); const generatedClassesPrefix = `${assm.name}.Cfn`; for (const type of assm.types) { // L1 classes are exempted from this rule, doing basic name matching here... if (type.fqn.startsWith(generatedClassesPrefix)) { continue; } if (!type.isClassType() && !type.isDataType() && !type.isInterfaceType()) { continue; } for (const property of type.allProperties) { if (isDurationProperty(property) && !property.docs.toString().includes(EXCLUDE_ANNOTATION_DURATION_PROP_TYPE)) { result.push(property); } } } return result; function isDurationProperty(prop: Property): boolean { const lowerCaseName = prop.name.toLowerCase(); // No lookbehind in JS regexes, so excluding "*PerSecond" by hand here... return (DURATION_SUFFIX.test(prop.name) && !/PerSecond$/.test(prop.name)) || lowerCaseName.endsWith('duration') || lowerCaseName.endsWith('period') || lowerCaseName.endsWith('timeout') || lowerCaseName.endsWith('ttl') || prop.type.fqn === DURATION_FQN; } }); durationsLinter.add({ code: 'duration-prop-type', message: `property must be typed ${DURATION_FQN}`, eval: evaluation => { evaluation.assert(evaluation.ctx.type.fqn === DURATION_FQN, `${evaluation.ctx.parentType.fqn}.${evaluation.ctx.name}`); }, }); durationsLinter.add({ code: 'duration-prop-name', message: 'property must not use time-unit suffix', eval: evaluation => { evaluation.assert(!DURATION_SUFFIX.test(evaluation.ctx.name), `${evaluation.ctx.parentType.fqn}.${evaluation.ctx.name}`, `(suggested name: "${evaluation.ctx.name.replace(DURATION_SUFFIX, '')}")`); }, });