docs-coderef 0.2.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +30 -0
- package/README.md +27 -0
- package/dist/chunk-U3LM2QL7.mjs +268 -0
- package/dist/cli/fix.js +325 -152
- package/dist/cli/fix.mjs +108 -106
- package/dist/cli/validate.js +216 -33
- package/dist/cli/validate.mjs +20 -17
- package/package.json +8 -1
- package/dist/chunk-NTTV47AI.mjs +0 -73
package/dist/cli/validate.js
CHANGED
|
@@ -824,38 +824,219 @@ function loadDocsignorePatterns(docsignoreFile) {
|
|
|
824
824
|
return content.split("\n").map((line) => line.trim()).filter((line) => line && !line.startsWith("#"));
|
|
825
825
|
}
|
|
826
826
|
|
|
827
|
-
// src/utils/
|
|
828
|
-
var
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
827
|
+
// src/utils/message-formatter.ts
|
|
828
|
+
var import_chalk = __toESM(require("chalk"));
|
|
829
|
+
var COLOR_SCHEMES = {
|
|
830
|
+
error: import_chalk.default.redBright,
|
|
831
|
+
warning: import_chalk.default.yellow,
|
|
832
|
+
info: import_chalk.default.cyan,
|
|
833
|
+
success: import_chalk.default.green,
|
|
834
|
+
debug: import_chalk.default.gray,
|
|
835
|
+
neutral: import_chalk.default.white,
|
|
836
|
+
// Accent colors
|
|
837
|
+
highlight: import_chalk.default.cyan.bold,
|
|
838
|
+
dim: import_chalk.default.dim,
|
|
839
|
+
code: import_chalk.default.yellow
|
|
840
|
+
};
|
|
841
|
+
var EMOJIS = {
|
|
842
|
+
error: "\u274C",
|
|
843
|
+
warning: "\u26A0\uFE0F",
|
|
844
|
+
success: "\u2705",
|
|
845
|
+
info: "\u2139\uFE0F",
|
|
846
|
+
search: "\u{1F50D}",
|
|
847
|
+
fix: "\u{1F527}",
|
|
848
|
+
file: "\u{1F4C4}",
|
|
849
|
+
stats: "\u{1F4CA}",
|
|
850
|
+
backup: "\u{1F4BE}",
|
|
851
|
+
skip: "\u23ED\uFE0F"
|
|
852
|
+
};
|
|
853
|
+
var MessageFormatter = class {
|
|
854
|
+
/**
|
|
855
|
+
* Set verbose mode
|
|
856
|
+
* @param enabled Whether verbose mode is enabled
|
|
857
|
+
*/
|
|
858
|
+
static setVerbose(enabled) {
|
|
859
|
+
this.verboseMode = enabled;
|
|
860
|
+
}
|
|
861
|
+
/**
|
|
862
|
+
* Format error message
|
|
863
|
+
* @param text Error message text
|
|
864
|
+
* @returns Formatted error message with emoji and color
|
|
865
|
+
*/
|
|
866
|
+
static error(text) {
|
|
867
|
+
return `${COLOR_SCHEMES.error(`${EMOJIS.error} ${text}`)}`;
|
|
868
|
+
}
|
|
869
|
+
/**
|
|
870
|
+
* Format warning message
|
|
871
|
+
* @param text Warning message text
|
|
872
|
+
* @returns Formatted warning message with emoji and color
|
|
873
|
+
*/
|
|
874
|
+
static warning(text) {
|
|
875
|
+
return `${COLOR_SCHEMES.warning(`${EMOJIS.warning} ${text}`)}`;
|
|
876
|
+
}
|
|
877
|
+
/**
|
|
878
|
+
* Format info message
|
|
879
|
+
* @param text Info message text
|
|
880
|
+
* @returns Formatted info message with emoji and color
|
|
881
|
+
*/
|
|
882
|
+
static info(text) {
|
|
883
|
+
return `${COLOR_SCHEMES.info(`${EMOJIS.info} ${text}`)}`;
|
|
884
|
+
}
|
|
885
|
+
/**
|
|
886
|
+
* Format success message
|
|
887
|
+
* @param text Success message text
|
|
888
|
+
* @returns Formatted success message with emoji and color
|
|
889
|
+
*/
|
|
890
|
+
static success(text) {
|
|
891
|
+
return `${COLOR_SCHEMES.success(`${EMOJIS.success} ${text}`)}`;
|
|
892
|
+
}
|
|
893
|
+
/**
|
|
894
|
+
* Format debug message (only shown in verbose mode)
|
|
895
|
+
* @param text Debug message text
|
|
896
|
+
* @returns Formatted debug message if verbose mode is enabled, empty string otherwise
|
|
897
|
+
*/
|
|
898
|
+
static debug(text) {
|
|
899
|
+
if (!this.verboseMode) {
|
|
900
|
+
return "";
|
|
901
|
+
}
|
|
902
|
+
return COLOR_SCHEMES.debug(text);
|
|
903
|
+
}
|
|
904
|
+
/**
|
|
905
|
+
* Format neutral message (no emoji, white color)
|
|
906
|
+
* @param text Neutral message text
|
|
907
|
+
* @returns Formatted neutral message
|
|
908
|
+
*/
|
|
909
|
+
static neutral(text) {
|
|
910
|
+
return COLOR_SCHEMES.neutral(text);
|
|
911
|
+
}
|
|
912
|
+
/**
|
|
913
|
+
* Format error detail with type, message, and optional location
|
|
914
|
+
* @param type Error type (e.g., 'CODE_CONTENT_MISMATCH')
|
|
915
|
+
* @param message Error message
|
|
916
|
+
* @param location Optional file location
|
|
917
|
+
* @returns Formatted error detail
|
|
918
|
+
*/
|
|
919
|
+
static errorDetail(type, message, location) {
|
|
920
|
+
const lines = [];
|
|
921
|
+
lines.push(this.error(`${type}: ${message}`));
|
|
922
|
+
if (location) {
|
|
923
|
+
lines.push(` ${COLOR_SCHEMES.dim(`Reference: ${location}`)}`);
|
|
924
|
+
}
|
|
925
|
+
return lines.join("\n");
|
|
926
|
+
}
|
|
927
|
+
/**
|
|
928
|
+
* Format summary section
|
|
929
|
+
* @param successful Number of successful operations
|
|
930
|
+
* @param failed Number of failed operations
|
|
931
|
+
* @param backupPaths Array of backup file paths
|
|
932
|
+
* @returns Formatted summary section
|
|
933
|
+
*/
|
|
934
|
+
static summary(successful, failed, backupPaths) {
|
|
935
|
+
const lines = [];
|
|
936
|
+
const separator = COLOR_SCHEMES.dim("\u2501".repeat(60));
|
|
937
|
+
lines.push("");
|
|
938
|
+
lines.push(separator);
|
|
939
|
+
lines.push(`${EMOJIS.stats} Fix Results Summary`);
|
|
940
|
+
lines.push("");
|
|
941
|
+
lines.push(COLOR_SCHEMES.success(`${EMOJIS.success} Successful: ${successful}`));
|
|
942
|
+
lines.push(COLOR_SCHEMES.error(`${EMOJIS.error} Failed: ${failed}`));
|
|
943
|
+
if (backupPaths.length > 0) {
|
|
944
|
+
lines.push("");
|
|
945
|
+
lines.push(`${EMOJIS.backup} Backup files: ${backupPaths.length}`);
|
|
946
|
+
backupPaths.forEach((path6) => {
|
|
947
|
+
lines.push(` ${COLOR_SCHEMES.dim(path6)}`);
|
|
948
|
+
});
|
|
949
|
+
}
|
|
950
|
+
return lines.join("\n");
|
|
951
|
+
}
|
|
952
|
+
/**
|
|
953
|
+
* Format start message for fix operation
|
|
954
|
+
* @param text Start message text
|
|
955
|
+
* @returns Formatted start message with fix emoji
|
|
956
|
+
*/
|
|
957
|
+
static startFix(text) {
|
|
958
|
+
return `${COLOR_SCHEMES.info(`${EMOJIS.fix} ${text}`)}`;
|
|
959
|
+
}
|
|
960
|
+
/**
|
|
961
|
+
* Format start message for validation operation
|
|
962
|
+
* @param text Start message text
|
|
963
|
+
* @returns Formatted start message with search emoji
|
|
964
|
+
*/
|
|
965
|
+
static startValidation(text) {
|
|
966
|
+
return `${COLOR_SCHEMES.info(`${EMOJIS.search} ${text}`)}`;
|
|
967
|
+
}
|
|
968
|
+
/**
|
|
969
|
+
* Format file reference
|
|
970
|
+
* @param text File path or reference
|
|
971
|
+
* @returns Formatted file reference with emoji
|
|
972
|
+
*/
|
|
973
|
+
static file(text) {
|
|
974
|
+
return `${EMOJIS.file} ${COLOR_SCHEMES.neutral(text)}`;
|
|
975
|
+
}
|
|
976
|
+
/**
|
|
977
|
+
* Format backup notification
|
|
978
|
+
* @param text Backup message text
|
|
979
|
+
* @returns Formatted backup message with emoji
|
|
980
|
+
*/
|
|
981
|
+
static backup(text) {
|
|
982
|
+
return `${COLOR_SCHEMES.info(`${EMOJIS.backup} ${text}`)}`;
|
|
983
|
+
}
|
|
984
|
+
/**
|
|
985
|
+
* Format skip notification
|
|
986
|
+
* @param text Skip message text
|
|
987
|
+
* @returns Formatted skip message with emoji
|
|
988
|
+
*/
|
|
989
|
+
static skip(text) {
|
|
990
|
+
return `${COLOR_SCHEMES.neutral(`${EMOJIS.skip} ${text}`)}`;
|
|
991
|
+
}
|
|
992
|
+
/**
|
|
993
|
+
* Format context line (indented with dim color)
|
|
994
|
+
* @param text Context text
|
|
995
|
+
* @returns Formatted context line with 3 spaces indentation
|
|
996
|
+
*/
|
|
997
|
+
static context(text) {
|
|
998
|
+
return ` ${COLOR_SCHEMES.dim(text)}`;
|
|
999
|
+
}
|
|
833
1000
|
};
|
|
1001
|
+
MessageFormatter.verboseMode = false;
|
|
1002
|
+
var msg = {
|
|
1003
|
+
error: (text) => MessageFormatter.error(text),
|
|
1004
|
+
warning: (text) => MessageFormatter.warning(text),
|
|
1005
|
+
info: (text) => MessageFormatter.info(text),
|
|
1006
|
+
success: (text) => MessageFormatter.success(text),
|
|
1007
|
+
debug: (text) => MessageFormatter.debug(text),
|
|
1008
|
+
neutral: (text) => MessageFormatter.neutral(text),
|
|
1009
|
+
errorDetail: (type, message, location) => MessageFormatter.errorDetail(type, message, location),
|
|
1010
|
+
summary: (successful, failed, backupPaths) => MessageFormatter.summary(successful, failed, backupPaths),
|
|
1011
|
+
startFix: (text) => MessageFormatter.startFix(text),
|
|
1012
|
+
startValidation: (text) => MessageFormatter.startValidation(text),
|
|
1013
|
+
file: (text) => MessageFormatter.file(text),
|
|
1014
|
+
backup: (text) => MessageFormatter.backup(text),
|
|
1015
|
+
skip: (text) => MessageFormatter.skip(text),
|
|
1016
|
+
context: (text) => MessageFormatter.context(text),
|
|
1017
|
+
setVerbose: (enabled) => MessageFormatter.setVerbose(enabled)
|
|
1018
|
+
};
|
|
1019
|
+
|
|
1020
|
+
// src/utils/diff-display.ts
|
|
834
1021
|
function displayLineRangeDiff(code, expectedRange, actualRange) {
|
|
835
1022
|
const output = [];
|
|
1023
|
+
output.push(COLOR_SCHEMES.dim("\u2501".repeat(64)));
|
|
836
1024
|
output.push(
|
|
837
|
-
|
|
838
|
-
);
|
|
839
|
-
output.push(
|
|
840
|
-
`${COLORS.RED}- Expected line range: ${expectedRange.start}-${expectedRange.end}${COLORS.RESET}`
|
|
841
|
-
);
|
|
842
|
-
output.push(
|
|
843
|
-
`${COLORS.GREEN}+ Actual line range: ${actualRange.start}-${actualRange.end}${COLORS.RESET}`
|
|
1025
|
+
COLOR_SCHEMES.error(`- Expected line range: ${expectedRange.start}-${expectedRange.end}`)
|
|
844
1026
|
);
|
|
845
1027
|
output.push(
|
|
846
|
-
|
|
1028
|
+
COLOR_SCHEMES.success(`+ Actual line range: ${actualRange.start}-${actualRange.end}`)
|
|
847
1029
|
);
|
|
1030
|
+
output.push(COLOR_SCHEMES.dim("\u2501".repeat(64)));
|
|
848
1031
|
const codeLines = code.split("\n");
|
|
849
1032
|
codeLines.forEach((line, index) => {
|
|
850
1033
|
const expectedLineNum = expectedRange.start + index;
|
|
851
1034
|
const actualLineNum = actualRange.start + index;
|
|
852
1035
|
output.push(
|
|
853
|
-
`${
|
|
1036
|
+
`${COLOR_SCHEMES.error(expectedLineNum.toString().padStart(4))} | ${COLOR_SCHEMES.success(actualLineNum.toString().padStart(4))} | ${line}`
|
|
854
1037
|
);
|
|
855
1038
|
});
|
|
856
|
-
output.push(
|
|
857
|
-
`${COLORS.DIM}\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501${COLORS.RESET}`
|
|
858
|
-
);
|
|
1039
|
+
output.push(COLOR_SCHEMES.dim("\u2501".repeat(64)));
|
|
859
1040
|
return output.join("\n");
|
|
860
1041
|
}
|
|
861
1042
|
|
|
@@ -888,14 +1069,16 @@ function resolveTargetFiles(targets, projectRoot, docsPath) {
|
|
|
888
1069
|
resolvedFiles.add(absolutePath);
|
|
889
1070
|
}
|
|
890
1071
|
} else {
|
|
891
|
-
console.warn(
|
|
1072
|
+
console.warn(msg.warning(`File not found: ${target}`));
|
|
892
1073
|
}
|
|
893
1074
|
}
|
|
894
1075
|
return Array.from(resolvedFiles);
|
|
895
1076
|
}
|
|
896
1077
|
async function main(args = process.argv.slice(2)) {
|
|
897
1078
|
const options = parseCliArgs(args);
|
|
898
|
-
|
|
1079
|
+
msg.setVerbose(options.verbose);
|
|
1080
|
+
console.log(`${msg.startValidation("Validating CODE_REF references in documentation...")}
|
|
1081
|
+
`);
|
|
899
1082
|
const config = loadConfig({
|
|
900
1083
|
targets: options.files.length > 0 ? options.files : void 0,
|
|
901
1084
|
verbose: options.verbose
|
|
@@ -903,13 +1086,13 @@ async function main(args = process.argv.slice(2)) {
|
|
|
903
1086
|
const docsPath = getDocsPath(config);
|
|
904
1087
|
const allMarkdownFiles = resolveTargetFiles(options.files, config.projectRoot, docsPath);
|
|
905
1088
|
if (options.files.length > 0 && options.verbose) {
|
|
906
|
-
console.log(
|
|
1089
|
+
console.log(`${msg.debug(`Specified files/directories: ${options.files.join(", ")}`)}
|
|
907
1090
|
`);
|
|
908
1091
|
}
|
|
909
1092
|
const ignoreFilePath = getIgnoreFilePath(config);
|
|
910
1093
|
const ignorePatterns = ignoreFilePath ? loadDocsignorePatterns(ignoreFilePath) : [];
|
|
911
1094
|
if (options.verbose) {
|
|
912
|
-
console.log(
|
|
1095
|
+
console.log(`${msg.debug(`Loaded ${ignorePatterns.length} ignore patterns`)}
|
|
913
1096
|
`);
|
|
914
1097
|
}
|
|
915
1098
|
const markdownFiles = allMarkdownFiles.filter((file) => {
|
|
@@ -918,11 +1101,11 @@ async function main(args = process.argv.slice(2)) {
|
|
|
918
1101
|
});
|
|
919
1102
|
if (options.verbose && allMarkdownFiles.length > markdownFiles.length) {
|
|
920
1103
|
console.log(
|
|
921
|
-
|
|
1104
|
+
`${msg.debug(`${allMarkdownFiles.length - markdownFiles.length} files excluded by ignore patterns`)}
|
|
922
1105
|
`
|
|
923
1106
|
);
|
|
924
1107
|
}
|
|
925
|
-
console.log(
|
|
1108
|
+
console.log(`${msg.file(`Found ${markdownFiles.length} markdown files`)}
|
|
926
1109
|
`);
|
|
927
1110
|
let totalRefs = 0;
|
|
928
1111
|
const allRefs = [];
|
|
@@ -933,25 +1116,25 @@ async function main(args = process.argv.slice(2)) {
|
|
|
933
1116
|
totalRefs += refs.length;
|
|
934
1117
|
refs.forEach((ref) => allRefs.push({ ref, file }));
|
|
935
1118
|
if (options.verbose) {
|
|
936
|
-
console.log(` ${path5.relative(docsPath, file)}: ${refs.length} references`);
|
|
1119
|
+
console.log(msg.debug(` ${path5.relative(docsPath, file)}: ${refs.length} references`));
|
|
937
1120
|
}
|
|
938
1121
|
}
|
|
939
1122
|
}
|
|
940
1123
|
console.log(`
|
|
941
|
-
|
|
1124
|
+
${msg.info(`Found ${totalRefs} CODE_REF references`)}
|
|
942
1125
|
`);
|
|
943
1126
|
if (totalRefs === 0) {
|
|
944
|
-
console.log("
|
|
1127
|
+
console.log(msg.success("No CODE_REF references found (no validation needed)"));
|
|
945
1128
|
process.exit(0);
|
|
946
1129
|
}
|
|
947
1130
|
const allErrors = await Promise.all(allRefs.map(({ ref }) => validateCodeRef(ref, config))).then(
|
|
948
1131
|
(results) => results.flat()
|
|
949
1132
|
);
|
|
950
1133
|
if (allErrors.length === 0) {
|
|
951
|
-
console.log("
|
|
1134
|
+
console.log(msg.success("All CODE_REF references are valid!"));
|
|
952
1135
|
process.exit(0);
|
|
953
1136
|
} else {
|
|
954
|
-
console.log(
|
|
1137
|
+
console.log(`${msg.error(`Found ${allErrors.length} errors:`)}
|
|
955
1138
|
`);
|
|
956
1139
|
const errorsByDoc = {};
|
|
957
1140
|
for (const error of allErrors) {
|
|
@@ -962,12 +1145,12 @@ async function main(args = process.argv.slice(2)) {
|
|
|
962
1145
|
errorsByDoc[docFile].push(error);
|
|
963
1146
|
}
|
|
964
1147
|
for (const [docFile, errors] of Object.entries(errorsByDoc)) {
|
|
965
|
-
console.log(
|
|
1148
|
+
console.log(`${msg.file(docFile)}:`);
|
|
966
1149
|
for (const error of errors) {
|
|
967
|
-
console.log(`
|
|
1150
|
+
console.log(` ${msg.error(`${error.type}: ${error.message}`)}`);
|
|
968
1151
|
const filePath = path5.relative(config.projectRoot, error.ref.docFile);
|
|
969
1152
|
const lineInfo = error.ref.docLineNumber ? `:${error.ref.docLineNumber}` : "";
|
|
970
|
-
console.log(`
|
|
1153
|
+
console.log(msg.context(` ${filePath}${lineInfo}: ${error.ref.fullMatch}`));
|
|
971
1154
|
if (error.type === "CODE_LOCATION_MISMATCH" && error.suggestedLines && options.verbose) {
|
|
972
1155
|
const filePath2 = path5.join(config.projectRoot, error.ref.refPath);
|
|
973
1156
|
const actualCode = extractLinesFromFile(
|
|
@@ -990,7 +1173,7 @@ async function main(args = process.argv.slice(2)) {
|
|
|
990
1173
|
}
|
|
991
1174
|
if (require.main === module) {
|
|
992
1175
|
main().catch((error) => {
|
|
993
|
-
console.error(
|
|
1176
|
+
console.error(msg.error(`Error: ${error}`));
|
|
994
1177
|
process.exit(1);
|
|
995
1178
|
});
|
|
996
1179
|
}
|
package/dist/cli/validate.mjs
CHANGED
|
@@ -4,8 +4,9 @@ import {
|
|
|
4
4
|
loadDocsignorePatterns
|
|
5
5
|
} from "../chunk-AQ3QIGEV.mjs";
|
|
6
6
|
import {
|
|
7
|
-
displayLineRangeDiff
|
|
8
|
-
|
|
7
|
+
displayLineRangeDiff,
|
|
8
|
+
msg
|
|
9
|
+
} from "../chunk-U3LM2QL7.mjs";
|
|
9
10
|
import {
|
|
10
11
|
__require,
|
|
11
12
|
extractCodeRefs,
|
|
@@ -48,14 +49,16 @@ function resolveTargetFiles(targets, projectRoot, docsPath) {
|
|
|
48
49
|
resolvedFiles.add(absolutePath);
|
|
49
50
|
}
|
|
50
51
|
} else {
|
|
51
|
-
console.warn(
|
|
52
|
+
console.warn(msg.warning(`File not found: ${target}`));
|
|
52
53
|
}
|
|
53
54
|
}
|
|
54
55
|
return Array.from(resolvedFiles);
|
|
55
56
|
}
|
|
56
57
|
async function main(args = process.argv.slice(2)) {
|
|
57
58
|
const options = parseCliArgs(args);
|
|
58
|
-
|
|
59
|
+
msg.setVerbose(options.verbose);
|
|
60
|
+
console.log(`${msg.startValidation("Validating CODE_REF references in documentation...")}
|
|
61
|
+
`);
|
|
59
62
|
const config = loadConfig({
|
|
60
63
|
targets: options.files.length > 0 ? options.files : void 0,
|
|
61
64
|
verbose: options.verbose
|
|
@@ -63,13 +66,13 @@ async function main(args = process.argv.slice(2)) {
|
|
|
63
66
|
const docsPath = getDocsPath(config);
|
|
64
67
|
const allMarkdownFiles = resolveTargetFiles(options.files, config.projectRoot, docsPath);
|
|
65
68
|
if (options.files.length > 0 && options.verbose) {
|
|
66
|
-
console.log(
|
|
69
|
+
console.log(`${msg.debug(`Specified files/directories: ${options.files.join(", ")}`)}
|
|
67
70
|
`);
|
|
68
71
|
}
|
|
69
72
|
const ignoreFilePath = getIgnoreFilePath(config);
|
|
70
73
|
const ignorePatterns = ignoreFilePath ? loadDocsignorePatterns(ignoreFilePath) : [];
|
|
71
74
|
if (options.verbose) {
|
|
72
|
-
console.log(
|
|
75
|
+
console.log(`${msg.debug(`Loaded ${ignorePatterns.length} ignore patterns`)}
|
|
73
76
|
`);
|
|
74
77
|
}
|
|
75
78
|
const markdownFiles = allMarkdownFiles.filter((file) => {
|
|
@@ -78,11 +81,11 @@ async function main(args = process.argv.slice(2)) {
|
|
|
78
81
|
});
|
|
79
82
|
if (options.verbose && allMarkdownFiles.length > markdownFiles.length) {
|
|
80
83
|
console.log(
|
|
81
|
-
|
|
84
|
+
`${msg.debug(`${allMarkdownFiles.length - markdownFiles.length} files excluded by ignore patterns`)}
|
|
82
85
|
`
|
|
83
86
|
);
|
|
84
87
|
}
|
|
85
|
-
console.log(
|
|
88
|
+
console.log(`${msg.file(`Found ${markdownFiles.length} markdown files`)}
|
|
86
89
|
`);
|
|
87
90
|
let totalRefs = 0;
|
|
88
91
|
const allRefs = [];
|
|
@@ -93,25 +96,25 @@ async function main(args = process.argv.slice(2)) {
|
|
|
93
96
|
totalRefs += refs.length;
|
|
94
97
|
refs.forEach((ref) => allRefs.push({ ref, file }));
|
|
95
98
|
if (options.verbose) {
|
|
96
|
-
console.log(` ${path.relative(docsPath, file)}: ${refs.length} references`);
|
|
99
|
+
console.log(msg.debug(` ${path.relative(docsPath, file)}: ${refs.length} references`));
|
|
97
100
|
}
|
|
98
101
|
}
|
|
99
102
|
}
|
|
100
103
|
console.log(`
|
|
101
|
-
|
|
104
|
+
${msg.info(`Found ${totalRefs} CODE_REF references`)}
|
|
102
105
|
`);
|
|
103
106
|
if (totalRefs === 0) {
|
|
104
|
-
console.log("
|
|
107
|
+
console.log(msg.success("No CODE_REF references found (no validation needed)"));
|
|
105
108
|
process.exit(0);
|
|
106
109
|
}
|
|
107
110
|
const allErrors = await Promise.all(allRefs.map(({ ref }) => validateCodeRef(ref, config))).then(
|
|
108
111
|
(results) => results.flat()
|
|
109
112
|
);
|
|
110
113
|
if (allErrors.length === 0) {
|
|
111
|
-
console.log("
|
|
114
|
+
console.log(msg.success("All CODE_REF references are valid!"));
|
|
112
115
|
process.exit(0);
|
|
113
116
|
} else {
|
|
114
|
-
console.log(
|
|
117
|
+
console.log(`${msg.error(`Found ${allErrors.length} errors:`)}
|
|
115
118
|
`);
|
|
116
119
|
const errorsByDoc = {};
|
|
117
120
|
for (const error of allErrors) {
|
|
@@ -122,12 +125,12 @@ async function main(args = process.argv.slice(2)) {
|
|
|
122
125
|
errorsByDoc[docFile].push(error);
|
|
123
126
|
}
|
|
124
127
|
for (const [docFile, errors] of Object.entries(errorsByDoc)) {
|
|
125
|
-
console.log(
|
|
128
|
+
console.log(`${msg.file(docFile)}:`);
|
|
126
129
|
for (const error of errors) {
|
|
127
|
-
console.log(`
|
|
130
|
+
console.log(` ${msg.error(`${error.type}: ${error.message}`)}`);
|
|
128
131
|
const filePath = path.relative(config.projectRoot, error.ref.docFile);
|
|
129
132
|
const lineInfo = error.ref.docLineNumber ? `:${error.ref.docLineNumber}` : "";
|
|
130
|
-
console.log(`
|
|
133
|
+
console.log(msg.context(` ${filePath}${lineInfo}: ${error.ref.fullMatch}`));
|
|
131
134
|
if (error.type === "CODE_LOCATION_MISMATCH" && error.suggestedLines && options.verbose) {
|
|
132
135
|
const filePath2 = path.join(config.projectRoot, error.ref.refPath);
|
|
133
136
|
const actualCode = extractLinesFromFile(
|
|
@@ -150,7 +153,7 @@ async function main(args = process.argv.slice(2)) {
|
|
|
150
153
|
}
|
|
151
154
|
if (__require.main === module) {
|
|
152
155
|
main().catch((error) => {
|
|
153
|
-
console.error(
|
|
156
|
+
console.error(msg.error(`Error: ${error}`));
|
|
154
157
|
process.exit(1);
|
|
155
158
|
});
|
|
156
159
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "docs-coderef",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "Validate and fix code references in markdown documentation",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"markdown",
|
|
@@ -46,6 +46,13 @@
|
|
|
46
46
|
"format:check": "prettier --check \"src/**/*.ts\" \"*.{js,json,md}\"",
|
|
47
47
|
"type-check": "tsc --noEmit",
|
|
48
48
|
"docs:validate": "tsx scripts/validate-docs.ts",
|
|
49
|
+
"demo:validate": "npm run build && cd demo && npx docs-coderef validate docs",
|
|
50
|
+
"demo:validate:valid": "npm run build && cd demo && npx docs-coderef validate docs/valid",
|
|
51
|
+
"demo:validate:invalid": "npm run build && cd demo && npx docs-coderef validate docs/invalid",
|
|
52
|
+
"demo:fix": "npm run build && cd demo && npx docs-coderef fix",
|
|
53
|
+
"demo:fix:dry": "npm run build && cd demo && npx docs-coderef fix --dry-run",
|
|
54
|
+
"demo:fix:auto": "npm run build && cd demo && npx docs-coderef fix --auto",
|
|
55
|
+
"demo:reset": "git checkout demo/docs/ && rm -f demo/docs/**/*.backup 2>/dev/null || true",
|
|
49
56
|
"prepublishOnly": "npm run build && npm test"
|
|
50
57
|
},
|
|
51
58
|
"engines": {
|
package/dist/chunk-NTTV47AI.mjs
DELETED
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
// src/utils/diff-display.ts
|
|
2
|
-
var COLORS = {
|
|
3
|
-
RED: "\x1B[31m",
|
|
4
|
-
GREEN: "\x1B[32m",
|
|
5
|
-
RESET: "\x1B[0m",
|
|
6
|
-
DIM: "\x1B[2m"
|
|
7
|
-
};
|
|
8
|
-
function displayCodeDiff(expected, actual) {
|
|
9
|
-
const expectedLines = expected.split("\n");
|
|
10
|
-
const actualLines = actual.split("\n");
|
|
11
|
-
const output = [];
|
|
12
|
-
const maxLines = Math.max(expectedLines.length, actualLines.length);
|
|
13
|
-
output.push(
|
|
14
|
-
`${COLORS.DIM}\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501${COLORS.RESET}`
|
|
15
|
-
);
|
|
16
|
-
output.push(`${COLORS.RED}- Expected code (in document)${COLORS.RESET}`);
|
|
17
|
-
output.push(`${COLORS.GREEN}+ Actual code (in file)${COLORS.RESET}`);
|
|
18
|
-
output.push(
|
|
19
|
-
`${COLORS.DIM}\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501${COLORS.RESET}`
|
|
20
|
-
);
|
|
21
|
-
for (let i = 0; i < maxLines; i++) {
|
|
22
|
-
const expectedLine = expectedLines[i];
|
|
23
|
-
const actualLine = actualLines[i];
|
|
24
|
-
if (expectedLine === actualLine) {
|
|
25
|
-
if (expectedLine !== void 0) {
|
|
26
|
-
output.push(` ${expectedLine}`);
|
|
27
|
-
}
|
|
28
|
-
} else {
|
|
29
|
-
if (expectedLine !== void 0) {
|
|
30
|
-
output.push(`${COLORS.RED}- ${expectedLine}${COLORS.RESET}`);
|
|
31
|
-
}
|
|
32
|
-
if (actualLine !== void 0) {
|
|
33
|
-
output.push(`${COLORS.GREEN}+ ${actualLine}${COLORS.RESET}`);
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
output.push(
|
|
38
|
-
`${COLORS.DIM}\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501${COLORS.RESET}`
|
|
39
|
-
);
|
|
40
|
-
return output.join("\n");
|
|
41
|
-
}
|
|
42
|
-
function displayLineRangeDiff(code, expectedRange, actualRange) {
|
|
43
|
-
const output = [];
|
|
44
|
-
output.push(
|
|
45
|
-
`${COLORS.DIM}\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501${COLORS.RESET}`
|
|
46
|
-
);
|
|
47
|
-
output.push(
|
|
48
|
-
`${COLORS.RED}- Expected line range: ${expectedRange.start}-${expectedRange.end}${COLORS.RESET}`
|
|
49
|
-
);
|
|
50
|
-
output.push(
|
|
51
|
-
`${COLORS.GREEN}+ Actual line range: ${actualRange.start}-${actualRange.end}${COLORS.RESET}`
|
|
52
|
-
);
|
|
53
|
-
output.push(
|
|
54
|
-
`${COLORS.DIM}\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501${COLORS.RESET}`
|
|
55
|
-
);
|
|
56
|
-
const codeLines = code.split("\n");
|
|
57
|
-
codeLines.forEach((line, index) => {
|
|
58
|
-
const expectedLineNum = expectedRange.start + index;
|
|
59
|
-
const actualLineNum = actualRange.start + index;
|
|
60
|
-
output.push(
|
|
61
|
-
`${COLORS.RED}${expectedLineNum.toString().padStart(4)}${COLORS.RESET} | ${COLORS.GREEN}${actualLineNum.toString().padStart(4)}${COLORS.RESET} | ${line}`
|
|
62
|
-
);
|
|
63
|
-
});
|
|
64
|
-
output.push(
|
|
65
|
-
`${COLORS.DIM}\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501${COLORS.RESET}`
|
|
66
|
-
);
|
|
67
|
-
return output.join("\n");
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
export {
|
|
71
|
-
displayCodeDiff,
|
|
72
|
-
displayLineRangeDiff
|
|
73
|
-
};
|