blob: 6cdad9b9f32145d2efcb1e7bce3a02258a4b96ed [file]
// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:dart_skills_lint/dart_skills_lint.dart';
import 'package:path/path.dart' as path;
/// A rule that checks that paths inside backticks are relative to the skill file,
/// not relative to the repository root.
class CheckBackticksRelativePathsRule extends SkillRule {
CheckBackticksRelativePathsRule(this.valid2SegmentPaths, this.repoRootPath);
final Set<String> valid2SegmentPaths;
final String repoRootPath;
@override
String get name => 'check-backticks-relative-paths';
@override
AnalysisSeverity get severity => AnalysisSeverity.error;
@override
Future<List<ValidationError>> validate(SkillContext context) async {
final errors = <ValidationError>[];
final String content = context.rawContent;
// Calculate relative path to root
final String relativePathToRoot = path.relative(repoRootPath, from: context.directory.path);
final backtickRegex = RegExp(r'`([^`]+)`');
final Iterable<RegExpMatch> matches = backtickRegex.allMatches(content);
for (final match in matches) {
final String textInBackticks = match.group(1)!;
final String normalizedText = textInBackticks.replaceAll(r'\', '/');
for (final String validPath in valid2SegmentPaths) {
if (normalizedText.startsWith('$validPath/')) {
final fullPath = textInBackticks;
final String correctedPath = path
.join(relativePathToRoot, fullPath)
.replaceAll(r'\', '/');
errors.add(
ValidationError(
ruleId: name,
file: 'SKILL.md',
message:
'Found root-relative path "$fullPath" in backticks. Suggested fix: [${path.basename(normalizedText)}]($correctedPath)',
severity: severity,
),
);
}
}
}
return errors;
}
}