UNPKG

@cdklabs/aws-data-solutions-framework

Version:
118 lines (101 loc) 5.01 kB
// 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>;