@doccov/sdk 0.5.7 → 0.5.8

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/dist/index.d.ts CHANGED
@@ -764,4 +764,82 @@ declare function readPackageJson(fs: FileSystem, dir: string): Promise<PackageJs
764
764
  * ```
765
765
  */
766
766
  declare function analyzeProject2(fs: FileSystem, options?: AnalyzeProjectOptions): Promise<ProjectInfo>;
767
- export { serializeJSDoc, safeParseJson, runExamplesWithPackage, runExamples, runExample, readPackageJson, parseMarkdownFiles, parseMarkdownFile, parseJSDocToPatch, parseAssertions, mergeFixes, isFixableDrift, isExecutableLang, hasNonAssertionComments, hasDocsImpact, hasDocsForExport, getUndocumentedExports, getRunCommand, getPrimaryBuildScript, getInstallCommand, getDocumentedExports, getDocsImpactSummary, generateFixesForExport, generateFix, formatPackageList, findRemovedReferences, findPackageByName, findJSDocLocation, findExportReferences, findDeprecatedReferences, extractPackageSpec, extractImports, extractFunctionCalls, diffSpecWithDocs, detectPackageManager, detectMonorepo, detectExampleRuntimeErrors, detectExampleAssertionFailures, detectEntryPoint, detectBuildInfo, createSourceFile, categorizeDrifts, blockReferencesExport, applyPatchToJSDoc, applyEdits, analyzeProject2 as analyzeProject, analyzeFile, analyzeDocsImpact, analyze, WorkspacePackage, SpecDiffWithDocs, SandboxFileSystem, RunExamplesWithPackageResult, RunExamplesWithPackageOptions, RunExampleOptions, ProjectInfo, PackageManagerInfo, PackageManager, PackageJson, PackageExports, OpenPkgSpec, OpenPkgOptions, OpenPkg4 as OpenPkg, NodeFileSystem, MonorepoType, MonorepoInfo, MemberChange, MarkdownDocFile, MarkdownCodeBlock, JSDocTag, JSDocReturn, JSDocPatch, JSDocParam, JSDocEdit, FixType, FixSuggestion, FilterOptions, FileSystem, ExportReference, ExampleRunResult, EntryPointSource, EntryPointInfo, DocsImpactResult, DocsImpactReference, DocsImpact, DocsChangeType, DocCovOptions, DocCov, DiffWithDocsOptions, Diagnostic, BuildInfo, ApplyEditsResult, AnalyzeProjectOptions, AnalyzeOptions, AnalysisResult };
767
+ import { SpecExport as SpecExport4 } from "@openpkg-ts/spec";
768
+ import { SpecExport as SpecExport3 } from "@openpkg-ts/spec";
769
+ type LintSeverity = "error" | "warn" | "off";
770
+ interface LintViolation {
771
+ rule: string;
772
+ severity: "error" | "warn";
773
+ message: string;
774
+ line?: number;
775
+ fixable: boolean;
776
+ }
777
+ interface LintRule {
778
+ name: string;
779
+ defaultSeverity: LintSeverity;
780
+ check(exp: SpecExport3, rawJSDoc?: string): LintViolation[];
781
+ fix?(exp: SpecExport3, rawJSDoc?: string): JSDocPatch | null;
782
+ }
783
+ interface LintConfig {
784
+ rules: Record<string, LintSeverity>;
785
+ }
786
+ interface LintResult {
787
+ violations: LintViolation[];
788
+ errorCount: number;
789
+ warningCount: number;
790
+ fixableCount: number;
791
+ }
792
+ /** All available lint rules */
793
+ declare const allRules: LintRule[];
794
+ /** Default configuration with rule defaults */
795
+ declare function getDefaultConfig(): LintConfig;
796
+ /** Get a rule by name */
797
+ declare function getRule(name: string): LintRule | undefined;
798
+ /** Lint a single */
799
+ declare function lintExport(exp: SpecExport4, rawJSDoc?: string, config?: LintConfig): LintViolation[];
800
+ /** Lint multiple exports and aggregate results */
801
+ declare function lintExports(exports: Array<{
802
+ export: SpecExport4;
803
+ rawJSDoc?: string;
804
+ }>, config?: LintConfig): LintResult;
805
+ /** Merge user config with defaults */
806
+ declare function mergeConfig(userConfig: Partial<LintConfig>): LintConfig;
807
+ declare const consistentParamStyle: LintRule;
808
+ declare const noEmptyReturns: LintRule;
809
+ declare const requireDescription: LintRule;
810
+ declare const requireExample: LintRule;
811
+ interface ExampleTypeError {
812
+ /** Index of the example in the examples array */
813
+ exampleIndex: number;
814
+ /** Line number within the example (1-based) */
815
+ line: number;
816
+ /** Column number (1-based) */
817
+ column: number;
818
+ /** Error message from TypeScript */
819
+ message: string;
820
+ /** TypeScript diagnostic code */
821
+ code: number;
822
+ }
823
+ interface TypecheckResult {
824
+ /** All type errors found across examples */
825
+ errors: ExampleTypeError[];
826
+ /** Number of examples that passed */
827
+ passed: number;
828
+ /** Number of examples that failed */
829
+ failed: number;
830
+ }
831
+ interface TypecheckOptions {
832
+ /** Path to tsconfig.json (auto-detected if not provided) */
833
+ tsconfig?: string;
834
+ /** Package name for imports (auto-detected from package.json if not provided) */
835
+ packageName?: string;
836
+ }
837
+ /**
838
+ * Type-check a single example
839
+ */
840
+ declare function typecheckExample(example: string, packagePath: string, options?: TypecheckOptions): ExampleTypeError[];
841
+ /**
842
+ * Type-check multiple examples
843
+ */
844
+ declare function typecheckExamples(examples: string[], packagePath: string, options?: TypecheckOptions): TypecheckResult;
845
+ export { typecheckExamples, typecheckExample, serializeJSDoc, safeParseJson, runExamplesWithPackage, runExamples, runExample, requireExample, requireDescription, readPackageJson, parseMarkdownFiles, parseMarkdownFile, parseJSDocToPatch, parseAssertions, noEmptyReturns, mergeFixes, mergeConfig, lintExports, lintExport, isFixableDrift, isExecutableLang, hasNonAssertionComments, hasDocsImpact, hasDocsForExport, getUndocumentedExports, getRunCommand, getRule, getPrimaryBuildScript, getInstallCommand, getDocumentedExports, getDocsImpactSummary, getDefaultConfig, generateFixesForExport, generateFix, formatPackageList, findRemovedReferences, findPackageByName, findJSDocLocation, findExportReferences, findDeprecatedReferences, extractPackageSpec, extractImports, extractFunctionCalls, diffSpecWithDocs, detectPackageManager, detectMonorepo, detectExampleRuntimeErrors, detectExampleAssertionFailures, detectEntryPoint, detectBuildInfo, createSourceFile, consistentParamStyle, categorizeDrifts, blockReferencesExport, applyPatchToJSDoc, applyEdits, analyzeProject2 as analyzeProject, analyzeFile, analyzeDocsImpact, analyze, allRules, WorkspacePackage, TypecheckResult, TypecheckOptions, SpecDiffWithDocs, SandboxFileSystem, RunExamplesWithPackageResult, RunExamplesWithPackageOptions, RunExampleOptions, ProjectInfo, PackageManagerInfo, PackageManager, PackageJson, PackageExports, OpenPkgSpec, OpenPkgOptions, OpenPkg4 as OpenPkg, NodeFileSystem, MonorepoType, MonorepoInfo, MemberChange, MarkdownDocFile, MarkdownCodeBlock, LintViolation, LintSeverity, LintRule, LintResult, LintConfig, JSDocTag, JSDocReturn, JSDocPatch, JSDocParam, JSDocEdit, FixType, FixSuggestion, FilterOptions, FileSystem, ExportReference, ExampleTypeError, ExampleRunResult, EntryPointSource, EntryPointInfo, DocsImpactResult, DocsImpactReference, DocsImpact, DocsChangeType, DocCovOptions, DocCov, DiffWithDocsOptions, Diagnostic, BuildInfo, ApplyEditsResult, AnalyzeProjectOptions, AnalyzeOptions, AnalysisResult };
package/dist/index.js CHANGED
@@ -5938,18 +5938,323 @@ async function analyzeProject(fs7, options = {}) {
5938
5938
  ]);
5939
5939
  return { packageManager, monorepo, entryPoint, build };
5940
5940
  }
5941
+ // src/lint/rules/consistent-param-style.ts
5942
+ var consistentParamStyle = {
5943
+ name: "consistent-param-style",
5944
+ defaultSeverity: "off",
5945
+ check(exp, rawJSDoc) {
5946
+ if (!rawJSDoc)
5947
+ return [];
5948
+ const violations = [];
5949
+ const paramRegex = /@param\s+(?:\{[^}]+\}\s+)?(\S+)\s+([^@\n]+)/g;
5950
+ let match;
5951
+ while ((match = paramRegex.exec(rawJSDoc)) !== null) {
5952
+ const paramName = match[1];
5953
+ const rest = match[2].trim();
5954
+ if (rest && !rest.startsWith("-") && !rest.startsWith("–")) {
5955
+ violations.push({
5956
+ rule: "consistent-param-style",
5957
+ severity: "warn",
5958
+ message: `Parameter '${paramName}' should use dash separator: @param ${paramName} - description`,
5959
+ fixable: true
5960
+ });
5961
+ }
5962
+ }
5963
+ return violations;
5964
+ },
5965
+ fix(_exp, rawJSDoc) {
5966
+ if (!rawJSDoc)
5967
+ return null;
5968
+ const patch = parseJSDocToPatch(rawJSDoc);
5969
+ if (!patch.params || patch.params.length === 0)
5970
+ return null;
5971
+ return patch;
5972
+ }
5973
+ };
5974
+ // src/lint/rules/no-empty-returns.ts
5975
+ var noEmptyReturns = {
5976
+ name: "no-empty-returns",
5977
+ defaultSeverity: "warn",
5978
+ check(exp, rawJSDoc) {
5979
+ if (!rawJSDoc)
5980
+ return [];
5981
+ const returnsMatch = rawJSDoc.match(/@returns?\s*(?:\{[^}]*\})?\s*$/m);
5982
+ if (returnsMatch) {
5983
+ return [
5984
+ {
5985
+ rule: "no-empty-returns",
5986
+ severity: "warn",
5987
+ message: `Export '${exp.name}' has @returns without a description`,
5988
+ fixable: false
5989
+ }
5990
+ ];
5991
+ }
5992
+ const returnsTypeOnly = rawJSDoc.match(/@returns?\s+\{[^}]+\}\s*$/m);
5993
+ if (returnsTypeOnly) {
5994
+ return [
5995
+ {
5996
+ rule: "no-empty-returns",
5997
+ severity: "warn",
5998
+ message: `Export '${exp.name}' has @returns without a description`,
5999
+ fixable: false
6000
+ }
6001
+ ];
6002
+ }
6003
+ return [];
6004
+ }
6005
+ };
6006
+ // src/lint/rules/require-description.ts
6007
+ var requireDescription = {
6008
+ name: "require-description",
6009
+ defaultSeverity: "warn",
6010
+ check(exp) {
6011
+ if (!exp.description || exp.description.trim() === "") {
6012
+ return [
6013
+ {
6014
+ rule: "require-description",
6015
+ severity: "warn",
6016
+ message: `Export '${exp.name}' is missing a description`,
6017
+ fixable: false
6018
+ }
6019
+ ];
6020
+ }
6021
+ return [];
6022
+ }
6023
+ };
6024
+ // src/lint/rules/require-example.ts
6025
+ var requireExample = {
6026
+ name: "require-example",
6027
+ defaultSeverity: "off",
6028
+ check(exp) {
6029
+ if (exp.kind !== "function" && exp.kind !== "method") {
6030
+ return [];
6031
+ }
6032
+ if (!exp.examples || exp.examples.length === 0) {
6033
+ return [
6034
+ {
6035
+ rule: "require-example",
6036
+ severity: "warn",
6037
+ message: `Function '${exp.name}' is missing an @example`,
6038
+ fixable: false
6039
+ }
6040
+ ];
6041
+ }
6042
+ return [];
6043
+ }
6044
+ };
6045
+ // src/lint/engine.ts
6046
+ var allRules = [
6047
+ requireDescription,
6048
+ requireExample,
6049
+ noEmptyReturns,
6050
+ consistentParamStyle
6051
+ ];
6052
+ function getDefaultConfig() {
6053
+ const rules = {};
6054
+ for (const rule of allRules) {
6055
+ rules[rule.name] = rule.defaultSeverity;
6056
+ }
6057
+ return { rules };
6058
+ }
6059
+ function getRule(name) {
6060
+ return allRules.find((r) => r.name === name);
6061
+ }
6062
+ function lintExport(exp, rawJSDoc, config = getDefaultConfig()) {
6063
+ const violations = [];
6064
+ for (const rule of allRules) {
6065
+ const severity = config.rules[rule.name];
6066
+ if (severity === "off")
6067
+ continue;
6068
+ const ruleViolations = rule.check(exp, rawJSDoc);
6069
+ for (const v of ruleViolations) {
6070
+ violations.push({
6071
+ ...v,
6072
+ severity: severity === "error" ? "error" : "warn"
6073
+ });
6074
+ }
6075
+ }
6076
+ return violations;
6077
+ }
6078
+ function lintExports(exports, config = getDefaultConfig()) {
6079
+ const violations = [];
6080
+ for (const { export: exp, rawJSDoc } of exports) {
6081
+ violations.push(...lintExport(exp, rawJSDoc, config));
6082
+ }
6083
+ return {
6084
+ violations,
6085
+ errorCount: violations.filter((v) => v.severity === "error").length,
6086
+ warningCount: violations.filter((v) => v.severity === "warn").length,
6087
+ fixableCount: violations.filter((v) => v.fixable).length
6088
+ };
6089
+ }
6090
+ function mergeConfig(userConfig) {
6091
+ const defaults = getDefaultConfig();
6092
+ return {
6093
+ rules: {
6094
+ ...defaults.rules,
6095
+ ...userConfig.rules
6096
+ }
6097
+ };
6098
+ }
6099
+ // src/typecheck/example-typechecker.ts
6100
+ import * as fs7 from "node:fs";
6101
+ import * as path8 from "node:path";
6102
+ import ts3 from "typescript";
6103
+ function stripCodeBlockMarkers2(code) {
6104
+ return code.replace(/^```(?:ts|typescript|js|javascript)?\n?/i, "").replace(/\n?```$/i, "").trim();
6105
+ }
6106
+ function getPackageName(packagePath) {
6107
+ const pkgJsonPath = path8.join(packagePath, "package.json");
6108
+ if (fs7.existsSync(pkgJsonPath)) {
6109
+ try {
6110
+ const pkgJson = JSON.parse(fs7.readFileSync(pkgJsonPath, "utf-8"));
6111
+ return pkgJson.name;
6112
+ } catch {
6113
+ return;
6114
+ }
6115
+ }
6116
+ return;
6117
+ }
6118
+ function findTsConfig(packagePath) {
6119
+ let dir = packagePath;
6120
+ while (dir !== path8.dirname(dir)) {
6121
+ const tsConfigPath = path8.join(dir, "tsconfig.json");
6122
+ if (fs7.existsSync(tsConfigPath)) {
6123
+ return tsConfigPath;
6124
+ }
6125
+ dir = path8.dirname(dir);
6126
+ }
6127
+ return;
6128
+ }
6129
+ function createVirtualSource(example, packageName, exportNames) {
6130
+ const cleanCode = stripCodeBlockMarkers2(example);
6131
+ const lines = [];
6132
+ if (packageName && exportNames && exportNames.length > 0) {
6133
+ lines.push(`import { ${exportNames.join(", ")} } from '${packageName}';`);
6134
+ lines.push("");
6135
+ }
6136
+ lines.push(cleanCode);
6137
+ return lines.join(`
6138
+ `);
6139
+ }
6140
+ function getCompilerOptions(tsconfigPath) {
6141
+ if (tsconfigPath && fs7.existsSync(tsconfigPath)) {
6142
+ const configFile = ts3.readConfigFile(tsconfigPath, ts3.sys.readFile);
6143
+ if (!configFile.error) {
6144
+ const parsed = ts3.parseJsonConfigFileContent(configFile.config, ts3.sys, path8.dirname(tsconfigPath));
6145
+ return {
6146
+ ...parsed.options,
6147
+ noEmit: true,
6148
+ skipLibCheck: true
6149
+ };
6150
+ }
6151
+ }
6152
+ return {
6153
+ target: ts3.ScriptTarget.ES2022,
6154
+ module: ts3.ModuleKind.ESNext,
6155
+ moduleResolution: ts3.ModuleResolutionKind.Bundler,
6156
+ esModuleInterop: true,
6157
+ strict: true,
6158
+ noEmit: true,
6159
+ skipLibCheck: true
6160
+ };
6161
+ }
6162
+ function typecheckExample(example, packagePath, options = {}) {
6163
+ const errors = [];
6164
+ const cleanCode = stripCodeBlockMarkers2(example);
6165
+ const packageName = options.packageName ?? getPackageName(packagePath);
6166
+ const tsconfigPath = options.tsconfig ?? findTsConfig(packagePath);
6167
+ const compilerOptions = getCompilerOptions(tsconfigPath);
6168
+ const virtualSource = createVirtualSource(cleanCode, packageName);
6169
+ const virtualFileName = path8.join(packagePath, "__doccov_example__.ts");
6170
+ const hasImport = packageName !== undefined;
6171
+ const lineOffset = hasImport ? 2 : 0;
6172
+ const sourceFile = ts3.createSourceFile(virtualFileName, virtualSource, ts3.ScriptTarget.ES2022, true);
6173
+ const defaultHost = ts3.createCompilerHost(compilerOptions);
6174
+ const customHost = {
6175
+ ...defaultHost,
6176
+ getSourceFile: (fileName, languageVersion) => {
6177
+ if (fileName === virtualFileName) {
6178
+ return sourceFile;
6179
+ }
6180
+ return defaultHost.getSourceFile(fileName, languageVersion);
6181
+ },
6182
+ fileExists: (fileName) => {
6183
+ if (fileName === virtualFileName)
6184
+ return true;
6185
+ return defaultHost.fileExists(fileName);
6186
+ },
6187
+ readFile: (fileName) => {
6188
+ if (fileName === virtualFileName)
6189
+ return virtualSource;
6190
+ return defaultHost.readFile(fileName);
6191
+ }
6192
+ };
6193
+ const program = ts3.createProgram([virtualFileName], compilerOptions, customHost);
6194
+ const diagnostics = ts3.getPreEmitDiagnostics(program, sourceFile);
6195
+ for (const diagnostic of diagnostics) {
6196
+ if (diagnostic.file && diagnostic.start !== undefined) {
6197
+ const { line, character } = diagnostic.file.getLineAndCharacterOfPosition(diagnostic.start);
6198
+ const exampleLine = line - lineOffset + 1;
6199
+ if (exampleLine < 1)
6200
+ continue;
6201
+ errors.push({
6202
+ exampleIndex: 0,
6203
+ line: exampleLine,
6204
+ column: character + 1,
6205
+ message: ts3.flattenDiagnosticMessageText(diagnostic.messageText, `
6206
+ `),
6207
+ code: diagnostic.code
6208
+ });
6209
+ }
6210
+ }
6211
+ return errors;
6212
+ }
6213
+ function typecheckExamples(examples, packagePath, options = {}) {
6214
+ const allErrors = [];
6215
+ let passed = 0;
6216
+ let failed = 0;
6217
+ for (let i = 0;i < examples.length; i++) {
6218
+ const example = examples[i];
6219
+ if (!example || typeof example !== "string" || !example.trim()) {
6220
+ continue;
6221
+ }
6222
+ const errors = typecheckExample(example, packagePath, options);
6223
+ for (const error of errors) {
6224
+ allErrors.push({ ...error, exampleIndex: i });
6225
+ }
6226
+ if (errors.length > 0) {
6227
+ failed++;
6228
+ } else {
6229
+ passed++;
6230
+ }
6231
+ }
6232
+ return {
6233
+ errors: allErrors,
6234
+ passed,
6235
+ failed
6236
+ };
6237
+ }
5941
6238
  export {
6239
+ typecheckExamples,
6240
+ typecheckExample,
5942
6241
  serializeJSDoc,
5943
6242
  safeParseJson,
5944
6243
  runExamplesWithPackage,
5945
6244
  runExamples,
5946
6245
  runExample,
6246
+ requireExample,
6247
+ requireDescription,
5947
6248
  readPackageJson,
5948
6249
  parseMarkdownFiles,
5949
6250
  parseMarkdownFile,
5950
6251
  parseJSDocToPatch,
5951
6252
  parseAssertions,
6253
+ noEmptyReturns,
5952
6254
  mergeFixes,
6255
+ mergeConfig,
6256
+ lintExports,
6257
+ lintExport,
5953
6258
  isFixableDrift,
5954
6259
  isExecutableLang,
5955
6260
  hasNonAssertionComments,
@@ -5957,10 +6262,12 @@ export {
5957
6262
  hasDocsForExport,
5958
6263
  getUndocumentedExports,
5959
6264
  getRunCommand,
6265
+ getRule,
5960
6266
  getPrimaryBuildScript,
5961
6267
  getInstallCommand2 as getInstallCommand,
5962
6268
  getDocumentedExports,
5963
6269
  getDocsImpactSummary,
6270
+ getDefaultConfig,
5964
6271
  generateFixesForExport,
5965
6272
  generateFix,
5966
6273
  formatPackageList,
@@ -5980,6 +6287,7 @@ export {
5980
6287
  detectEntryPoint,
5981
6288
  detectBuildInfo,
5982
6289
  createSourceFile,
6290
+ consistentParamStyle,
5983
6291
  categorizeDrifts,
5984
6292
  blockReferencesExport,
5985
6293
  applyPatchToJSDoc,
@@ -5988,6 +6296,7 @@ export {
5988
6296
  analyzeFile,
5989
6297
  analyzeDocsImpact,
5990
6298
  analyze,
6299
+ allRules,
5991
6300
  SandboxFileSystem,
5992
6301
  OpenPkg,
5993
6302
  NodeFileSystem,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@doccov/sdk",
3
- "version": "0.5.7",
3
+ "version": "0.5.8",
4
4
  "description": "DocCov SDK - Documentation coverage and drift detection for TypeScript",
5
5
  "keywords": [
6
6
  "typescript",