patram 0.8.0 → 0.10.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/bin/patram.js +2 -2
- package/lib/cli/arguments.types.d.ts +63 -0
- package/lib/{parse-cli-color-options.js → cli/color-options.js} +2 -2
- package/lib/cli/command-helpers.js +35 -0
- package/lib/cli/commands/check.js +73 -0
- package/lib/cli/commands/fields.js +57 -0
- package/lib/cli/commands/queries.js +41 -0
- package/lib/cli/commands/query.js +242 -0
- package/lib/cli/commands/refs.js +72 -0
- package/lib/cli/commands/show.js +58 -0
- package/lib/{cli-help-metadata.js → cli/help-metadata.js} +7 -102
- package/lib/cli/main.js +76 -0
- package/lib/{parse-cli-arguments-helpers.js → cli/parse-arguments-helpers.js} +24 -12
- package/lib/{parse-cli-arguments.js → cli/parse-arguments.js} +12 -12
- package/lib/{parse-cli-query-pagination.js → cli/query-pagination.js} +2 -2
- package/lib/{render-cli-help.js → cli/render-help.js} +84 -3
- package/lib/{resolve-output-mode.js → cli/resolve-output-mode.js} +2 -2
- package/lib/cli/test-helpers.js +30 -0
- package/lib/config/defaults.d.ts +10 -0
- package/lib/config/defaults.js +80 -0
- package/lib/config/load-patram-config.d.ts +76 -0
- package/lib/config/load-patram-config.js +315 -0
- package/lib/config/load-patram-config.types.d.ts +45 -0
- package/lib/{patram-config.d.ts → config/patram-config.d.ts} +31 -31
- package/lib/{patram-config.js → config/patram-config.js} +3 -3
- package/lib/{patram-config.types.d.ts → config/patram-config.types.d.ts} +1 -1
- package/lib/{resolve-patram-graph-config.d.ts → config/resolve-patram-graph-config.d.ts} +2 -2
- package/lib/{resolve-patram-graph-config.js → config/resolve-patram-graph-config.js} +3 -3
- package/lib/{load-patram-config.d.ts → config/schema.d.ts} +149 -191
- package/lib/config/schema.js +328 -0
- package/lib/{source-file-defaults.d.ts → config/source-file-defaults.d.ts} +0 -1
- package/lib/{source-file-defaults.js → config/source-file-defaults.js} +1 -1
- package/lib/config/validation.d.ts +27 -0
- package/lib/config/validation.js +615 -0
- package/lib/directive-validation-test-helpers.js +1 -1
- package/lib/find-close-match.d.ts +8 -0
- package/lib/find-close-match.js +98 -0
- package/lib/{build-graph-identity.d.ts → graph/build-graph-identity.d.ts} +2 -2
- package/lib/{build-graph-identity.js → graph/build-graph-identity.js} +1 -1
- package/lib/{build-graph.d.ts → graph/build-graph.d.ts} +3 -3
- package/lib/{build-graph.js → graph/build-graph.js} +17 -13
- package/lib/{build-graph.types.d.ts → graph/build-graph.types.d.ts} +1 -1
- package/lib/graph/check-directive-metadata.d.ts +23 -0
- package/lib/{check-directive-metadata.js → graph/check-directive-metadata.js} +7 -7
- package/lib/graph/check-directive-path-target.d.ts +32 -0
- package/lib/{check-directive-path-target.js → graph/check-directive-path-target.js} +4 -4
- package/lib/graph/check-directive-value.d.ts +19 -0
- package/lib/{check-directive-value.js → graph/check-directive-value.js} +3 -3
- package/lib/graph/check-graph.d.ts +29 -0
- package/lib/{check-graph.js → graph/check-graph.js} +6 -6
- package/lib/graph/directive-diagnostics.d.ts +20 -0
- package/lib/{directive-diagnostics.js → graph/directive-diagnostics.js} +2 -2
- package/lib/graph/directive-type-rules.d.ts +18 -0
- package/lib/{directive-type-rules.js → graph/directive-type-rules.js} +3 -3
- package/lib/{document-node-identity.d.ts → graph/document-node-identity.d.ts} +2 -2
- package/lib/{document-node-identity.js → graph/document-node-identity.js} +2 -2
- package/lib/graph/inspect-reverse-references.d.ts +22 -0
- package/lib/{inspect-reverse-references.js → graph/inspect-reverse-references.js} +2 -2
- package/lib/{load-project-graph.d.ts → graph/load-project-graph.d.ts} +10 -10
- package/lib/{load-project-graph.js → graph/load-project-graph.js} +12 -12
- package/lib/{parse-where-clause.types.d.ts → graph/parse-where-clause.types.d.ts} +1 -1
- package/lib/{query-graph.d.ts → graph/query/execute.d.ts} +11 -11
- package/lib/{query-graph.js → graph/query/execute.js} +12 -12
- package/lib/{query-inspection.d.ts → graph/query/inspect.d.ts} +10 -8
- package/lib/{query-inspection.js → graph/query/inspect.js} +16 -17
- package/lib/{parse-where-clause.d.ts → graph/query/parse.d.ts} +6 -6
- package/lib/{parse-where-clause.js → graph/query/parse.js} +2 -2
- package/lib/graph/query/resolve.d.ts +28 -0
- package/lib/{resolve-where-clause.js → graph/query/resolve.js} +39 -5
- package/lib/graph/reverse-reference-test-helpers.d.ts +55 -0
- package/lib/{command-output.js → output/command-output.js} +5 -5
- package/lib/{derived-summary.js → output/derived-summary.js} +7 -7
- package/lib/{layout-incoming-references.js → output/layout-incoming-references.js} +4 -4
- package/lib/{layout-incoming-summary-lines.js → output/layout-incoming-summary-lines.js} +0 -5
- package/lib/{layout-stored-queries.js → output/layout-stored-queries.js} +27 -11
- package/lib/{list-queries.js → output/list-queries.js} +3 -2
- package/lib/{render-check-output.js → output/render-check-output.js} +1 -1
- package/lib/{render-field-discovery.js → output/render-field-discovery.js} +3 -3
- package/lib/output/render-output-view.js +56 -0
- package/lib/{render-json-output.js → output/renderers/json.js} +10 -6
- package/lib/{render-plain-output.js → output/renderers/plain.js} +34 -33
- package/lib/{render-rich-output.js → output/renderers/rich.js} +44 -32
- package/lib/{resolve-check-target.js → output/resolve-check-target.js} +1 -1
- package/lib/{render-rich-source.js → output/rich-source/render.js} +6 -6
- package/lib/{show-document.js → output/show-document.js} +12 -12
- package/lib/{render-output-view.js → output/view-model/index.js} +11 -70
- package/lib/{write-paged-output.js → output/write-paged-output.js} +9 -5
- package/lib/{claim-helpers.d.ts → parse/claim-helpers.d.ts} +2 -2
- package/lib/{parse-jsdoc-claims.d.ts → parse/jsdoc/parse-jsdoc-claims.d.ts} +2 -2
- package/lib/{parse-jsdoc-claims.js → parse/jsdoc/parse-jsdoc-claims.js} +9 -9
- package/lib/{parse-jsdoc-prose.d.ts → parse/jsdoc/parse-jsdoc-prose.d.ts} +1 -1
- package/lib/{parse-jsdoc-prose.js → parse/jsdoc/parse-jsdoc-prose.js} +1 -1
- package/lib/{parse-markdown-claims.d.ts → parse/markdown/parse-markdown-claims.d.ts} +3 -3
- package/lib/{parse-markdown-claims.js → parse/markdown/parse-markdown-claims.js} +8 -8
- package/lib/{parse-markdown-directives.d.ts → parse/markdown/parse-markdown-directives.d.ts} +2 -2
- package/lib/{parse-markdown-directives.js → parse/markdown/parse-markdown-directives.js} +3 -3
- package/lib/{parse-claims.d.ts → parse/parse-claims.d.ts} +4 -13
- package/lib/{parse-claims.js → parse/parse-claims.js} +18 -26
- package/lib/{parse-claims.types.d.ts → parse/parse-claims.types.d.ts} +1 -1
- package/lib/{tagged-fenced-block-error.d.ts → parse/tagged-fenced/tagged-fenced-block-error.d.ts} +2 -2
- package/lib/{tagged-fenced-block-parser.d.ts → parse/tagged-fenced/tagged-fenced-block-parser.d.ts} +3 -3
- package/lib/{tagged-fenced-blocks.d.ts → parse/tagged-fenced/tagged-fenced-blocks.d.ts} +7 -7
- package/lib/{tagged-fenced-blocks.js → parse/tagged-fenced/tagged-fenced-blocks.js} +3 -3
- package/lib/{parse-yaml-claims.d.ts → parse/yaml/parse-yaml-claims.d.ts} +4 -4
- package/lib/{parse-yaml-claims.js → parse/yaml/parse-yaml-claims.js} +22 -13
- package/lib/patram.d.ts +29 -28
- package/lib/patram.js +5 -6
- package/lib/{discover-fields.js → scan/discover-fields.js} +145 -18
- package/lib/scan/list-repo-files.d.ts +16 -0
- package/lib/{list-source-files.js → scan/list-repo-files.js} +2 -35
- package/lib/{list-source-files.d.ts → scan/list-source-files.d.ts} +4 -11
- package/lib/scan/list-source-files.js +45 -0
- package/package.json +8 -7
- package/lib/build-graph.types.ts +0 -27
- package/lib/discover-fields.types.ts +0 -52
- package/lib/load-patram-config.js +0 -1215
- package/lib/load-patram-config.types.d.ts +0 -45
- package/lib/load-patram-config.types.ts +0 -56
- package/lib/output-view.types.d.ts +0 -88
- package/lib/output-view.types.ts +0 -113
- package/lib/overlay-graph.d.ts +0 -43
- package/lib/overlay-graph.js +0 -191
- package/lib/parse-claims.types.ts +0 -41
- package/lib/parse-cli-arguments.types.ts +0 -75
- package/lib/parse-where-clause.types.ts +0 -87
- package/lib/patram-cli.js +0 -593
- package/lib/patram-config.types.ts +0 -22
- package/lib/tagged-fenced-blocks.types.ts +0 -38
- /package/lib/{reverse-reference-test-helpers.js → graph/reverse-reference-test-helpers.js} +0 -0
- /package/lib/{format-derived-summary-row.js → output/format-derived-summary-row.js} +0 -0
- /package/lib/{format-node-header.js → output/format-node-header.js} +0 -0
- /package/lib/{format-output-item-block.js → output/format-output-item-block.js} +0 -0
- /package/lib/{format-output-metadata.js → output/format-output-metadata.js} +0 -0
- /package/lib/{claim-helpers.js → parse/claim-helpers.js} +0 -0
- /package/lib/{parse-jsdoc-blocks.d.ts → parse/jsdoc/parse-jsdoc-blocks.d.ts} +0 -0
- /package/lib/{parse-jsdoc-blocks.js → parse/jsdoc/parse-jsdoc-blocks.js} +0 -0
- /package/lib/{tagged-fenced-block-error.js → parse/tagged-fenced/tagged-fenced-block-error.js} +0 -0
- /package/lib/{tagged-fenced-block-markdown.d.ts → parse/tagged-fenced/tagged-fenced-block-markdown.d.ts} +0 -0
- /package/lib/{tagged-fenced-block-markdown.js → parse/tagged-fenced/tagged-fenced-block-markdown.js} +0 -0
- /package/lib/{tagged-fenced-block-metadata.d.ts → parse/tagged-fenced/tagged-fenced-block-metadata.d.ts} +0 -0
- /package/lib/{tagged-fenced-block-metadata.js → parse/tagged-fenced/tagged-fenced-block-metadata.js} +0 -0
- /package/lib/{tagged-fenced-block-parser.js → parse/tagged-fenced/tagged-fenced-block-parser.js} +0 -0
- /package/lib/{tagged-fenced-blocks.types.d.ts → parse/tagged-fenced/tagged-fenced-blocks.types.d.ts} +0 -0
package/lib/patram.d.ts
CHANGED
|
@@ -3,52 +3,53 @@ export {
|
|
|
3
3
|
loadTaggedFencedBlocks,
|
|
4
4
|
selectTaggedBlock,
|
|
5
5
|
selectTaggedBlocks,
|
|
6
|
-
} from './tagged-fenced-blocks.js';
|
|
6
|
+
} from './parse/tagged-fenced/tagged-fenced-blocks.js';
|
|
7
7
|
|
|
8
|
-
export { parseWhereClause } from './parse
|
|
9
|
-
export { getQuerySemanticDiagnostics } from './query
|
|
10
|
-
export { loadProjectGraph } from './load-project-graph.js';
|
|
11
|
-
export {
|
|
12
|
-
export { queryGraph } from './query-graph.js';
|
|
8
|
+
export { parseWhereClause } from './graph/query/parse.js';
|
|
9
|
+
export { getQuerySemanticDiagnostics } from './graph/query/inspect.js';
|
|
10
|
+
export { loadProjectGraph } from './graph/load-project-graph.js';
|
|
11
|
+
export { queryGraph } from './graph/query/execute.js';
|
|
13
12
|
|
|
14
|
-
export type PatramGraphNode =
|
|
15
|
-
|
|
13
|
+
export type PatramGraphNode =
|
|
14
|
+
import('./graph/build-graph.types.d.ts').GraphNode;
|
|
15
|
+
export type PatramGraphEdge =
|
|
16
|
+
import('./graph/build-graph.types.d.ts').GraphEdge;
|
|
16
17
|
export type PatramBuildGraphResult =
|
|
17
|
-
import('./build-graph.types.ts').BuildGraphResult;
|
|
18
|
+
import('./graph/build-graph.types.d.ts').BuildGraphResult;
|
|
18
19
|
export type PatramDiagnostic =
|
|
19
|
-
import('./load-patram-config.types.ts').PatramDiagnostic;
|
|
20
|
+
import('./config/load-patram-config.types.d.ts').PatramDiagnostic;
|
|
20
21
|
export type PatramRepoConfig =
|
|
21
|
-
import('./load-patram-config.types.ts').PatramRepoConfig;
|
|
22
|
+
import('./config/load-patram-config.types.d.ts').PatramRepoConfig;
|
|
22
23
|
export type PatramParsedFieldName =
|
|
23
|
-
import('./parse-where-clause.types.ts').ParsedFieldName;
|
|
24
|
+
import('./graph/parse-where-clause.types.d.ts').ParsedFieldName;
|
|
24
25
|
export type PatramParsedFieldTerm =
|
|
25
|
-
import('./parse-where-clause.types.ts').ParsedFieldTerm;
|
|
26
|
+
import('./graph/parse-where-clause.types.d.ts').ParsedFieldTerm;
|
|
26
27
|
export type PatramParsedFieldSetTerm =
|
|
27
|
-
import('./parse-where-clause.types.ts').ParsedFieldSetTerm;
|
|
28
|
+
import('./graph/parse-where-clause.types.d.ts').ParsedFieldSetTerm;
|
|
28
29
|
export type PatramParsedTraversalTerm =
|
|
29
|
-
import('./parse-where-clause.types.ts').ParsedTraversalTerm;
|
|
30
|
+
import('./graph/parse-where-clause.types.d.ts').ParsedTraversalTerm;
|
|
30
31
|
export type PatramParsedRelationTerm =
|
|
31
|
-
import('./parse-where-clause.types.ts').ParsedRelationTerm;
|
|
32
|
+
import('./graph/parse-where-clause.types.d.ts').ParsedRelationTerm;
|
|
32
33
|
export type PatramParsedRelationTargetTerm =
|
|
33
|
-
import('./parse-where-clause.types.ts').ParsedRelationTargetTerm;
|
|
34
|
+
import('./graph/parse-where-clause.types.d.ts').ParsedRelationTargetTerm;
|
|
34
35
|
export type PatramParsedAggregateComparison =
|
|
35
|
-
import('./parse-where-clause.types.ts').ParsedAggregateComparison;
|
|
36
|
+
import('./graph/parse-where-clause.types.d.ts').ParsedAggregateComparison;
|
|
36
37
|
export type PatramParsedAggregateName =
|
|
37
|
-
import('./parse-where-clause.types.ts').ParsedAggregateName;
|
|
38
|
+
import('./graph/parse-where-clause.types.d.ts').ParsedAggregateName;
|
|
38
39
|
export type PatramParsedAggregateTerm =
|
|
39
|
-
import('./parse-where-clause.types.ts').ParsedAggregateTerm;
|
|
40
|
+
import('./graph/parse-where-clause.types.d.ts').ParsedAggregateTerm;
|
|
40
41
|
export type PatramParsedTermExpression =
|
|
41
|
-
import('./parse-where-clause.types.ts').ParsedTermExpression;
|
|
42
|
+
import('./graph/parse-where-clause.types.d.ts').ParsedTermExpression;
|
|
42
43
|
export type PatramParsedNotExpression =
|
|
43
|
-
import('./parse-where-clause.types.ts').ParsedNotExpression;
|
|
44
|
+
import('./graph/parse-where-clause.types.d.ts').ParsedNotExpression;
|
|
44
45
|
export type PatramParsedBooleanExpression =
|
|
45
|
-
import('./parse-where-clause.types.ts').ParsedBooleanExpression;
|
|
46
|
+
import('./graph/parse-where-clause.types.d.ts').ParsedBooleanExpression;
|
|
46
47
|
export type PatramParsedTerm =
|
|
47
|
-
import('./parse-where-clause.types.ts').ParsedTerm;
|
|
48
|
+
import('./graph/parse-where-clause.types.d.ts').ParsedTerm;
|
|
48
49
|
export type PatramParsedExpression =
|
|
49
|
-
import('./parse-where-clause.types.ts').ParsedExpression;
|
|
50
|
+
import('./graph/parse-where-clause.types.d.ts').ParsedExpression;
|
|
50
51
|
export type PatramParseWhereClauseResult =
|
|
51
|
-
import('./parse-where-clause.types.ts').ParseWhereClauseResult;
|
|
52
|
+
import('./graph/parse-where-clause.types.d.ts').ParseWhereClauseResult;
|
|
52
53
|
export type PatramQuerySource =
|
|
53
54
|
| {
|
|
54
55
|
kind: 'ad_hoc';
|
|
@@ -59,8 +60,8 @@ export type PatramQuerySource =
|
|
|
59
60
|
};
|
|
60
61
|
|
|
61
62
|
export interface PatramProjectGraphResult {
|
|
62
|
-
claims: import('./parse-claims.types.ts').PatramClaim[];
|
|
63
|
-
config: import('./load-patram-config.types.ts').PatramRepoConfig;
|
|
63
|
+
claims: import('./parse/parse-claims.types.d.ts').PatramClaim[];
|
|
64
|
+
config: import('./config/load-patram-config.types.d.ts').PatramRepoConfig;
|
|
64
65
|
diagnostics: PatramDiagnostic[];
|
|
65
66
|
graph: PatramBuildGraphResult;
|
|
66
67
|
source_file_paths: string[];
|
package/lib/patram.js
CHANGED
|
@@ -3,10 +3,9 @@ export {
|
|
|
3
3
|
loadTaggedFencedBlocks,
|
|
4
4
|
selectTaggedBlock,
|
|
5
5
|
selectTaggedBlocks,
|
|
6
|
-
} from './tagged-fenced-blocks.js';
|
|
6
|
+
} from './parse/tagged-fenced/tagged-fenced-blocks.js';
|
|
7
7
|
|
|
8
|
-
export { parseWhereClause } from './parse
|
|
9
|
-
export { getQuerySemanticDiagnostics } from './query
|
|
10
|
-
export { loadProjectGraph } from './load-project-graph.js';
|
|
11
|
-
export {
|
|
12
|
-
export { queryGraph } from './query-graph.js';
|
|
8
|
+
export { parseWhereClause } from './graph/query/parse.js';
|
|
9
|
+
export { getQuerySemanticDiagnostics } from './graph/query/inspect.js';
|
|
10
|
+
export { loadProjectGraph } from './graph/load-project-graph.js';
|
|
11
|
+
export { queryGraph } from './graph/query/execute.js';
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/* eslint-disable max-lines, max-lines-per-function */
|
|
2
2
|
/**
|
|
3
|
-
* @import { ClaimOrigin, PatramClaim } from '
|
|
3
|
+
* @import { ClaimOrigin, PatramClaim } from '../parse/parse-claims.types.ts';
|
|
4
4
|
* @import {
|
|
5
5
|
* DiscoveredFieldMultiplicity,
|
|
6
6
|
* DiscoveredFieldTypeName,
|
|
@@ -17,9 +17,14 @@ import { readFile } from 'node:fs/promises';
|
|
|
17
17
|
import process from 'node:process';
|
|
18
18
|
import { resolve } from 'node:path';
|
|
19
19
|
|
|
20
|
-
import { DEFAULT_INCLUDE_PATTERNS } from '
|
|
20
|
+
import { DEFAULT_INCLUDE_PATTERNS } from '../config/source-file-defaults.js';
|
|
21
21
|
import { listSourceFiles } from './list-source-files.js';
|
|
22
|
-
import { parseSourceFile } from '
|
|
22
|
+
import { parseSourceFile } from '../parse/parse-claims.js';
|
|
23
|
+
import {
|
|
24
|
+
matchHiddenDirectiveFields,
|
|
25
|
+
matchVisibleDirectiveFields,
|
|
26
|
+
} from '../parse/markdown/parse-markdown-directives.js';
|
|
27
|
+
import { isPathLikeTarget } from '../parse/claim-helpers.js';
|
|
23
28
|
|
|
24
29
|
/**
|
|
25
30
|
* Field discovery from source claims.
|
|
@@ -29,10 +34,10 @@ import { parseSourceFile } from './parse-claims.js';
|
|
|
29
34
|
*
|
|
30
35
|
* Kind: discovery
|
|
31
36
|
* Status: active
|
|
32
|
-
* Tracked in:
|
|
33
|
-
* Decided by:
|
|
37
|
+
* Tracked in: ../../docs/plans/v1/field-model-redesign.md
|
|
38
|
+
* Decided by: ../../docs/decisions/field-discovery-workflow.md
|
|
34
39
|
* @patram
|
|
35
|
-
* @see {@link
|
|
40
|
+
* @see {@link ../output/render-field-discovery.js}
|
|
36
41
|
*/
|
|
37
42
|
|
|
38
43
|
const TYPE_NAME_ORDER = /** @type {const} */ ([
|
|
@@ -71,10 +76,9 @@ export async function discoverFields(
|
|
|
71
76
|
options,
|
|
72
77
|
) {
|
|
73
78
|
const defined_field_names = options?.defined_field_names ?? new Set();
|
|
74
|
-
const source_file_paths =
|
|
75
|
-
DEFAULT_INCLUDE_PATTERNS,
|
|
76
|
-
|
|
77
|
-
);
|
|
79
|
+
const source_file_paths = (
|
|
80
|
+
await listSourceFiles(DEFAULT_INCLUDE_PATTERNS, project_directory)
|
|
81
|
+
).filter((source_file_path) => source_file_path.includes('/'));
|
|
78
82
|
const parse_results = await Promise.all(
|
|
79
83
|
source_file_paths.map(async (source_file_path) => {
|
|
80
84
|
const source_text = await readFile(
|
|
@@ -88,6 +92,7 @@ export async function discoverFields(
|
|
|
88
92
|
source: source_text,
|
|
89
93
|
}).claims,
|
|
90
94
|
path: source_file_path,
|
|
95
|
+
source_text,
|
|
91
96
|
};
|
|
92
97
|
}),
|
|
93
98
|
);
|
|
@@ -107,13 +112,20 @@ export async function discoverFields(
|
|
|
107
112
|
}
|
|
108
113
|
}
|
|
109
114
|
|
|
115
|
+
const allowed_markdown_lines = collectAllowedMarkdownDirectiveLines(
|
|
116
|
+
parse_result.path,
|
|
117
|
+
parse_result.source_text,
|
|
118
|
+
parse_result.claims,
|
|
119
|
+
);
|
|
120
|
+
|
|
110
121
|
return parse_result.claims.flatMap((claim) => {
|
|
111
122
|
if (
|
|
112
123
|
claim.type !== 'directive' ||
|
|
113
124
|
!claim.name ||
|
|
114
125
|
claim.name.startsWith('$') ||
|
|
115
126
|
typeof claim.value !== 'string' ||
|
|
116
|
-
claim.value.length === 0
|
|
127
|
+
claim.value.length === 0 ||
|
|
128
|
+
!shouldIncludeDiscoveryClaim(claim, allowed_markdown_lines)
|
|
117
129
|
) {
|
|
118
130
|
return [];
|
|
119
131
|
}
|
|
@@ -123,6 +135,7 @@ export async function discoverFields(
|
|
|
123
135
|
class_names: new Set(document_classes),
|
|
124
136
|
document_id: claim.document_id,
|
|
125
137
|
name: claim.name,
|
|
138
|
+
normalized_value: normalizeDiscoveryValue(claim.value),
|
|
126
139
|
origin: claim.origin,
|
|
127
140
|
value: claim.value,
|
|
128
141
|
},
|
|
@@ -132,6 +145,7 @@ export async function discoverFields(
|
|
|
132
145
|
/** @type {Map<string, FieldBucket>} */
|
|
133
146
|
const field_buckets = field_observations.reduce(
|
|
134
147
|
(buckets, field_observation) => {
|
|
148
|
+
/** @type {FieldBucket} */
|
|
135
149
|
const bucket = buckets.get(field_observation.name) ?? {
|
|
136
150
|
name: field_observation.name,
|
|
137
151
|
observations: [],
|
|
@@ -141,12 +155,14 @@ export async function discoverFields(
|
|
|
141
155
|
buckets.set(field_observation.name, bucket);
|
|
142
156
|
return buckets;
|
|
143
157
|
},
|
|
144
|
-
new Map(),
|
|
158
|
+
/** @type {Map<string, FieldBucket>} */ (new Map()),
|
|
145
159
|
);
|
|
146
160
|
const fields = [...field_buckets.values()]
|
|
147
161
|
.map(buildFieldSuggestion)
|
|
148
162
|
.filter(
|
|
149
|
-
(field_suggestion) =>
|
|
163
|
+
(field_suggestion) =>
|
|
164
|
+
!defined_field_names.has(field_suggestion.name) &&
|
|
165
|
+
isPlausibleFieldName(field_suggestion.name),
|
|
150
166
|
)
|
|
151
167
|
.sort((left_suggestion, right_suggestion) =>
|
|
152
168
|
left_suggestion.confidence !== right_suggestion.confidence
|
|
@@ -181,7 +197,10 @@ function buildFieldSuggestion(field_bucket) {
|
|
|
181
197
|
const conflicting_evidence = buildEvidenceReferences(
|
|
182
198
|
field_bucket.observations.filter(
|
|
183
199
|
(field_observation) =>
|
|
184
|
-
scoreFieldValue(
|
|
200
|
+
scoreFieldValue(
|
|
201
|
+
field_observation.normalized_value,
|
|
202
|
+
type_result.name,
|
|
203
|
+
) === 0,
|
|
185
204
|
),
|
|
186
205
|
);
|
|
187
206
|
|
|
@@ -227,16 +246,17 @@ function buildEvidenceReferences(observations) {
|
|
|
227
246
|
function inferFieldMultiplicity(observations) {
|
|
228
247
|
/** @type {Map<string, Set<string>>} */
|
|
229
248
|
const values_by_document = observations.reduce((values, observation) => {
|
|
249
|
+
const normalized_value = observation.normalized_value;
|
|
230
250
|
const current_values = values.get(observation.document_id);
|
|
231
251
|
|
|
232
252
|
if (current_values) {
|
|
233
|
-
current_values.add(
|
|
253
|
+
current_values.add(normalized_value);
|
|
234
254
|
} else {
|
|
235
|
-
values.set(observation.document_id, new Set([
|
|
255
|
+
values.set(observation.document_id, new Set([normalized_value]));
|
|
236
256
|
}
|
|
237
257
|
|
|
238
258
|
return values;
|
|
239
|
-
}, new Map());
|
|
259
|
+
}, /** @type {Map<string, Set<string>>} */ (new Map()));
|
|
240
260
|
const repeated_identical_documents = [...values_by_document.values()].reduce(
|
|
241
261
|
(count, values) => {
|
|
242
262
|
if (values.size > 1) {
|
|
@@ -368,7 +388,7 @@ function scoreFieldType(observations, field_type_name) {
|
|
|
368
388
|
|
|
369
389
|
const total_score = observations.reduce(
|
|
370
390
|
(sum, observation) =>
|
|
371
|
-
sum + scoreFieldValue(observation.
|
|
391
|
+
sum + scoreFieldValue(observation.normalized_value, field_type_name),
|
|
372
392
|
0,
|
|
373
393
|
);
|
|
374
394
|
|
|
@@ -422,6 +442,7 @@ const FIELD_TYPE_SCORERS = {
|
|
|
422
442
|
* class_names: Set<string>,
|
|
423
443
|
* document_id: string,
|
|
424
444
|
* name: string,
|
|
445
|
+
* normalized_value: string,
|
|
425
446
|
* origin: ClaimOrigin,
|
|
426
447
|
* value: string,
|
|
427
448
|
* }} FieldObservation
|
|
@@ -433,3 +454,109 @@ const FIELD_TYPE_SCORERS = {
|
|
|
433
454
|
* observations: FieldObservation[],
|
|
434
455
|
* }} FieldBucket
|
|
435
456
|
*/
|
|
457
|
+
|
|
458
|
+
/**
|
|
459
|
+
* @param {PatramClaim} claim
|
|
460
|
+
* @param {Set<number> | null} allowed_markdown_lines
|
|
461
|
+
* @returns {boolean}
|
|
462
|
+
*/
|
|
463
|
+
function shouldIncludeDiscoveryClaim(claim, allowed_markdown_lines) {
|
|
464
|
+
if (claim.parser !== 'markdown') {
|
|
465
|
+
return true;
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
if (claim.markdown_style === 'front_matter') {
|
|
469
|
+
return true;
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
return allowed_markdown_lines?.has(claim.origin.line) ?? false;
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
/**
|
|
476
|
+
* @param {string} file_path
|
|
477
|
+
* @param {string} source_text
|
|
478
|
+
* @param {PatramClaim[]} claims
|
|
479
|
+
* @returns {Set<number> | null}
|
|
480
|
+
*/
|
|
481
|
+
function collectAllowedMarkdownDirectiveLines(file_path, source_text, claims) {
|
|
482
|
+
if (!file_path.endsWith('.md')) {
|
|
483
|
+
return null;
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
const title_claim = claims.find((claim) => claim.type === 'document.title');
|
|
487
|
+
|
|
488
|
+
if (!title_claim) {
|
|
489
|
+
return new Set();
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
const lines = source_text.split('\n');
|
|
493
|
+
/** @type {Set<number>} */
|
|
494
|
+
const allowed_lines = new Set();
|
|
495
|
+
|
|
496
|
+
for (
|
|
497
|
+
let line_index = title_claim.origin.line;
|
|
498
|
+
line_index < lines.length;
|
|
499
|
+
line_index += 1
|
|
500
|
+
) {
|
|
501
|
+
const line = lines[line_index];
|
|
502
|
+
|
|
503
|
+
if (line.trim().length === 0) {
|
|
504
|
+
continue;
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
if (isMarkdownDiscoveryDirective(file_path, line, line_index + 1)) {
|
|
508
|
+
allowed_lines.add(line_index + 1);
|
|
509
|
+
continue;
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
break;
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
return allowed_lines;
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
/**
|
|
519
|
+
* @param {string} file_path
|
|
520
|
+
* @param {string} line
|
|
521
|
+
* @param {number} line_number
|
|
522
|
+
* @returns {boolean}
|
|
523
|
+
*/
|
|
524
|
+
function isMarkdownDiscoveryDirective(file_path, line, line_number) {
|
|
525
|
+
return (
|
|
526
|
+
matchVisibleDirectiveFields(file_path, line, line_number) !== null ||
|
|
527
|
+
matchHiddenDirectiveFields(file_path, line, line_number) !== null
|
|
528
|
+
);
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
/**
|
|
532
|
+
* @param {string} value
|
|
533
|
+
* @returns {string}
|
|
534
|
+
*/
|
|
535
|
+
function normalizeDiscoveryValue(value) {
|
|
536
|
+
const trimmed_value = value.trim();
|
|
537
|
+
const markdown_link_match = trimmed_value.match(
|
|
538
|
+
/^\[([^\]]+)\]\(([^)]+)\)$/du,
|
|
539
|
+
);
|
|
540
|
+
|
|
541
|
+
if (markdown_link_match && isPathLikeTarget(markdown_link_match[2])) {
|
|
542
|
+
return markdown_link_match[2];
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
const code_span_match = trimmed_value.match(/^`([^`]+)`[.,;:]?$/du);
|
|
546
|
+
|
|
547
|
+
if (code_span_match) {
|
|
548
|
+
return code_span_match[1];
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
return trimmed_value;
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
/**
|
|
555
|
+
* @param {string} field_name
|
|
556
|
+
* @returns {boolean}
|
|
557
|
+
*/
|
|
558
|
+
function isPlausibleFieldName(field_name) {
|
|
559
|
+
const field_name_tokens = field_name.split('_');
|
|
560
|
+
|
|
561
|
+
return field_name.length <= 32 && field_name_tokens.length <= 4;
|
|
562
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* List repo files available for broken-link validation.
|
|
3
|
+
*
|
|
4
|
+
* @param {string} [project_directory]
|
|
5
|
+
* @returns {Promise<string[]>}
|
|
6
|
+
*/
|
|
7
|
+
export function listRepoFiles(project_directory?: string): Promise<string[]>;
|
|
8
|
+
/**
|
|
9
|
+
* @param {string[]} include_patterns
|
|
10
|
+
* @param {string} project_directory
|
|
11
|
+
* @param {{ dot?: boolean }} [options]
|
|
12
|
+
* @returns {Promise<string[]>}
|
|
13
|
+
*/
|
|
14
|
+
export function listMatchingFiles(include_patterns: string[], project_directory: string, options?: {
|
|
15
|
+
dot?: boolean;
|
|
16
|
+
}): Promise<string[]>;
|
|
@@ -1,39 +1,6 @@
|
|
|
1
|
-
import { globby } from 'globby';
|
|
2
1
|
import process from 'node:process';
|
|
3
2
|
|
|
4
|
-
|
|
5
|
-
* Source file scanning.
|
|
6
|
-
*
|
|
7
|
-
* Expands include globs into stable repo-relative file lists for indexing and
|
|
8
|
-
* broken-link validation.
|
|
9
|
-
*
|
|
10
|
-
* Kind: scan
|
|
11
|
-
* Status: active
|
|
12
|
-
* Tracked in: ../docs/plans/v0/source-anchor-dogfooding.md
|
|
13
|
-
* Decided by: ../docs/decisions/source-scan.md
|
|
14
|
-
* @patram
|
|
15
|
-
* @see {@link ./load-project-graph.js}
|
|
16
|
-
* @see {@link ../docs/decisions/source-scan.md}
|
|
17
|
-
*/
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* List source files matched by Patram include globs.
|
|
21
|
-
*
|
|
22
|
-
* @param {string[]} include_patterns
|
|
23
|
-
* @param {string} [project_directory]
|
|
24
|
-
* @returns {Promise<string[]>}
|
|
25
|
-
*/
|
|
26
|
-
export async function listSourceFiles(
|
|
27
|
-
include_patterns,
|
|
28
|
-
project_directory = process.cwd(),
|
|
29
|
-
) {
|
|
30
|
-
const source_file_paths = await listMatchingFiles(
|
|
31
|
-
include_patterns,
|
|
32
|
-
project_directory,
|
|
33
|
-
);
|
|
34
|
-
|
|
35
|
-
return [...new Set(source_file_paths)].sort(comparePaths);
|
|
36
|
-
}
|
|
3
|
+
import { globby } from 'globby';
|
|
37
4
|
|
|
38
5
|
/**
|
|
39
6
|
* List repo files available for broken-link validation.
|
|
@@ -55,7 +22,7 @@ export async function listRepoFiles(project_directory = process.cwd()) {
|
|
|
55
22
|
* @param {{ dot?: boolean }} [options]
|
|
56
23
|
* @returns {Promise<string[]>}
|
|
57
24
|
*/
|
|
58
|
-
async function listMatchingFiles(
|
|
25
|
+
export async function listMatchingFiles(
|
|
59
26
|
include_patterns,
|
|
60
27
|
project_directory,
|
|
61
28
|
options = {},
|
|
@@ -6,11 +6,11 @@
|
|
|
6
6
|
*
|
|
7
7
|
* Kind: scan
|
|
8
8
|
* Status: active
|
|
9
|
-
* Tracked in:
|
|
10
|
-
* Decided by:
|
|
9
|
+
* Tracked in: ../../docs/plans/v0/source-anchor-dogfooding.md
|
|
10
|
+
* Decided by: ../../docs/decisions/source-scan.md
|
|
11
11
|
* @patram
|
|
12
|
-
* @see {@link
|
|
13
|
-
* @see {@link
|
|
12
|
+
* @see {@link ../graph/load-project-graph.js}
|
|
13
|
+
* @see {@link ../../docs/decisions/source-scan.md}
|
|
14
14
|
*/
|
|
15
15
|
/**
|
|
16
16
|
* List source files matched by Patram include globs.
|
|
@@ -20,10 +20,3 @@
|
|
|
20
20
|
* @returns {Promise<string[]>}
|
|
21
21
|
*/
|
|
22
22
|
export function listSourceFiles(include_patterns: string[], project_directory?: string): Promise<string[]>;
|
|
23
|
-
/**
|
|
24
|
-
* List repo files available for broken-link validation.
|
|
25
|
-
*
|
|
26
|
-
* @param {string} [project_directory]
|
|
27
|
-
* @returns {Promise<string[]>}
|
|
28
|
-
*/
|
|
29
|
-
export function listRepoFiles(project_directory?: string): Promise<string[]>;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import process from 'node:process';
|
|
2
|
+
|
|
3
|
+
import { listMatchingFiles } from './list-repo-files.js';
|
|
4
|
+
/**
|
|
5
|
+
* Source file scanning.
|
|
6
|
+
*
|
|
7
|
+
* Expands include globs into stable repo-relative file lists for indexing and
|
|
8
|
+
* broken-link validation.
|
|
9
|
+
*
|
|
10
|
+
* Kind: scan
|
|
11
|
+
* Status: active
|
|
12
|
+
* Tracked in: ../../docs/plans/v0/source-anchor-dogfooding.md
|
|
13
|
+
* Decided by: ../../docs/decisions/source-scan.md
|
|
14
|
+
* @patram
|
|
15
|
+
* @see {@link ../graph/load-project-graph.js}
|
|
16
|
+
* @see {@link ../../docs/decisions/source-scan.md}
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* List source files matched by Patram include globs.
|
|
21
|
+
*
|
|
22
|
+
* @param {string[]} include_patterns
|
|
23
|
+
* @param {string} [project_directory]
|
|
24
|
+
* @returns {Promise<string[]>}
|
|
25
|
+
*/
|
|
26
|
+
export async function listSourceFiles(
|
|
27
|
+
include_patterns,
|
|
28
|
+
project_directory = process.cwd(),
|
|
29
|
+
) {
|
|
30
|
+
const source_file_paths = await listMatchingFiles(
|
|
31
|
+
include_patterns,
|
|
32
|
+
project_directory,
|
|
33
|
+
);
|
|
34
|
+
|
|
35
|
+
return [...new Set(source_file_paths)].sort(comparePaths);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* @param {string} left_path
|
|
40
|
+
* @param {string} right_path
|
|
41
|
+
* @returns {number}
|
|
42
|
+
*/
|
|
43
|
+
function comparePaths(left_path, right_path) {
|
|
44
|
+
return left_path.localeCompare(right_path, 'en');
|
|
45
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "patram",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.10.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./lib/patram.js",
|
|
6
6
|
"types": "./lib/patram.d.ts",
|
|
@@ -15,7 +15,6 @@
|
|
|
15
15
|
"bin/patram.js",
|
|
16
16
|
"lib/**/*.d.ts",
|
|
17
17
|
"lib/**/*.js",
|
|
18
|
-
"lib/**/*.ts",
|
|
19
18
|
"!bin/**/*.test.d.ts",
|
|
20
19
|
"!bin/**/*.test-helpers.d.ts",
|
|
21
20
|
"!bin/**/*.test.js",
|
|
@@ -38,9 +37,11 @@
|
|
|
38
37
|
},
|
|
39
38
|
"license": "MIT",
|
|
40
39
|
"scripts": {
|
|
41
|
-
"all": "npm run check:lint && npm run check:format && npm run check:types && npm run check:patram && npm run test:coverage && npm run check:dupes",
|
|
40
|
+
"all": "npm run check:lint && npm run check:format && npm run check:types && npm run check:patram && npm run check:knip && npm run check:knip:production && npm run test:coverage && npm run check:dupes",
|
|
42
41
|
"check:dupes": "jscpd --min-tokens 100 --min-lines 6 --mode mild --threshold 0 --reporters console --gitignore .",
|
|
43
42
|
"check:format": "prettier --check .",
|
|
43
|
+
"check:knip": "knip",
|
|
44
|
+
"check:knip:production": "knip --production --include exports",
|
|
44
45
|
"check:lint": "eslint .",
|
|
45
46
|
"check:patram": "./bin/patram.js check",
|
|
46
47
|
"check:staged": "lint-staged",
|
|
@@ -62,7 +63,6 @@
|
|
|
62
63
|
]
|
|
63
64
|
},
|
|
64
65
|
"dependencies": {
|
|
65
|
-
"@shikijs/cli": "^4.0.2",
|
|
66
66
|
"@shikijs/vscode-textmate": "^10.0.2",
|
|
67
67
|
"ansis": "^4.2.0",
|
|
68
68
|
"beautiful-mermaid": "^1.1.3",
|
|
@@ -77,16 +77,17 @@
|
|
|
77
77
|
"devDependencies": {
|
|
78
78
|
"@eslint/js": "^10.0.1",
|
|
79
79
|
"@types/node": "^24.12.0",
|
|
80
|
-
"@vitest/coverage-
|
|
80
|
+
"@vitest/coverage-istanbul": "^4.1.2",
|
|
81
81
|
"eslint": "^10.1.0",
|
|
82
82
|
"eslint-plugin-jsdoc": "^62.8.0",
|
|
83
83
|
"globals": "^17.4.0",
|
|
84
84
|
"husky": "^9.1.7",
|
|
85
85
|
"jscpd": "^4.0.8",
|
|
86
|
+
"knip": "^6.1.0",
|
|
86
87
|
"lint-staged": "^16.2.6",
|
|
87
88
|
"prettier": "^3.5.3",
|
|
88
|
-
"
|
|
89
|
-
"typescript": "^
|
|
89
|
+
"typescript": "^5.9.3",
|
|
90
|
+
"typescript-eslint": "^8.57.2",
|
|
90
91
|
"vitest": "^4.1.1"
|
|
91
92
|
}
|
|
92
93
|
}
|
package/lib/build-graph.types.ts
DELETED
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
import type { ClaimOrigin } from './parse-claims.types.ts';
|
|
2
|
-
|
|
3
|
-
export interface GraphNode {
|
|
4
|
-
$class?: string;
|
|
5
|
-
$id?: string;
|
|
6
|
-
$path?: string;
|
|
7
|
-
id: string;
|
|
8
|
-
kind?: string;
|
|
9
|
-
key?: string;
|
|
10
|
-
path?: string;
|
|
11
|
-
title?: string;
|
|
12
|
-
[field: string]: string | string[] | undefined;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
export interface GraphEdge {
|
|
16
|
-
from: string;
|
|
17
|
-
id: string;
|
|
18
|
-
origin: ClaimOrigin;
|
|
19
|
-
relation: string;
|
|
20
|
-
to: string;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
export interface BuildGraphResult {
|
|
24
|
-
document_node_ids?: Record<string, string>;
|
|
25
|
-
edges: GraphEdge[];
|
|
26
|
-
nodes: Record<string, GraphNode>;
|
|
27
|
-
}
|
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
export type DiscoveredFieldTypeName =
|
|
2
|
-
| 'date'
|
|
3
|
-
| 'date_time'
|
|
4
|
-
| 'enum'
|
|
5
|
-
| 'glob'
|
|
6
|
-
| 'integer'
|
|
7
|
-
| 'path'
|
|
8
|
-
| 'string';
|
|
9
|
-
|
|
10
|
-
export type DiscoveredFieldMultiplicity = 'multiple' | 'single';
|
|
11
|
-
|
|
12
|
-
export interface FieldDiscoveryEvidenceReference {
|
|
13
|
-
column: number;
|
|
14
|
-
line: number;
|
|
15
|
-
path: string;
|
|
16
|
-
value: string;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
export interface FieldDiscoveryClassUsage {
|
|
20
|
-
classes: string[];
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
export interface FieldDiscoveryTypeSuggestion {
|
|
24
|
-
confidence: number;
|
|
25
|
-
name: DiscoveredFieldTypeName;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
export interface FieldDiscoveryMultiplicitySuggestion {
|
|
29
|
-
confidence: number;
|
|
30
|
-
name: DiscoveredFieldMultiplicity;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
export interface FieldDiscoverySuggestion {
|
|
34
|
-
confidence: number;
|
|
35
|
-
conflicting_evidence: FieldDiscoveryEvidenceReference[];
|
|
36
|
-
evidence_references: FieldDiscoveryEvidenceReference[];
|
|
37
|
-
likely_class_usage: FieldDiscoveryClassUsage;
|
|
38
|
-
likely_multiplicity: FieldDiscoveryMultiplicitySuggestion;
|
|
39
|
-
likely_type: FieldDiscoveryTypeSuggestion;
|
|
40
|
-
name: string;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
export interface FieldDiscoverySummary {
|
|
44
|
-
claim_count: number;
|
|
45
|
-
count: number;
|
|
46
|
-
source_file_count: number;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
export interface FieldDiscoveryResult {
|
|
50
|
-
fields: FieldDiscoverySuggestion[];
|
|
51
|
-
summary: FieldDiscoverySummary;
|
|
52
|
-
}
|