@cdklabs/aws-data-solutions-framework
Version:
L3 CDK Constructs used to build data solutions with AWS
118 lines (101 loc) • 5.01 kB
text/typescript
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
import { RuleTester, type Rule } from 'eslint';
import * as ts from 'typescript';
import request from 'sync-request-curl';
import * as ESTree from 'estree';
export default {
// Put the following comment above a code line you want to exclude from this check, e.g. after review:
// eslint-disable-next-line local-rules/no-tokens-in-construct-id
'no-tokens-in-construct-id': {
meta: {
docs: {
description: 'Checks whether a CDK token might appear in a construct ID on instantiation',
recommended: true
},
schema: [],
},
create: function (context) {
const sourceCode = context.sourceCode ?? context.getSourceCode();
return {
NewExpression: function (node) {
if (node.callee.type != 'Identifier') {
return;
}
const typeChecker = sourceCode.parserServices.program.getTypeChecker();
const typescriptNode = <ts.Node>sourceCode.parserServices.esTreeNodeToTSNodeMap.get(node);
const instantiatedType = <ts.Type>typeChecker.getTypeAtLocation(typescriptNode);
const baseTypes = instantiatedType.getBaseTypes();
if (instantiatedType.symbol == null) {
// Non-nullable 'symbol' property contains null - no analysis possible
return;
}
if (instantiatedType.symbol.name == 'Construct' || baseTypes && baseTypes.some(t => t.symbol.name == 'Construct')) {
if (node.arguments.length <= 1) {
// Non-standard schema, expected at least 2 parameters
return;
}
// We expect the second argument to be the ID
const secondArgument = node.arguments[1];
if (secondArgument.type == 'Literal') {
if (secondArgument.value?.toString().startsWith('${TOKEN')) {
context.report({
node,
message: 'The ID argument of a construct contains a token, this is not allowed.'
});
}
// No further check needed for literals
return;
}
context.report({
node,
message: 'An expression is used for the construct ID. it might contain tokens, please review. ' +
'Suppress this finding by putting this comment above the code line: // eslint-disable-next-line local-rules/no-tokens-in-construct-id'
});
}
},
};
},
},
'url-checker': {
meta: {
docs: {
description: 'Checks the URLs in the comment-docs for accessibility'
},
schema: [],
},
create: function (context: Rule.RuleContext) : Rule.RuleListener {
function checkProgramComment(program: ESTree.Program): void {
if (!program.comments) {
return;
}
for (const c of program.comments.filter(c => c.type == 'Block')) {
const matches = c.value.match(/\bhttps?:\/\/[\-A-Za-z0-9+&@#\/%?=~_|!:,.;]*[\-A-Za-z0-9+&@#\/%=~_|]/);
if (!matches || matches.length == 0) {
continue;
}
for (const url of matches) {
try {
const res = request('GET', url, { headers: { 'user-agent': 'libcurl/1.0.6'} });
if (res.statusCode != 200) {
context.report({
loc: c.loc!,
message: `Fetching the URL '${url}' resulted in HTTP ${res.statusCode}`,
});
}
}
catch (e) {
context.report({
loc: c.loc!,
message: `Failed to check the URL '${url}': ${e}`,
});
}
}
}
}
return {
Program: checkProgramComment,
};
},
},
} satisfies Record<string, Rule.RuleModule>;