@knapsack/source-conflicts-adapter 4.89.10--canary.7202.53e0d58.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/.eslintrc.cjs +9 -0
- package/README.md +269 -0
- package/dist/analyzer.d.ts +29 -0
- package/dist/analyzer.d.ts.map +1 -0
- package/dist/analyzer.js +61 -0
- package/dist/analyzer.js.map +1 -0
- package/dist/analyzer.vitest.d.ts +2 -0
- package/dist/analyzer.vitest.d.ts.map +1 -0
- package/dist/analyzer.vitest.js +60 -0
- package/dist/analyzer.vitest.js.map +1 -0
- package/dist/compare/preview.d.ts +28 -0
- package/dist/compare/preview.d.ts.map +1 -0
- package/dist/compare/preview.js +27 -0
- package/dist/compare/preview.js.map +1 -0
- package/dist/compare/preview.vitest.d.ts +2 -0
- package/dist/compare/preview.vitest.d.ts.map +1 -0
- package/dist/compare/preview.vitest.js +67 -0
- package/dist/compare/preview.vitest.js.map +1 -0
- package/dist/detect.d.ts +13 -0
- package/dist/detect.d.ts.map +1 -0
- package/dist/detect.js +104 -0
- package/dist/detect.js.map +1 -0
- package/dist/detect.vitest.d.ts +2 -0
- package/dist/detect.vitest.d.ts.map +1 -0
- package/dist/detect.vitest.js +116 -0
- package/dist/detect.vitest.js.map +1 -0
- package/dist/index.d.ts +26 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +26 -0
- package/dist/index.js.map +1 -0
- package/dist/mdx/mdxConflicts.d.ts +160 -0
- package/dist/mdx/mdxConflicts.d.ts.map +1 -0
- package/dist/mdx/mdxConflicts.js +393 -0
- package/dist/mdx/mdxConflicts.js.map +1 -0
- package/dist/mdx/mdxConflicts.vitest.d.ts +2 -0
- package/dist/mdx/mdxConflicts.vitest.d.ts.map +1 -0
- package/dist/mdx/mdxConflicts.vitest.js +101 -0
- package/dist/mdx/mdxConflicts.vitest.js.map +1 -0
- package/dist/mdx/mdxRules.d.ts +56 -0
- package/dist/mdx/mdxRules.d.ts.map +1 -0
- package/dist/mdx/mdxRules.js +386 -0
- package/dist/mdx/mdxRules.js.map +1 -0
- package/dist/mdx/mdxRules.vitest.d.ts +2 -0
- package/dist/mdx/mdxRules.vitest.d.ts.map +1 -0
- package/dist/mdx/mdxRules.vitest.js +36 -0
- package/dist/mdx/mdxRules.vitest.js.map +1 -0
- package/dist/mdx/sharedProcessor.d.ts +13 -0
- package/dist/mdx/sharedProcessor.d.ts.map +1 -0
- package/dist/mdx/sharedProcessor.js +48 -0
- package/dist/mdx/sharedProcessor.js.map +1 -0
- package/dist/mdx/tableMdx.d.ts +45 -0
- package/dist/mdx/tableMdx.d.ts.map +1 -0
- package/dist/mdx/tableMdx.js +114 -0
- package/dist/mdx/tableMdx.js.map +1 -0
- package/dist/mdx/tableMdx.vitest.d.ts +2 -0
- package/dist/mdx/tableMdx.vitest.d.ts.map +1 -0
- package/dist/mdx/tableMdx.vitest.js +99 -0
- package/dist/mdx/tableMdx.vitest.js.map +1 -0
- package/dist/multiSourceCompare.d.ts +40 -0
- package/dist/multiSourceCompare.d.ts.map +1 -0
- package/dist/multiSourceCompare.js +286 -0
- package/dist/multiSourceCompare.js.map +1 -0
- package/dist/multiSourceCompare.vitest.d.ts +2 -0
- package/dist/multiSourceCompare.vitest.d.ts.map +1 -0
- package/dist/multiSourceCompare.vitest.js +46 -0
- package/dist/multiSourceCompare.vitest.js.map +1 -0
- package/dist/parse.d.ts +6 -0
- package/dist/parse.d.ts.map +1 -0
- package/dist/parse.js +21 -0
- package/dist/parse.js.map +1 -0
- package/dist/parse.vitest.d.ts +2 -0
- package/dist/parse.vitest.d.ts.map +1 -0
- package/dist/parse.vitest.js +34 -0
- package/dist/parse.vitest.js.map +1 -0
- package/dist/parser.d.ts +4 -0
- package/dist/parser.d.ts.map +1 -0
- package/dist/parser.js +61 -0
- package/dist/parser.js.map +1 -0
- package/dist/transformer.d.ts +4 -0
- package/dist/transformer.d.ts.map +1 -0
- package/dist/transformer.js +112 -0
- package/dist/transformer.js.map +1 -0
- package/dist/types.d.ts +57 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +13 -0
- package/dist/types.js.map +1 -0
- package/dist/utils/canonicalCache.d.ts +7 -0
- package/dist/utils/canonicalCache.d.ts.map +1 -0
- package/dist/utils/canonicalCache.js +18 -0
- package/dist/utils/canonicalCache.js.map +1 -0
- package/dist/utils/canonicalCache.vitest.d.ts +2 -0
- package/dist/utils/canonicalCache.vitest.d.ts.map +1 -0
- package/dist/utils/canonicalCache.vitest.js +40 -0
- package/dist/utils/canonicalCache.vitest.js.map +1 -0
- package/dist/utils/frontmatter.d.ts +13 -0
- package/dist/utils/frontmatter.d.ts.map +1 -0
- package/dist/utils/frontmatter.js +14 -0
- package/dist/utils/frontmatter.js.map +1 -0
- package/dist/utils/frontmatter.vitest.d.ts +2 -0
- package/dist/utils/frontmatter.vitest.d.ts.map +1 -0
- package/dist/utils/frontmatter.vitest.js +34 -0
- package/dist/utils/frontmatter.vitest.js.map +1 -0
- package/dist/validator.d.ts +7 -0
- package/dist/validator.d.ts.map +1 -0
- package/dist/validator.js +30 -0
- package/dist/validator.js.map +1 -0
- package/package.json +60 -0
- package/tsconfig.json +9 -0
- package/vitest.config.mjs +9 -0
package/.eslintrc.cjs
ADDED
package/README.md
ADDED
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
# @knapsack/source-conflicts-adapter
|
|
2
|
+
|
|
3
|
+
Detects and compares entity documentation conflicts across multiple ingestion sources (e.g. Storybook, Knapsack, Figma). Implemented as a `ContextSrcAdapter` so it integrates with the ingest pipeline and can also be used standalone via its `analyzer` interface.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Overview
|
|
8
|
+
|
|
9
|
+
When the same entity (e.g. `button.react.mdx`) is contributed by more than one source, the sections within each file may diverge. This adapter:
|
|
10
|
+
|
|
11
|
+
1. **Indexes** the entities directory to find files contributed by multiple sources
|
|
12
|
+
2. **Groups** files that map to the same canonical entity path
|
|
13
|
+
3. **Detects** conflicts by parsing each MDX/MD file into anchored sections, then comparing section content across sources with a chain of canonicalization rules
|
|
14
|
+
4. **Reports** per-anchor verdicts: `ALL_SAME`, `DIFFERENT`, or `MISSING`
|
|
15
|
+
|
|
16
|
+
### Entity file layout
|
|
17
|
+
|
|
18
|
+
```
|
|
19
|
+
entities/
|
|
20
|
+
└── <entityKind>/ # e.g. "components", "tokens"
|
|
21
|
+
├── button.react.KNAPSACK-abc123.mdx
|
|
22
|
+
├── button.react.STORYBOOK-def456.mdx
|
|
23
|
+
└── card.react.KNAPSACK-111aaa.mdx
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Files with the same base name and extension (e.g. `button.react.mdx`) but different `<SOURCE>-<hash>` segments are candidates for conflict detection.
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
## Installation
|
|
31
|
+
|
|
32
|
+
This package lives in the monorepo at `libs/ingest-pipeline/adapters/source-conflicts/` and is consumed as a workspace dependency:
|
|
33
|
+
|
|
34
|
+
```json
|
|
35
|
+
"@knapsack/source-conflicts-adapter": "workspace:*"
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
## Quick start — standalone analyzer
|
|
41
|
+
|
|
42
|
+
The fastest way to detect conflicts without running the full pipeline is via the `analyzer` interface:
|
|
43
|
+
|
|
44
|
+
```typescript
|
|
45
|
+
import * as fs from 'node:fs/promises';
|
|
46
|
+
import * as path from 'node:path';
|
|
47
|
+
import { analyze } from '@knapsack/source-conflicts-adapter';
|
|
48
|
+
import { createLogger } from '@knapsack/utils';
|
|
49
|
+
|
|
50
|
+
const entitiesRootAbs = '/absolute/path/to/entities';
|
|
51
|
+
const outputFile = path.join(entitiesRootAbs, 'source-conflicts-result.json');
|
|
52
|
+
const logger = createLogger('source-conflicts');
|
|
53
|
+
|
|
54
|
+
const result = await analyze({ entitiesRootAbs }, { logger });
|
|
55
|
+
|
|
56
|
+
await fs.writeFile(outputFile, JSON.stringify(result, null, 2), 'utf8');
|
|
57
|
+
console.log(`Wrote results to ${outputFile}`);
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
The output file contains the full `SourceConflictsAnalysisResult` as JSON — `groupResults` with per-anchor verdicts and previews, plus `skippedGroupKeys` for any groups that were excluded.
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
|
|
64
|
+
## Configuration
|
|
65
|
+
|
|
66
|
+
```typescript
|
|
67
|
+
import type { SourceConflictsConfig } from '@knapsack/source-conflicts-adapter';
|
|
68
|
+
|
|
69
|
+
const config: SourceConflictsConfig = {
|
|
70
|
+
/** Required: absolute path to the directory containing <entityKind>/ subdirectories. */
|
|
71
|
+
entitiesRootAbs: '/path/to/entities',
|
|
72
|
+
|
|
73
|
+
/** Optional: scope identifiers forwarded to fingerprint computation and logging. */
|
|
74
|
+
siteId: 'my-site',
|
|
75
|
+
userId: 'user-123',
|
|
76
|
+
configId: 'config-abc',
|
|
77
|
+
};
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
---
|
|
81
|
+
|
|
82
|
+
## Pipeline usage
|
|
83
|
+
|
|
84
|
+
The adapter implements the full `ContextSrcAdapter<SourceConflictsConfig, SourceConflictsAnalysisResult>` interface:
|
|
85
|
+
|
|
86
|
+
```typescript
|
|
87
|
+
import { sourceConflictsAdapter } from '@knapsack/source-conflicts-adapter';
|
|
88
|
+
import type { SourceConflictsConfig } from '@knapsack/source-conflicts-adapter';
|
|
89
|
+
import type { RuntimeDeps } from '@knapsack/adapter-core';
|
|
90
|
+
|
|
91
|
+
// Validate config before running
|
|
92
|
+
const configError = sourceConflictsAdapter.validator.validateConfig(config);
|
|
93
|
+
if (configError) throw new Error(configError);
|
|
94
|
+
|
|
95
|
+
// Parse stage: indexes entities + writes manifest
|
|
96
|
+
await sourceConflictsAdapter.parser.parse(config, parseDeps);
|
|
97
|
+
|
|
98
|
+
// Transform stage: runs conflict detection + writes verdict bundles
|
|
99
|
+
await sourceConflictsAdapter.transformer.transform(config, transformDeps);
|
|
100
|
+
|
|
101
|
+
// Analyze stage: in-process, returns typed results (no file writing)
|
|
102
|
+
const result = await sourceConflictsAdapter.analyzer!.analyze(config, {
|
|
103
|
+
logger,
|
|
104
|
+
});
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
---
|
|
108
|
+
|
|
109
|
+
## Result shape
|
|
110
|
+
|
|
111
|
+
### `SourceConflictsAnalysisResult`
|
|
112
|
+
|
|
113
|
+
```typescript
|
|
114
|
+
type SourceConflictsAnalysisResult = {
|
|
115
|
+
/** One entry per processed conflict group. */
|
|
116
|
+
groupResults: ConflictGroupResult[];
|
|
117
|
+
/** Keys of groups that were skipped (non-MDX/MD or too few sources). */
|
|
118
|
+
skippedGroupKeys: string[];
|
|
119
|
+
};
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
### `ConflictGroupResult`
|
|
123
|
+
|
|
124
|
+
```typescript
|
|
125
|
+
type ConflictGroupResult = {
|
|
126
|
+
group: ConflictGroup; // entityKind, relPath, artifacts[]
|
|
127
|
+
bundle: MdxConflictBundle; // source-agnostic per-anchor snapshot (serializable — store in DB)
|
|
128
|
+
baselineSourceKey: string; // frontmatter URI of the baseline source, e.g. "knapsack://patterns/button"
|
|
129
|
+
compareSourceKeys: string[]; // frontmatter URIs of compare sources (up to MAX_COMPARE_SOURCES)
|
|
130
|
+
verdicts: AnchorVerdictView[]; // per-anchor verdict derived from bundle for this baseline/compare
|
|
131
|
+
};
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
`bundle` is a fully-serializable JSON snapshot — no functions, no circular refs. Storing it once and calling `computeVerdictsForBaselineCompare` with different baseline/compare args is the recommended pattern (see [Option A](#option-a--bundle-first-pattern)).
|
|
135
|
+
|
|
136
|
+
### `ConflictItemRecord` (inside `MdxConflictBundle.items`)
|
|
137
|
+
|
|
138
|
+
```typescript
|
|
139
|
+
type ConflictItemRecord = {
|
|
140
|
+
fingerprint: string;
|
|
141
|
+
sourceType: SourceType; // filename-parsed, e.g. "KNAPSACK" — used internally for matching
|
|
142
|
+
sourceKey: string; // frontmatter URI, e.g. "knapsack://patterns/button" — use this for display and storage
|
|
143
|
+
frontmatterSchemaVersion: number;
|
|
144
|
+
frontmatter: Record<string, unknown>;
|
|
145
|
+
};
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
### Verdicts
|
|
149
|
+
|
|
150
|
+
| Value | Meaning |
|
|
151
|
+
| ----------- | --------------------------------------------------------------------- |
|
|
152
|
+
| `ALL_SAME` | All sources agree (or content was unified by a canonicalization rule) |
|
|
153
|
+
| `DIFFERENT` | At least one source has different content for this anchor |
|
|
154
|
+
| `MISSING` | At least one source does not contain this anchor |
|
|
155
|
+
|
|
156
|
+
---
|
|
157
|
+
|
|
158
|
+
## Option A — bundle-first pattern
|
|
159
|
+
|
|
160
|
+
`MdxConflictBundle` is the stable stored artifact. `computeVerdictsForBaselineCompare` is a pure function that derives verdicts from any stored bundle with no I/O or re-parsing.
|
|
161
|
+
|
|
162
|
+
### Recommended DB/GraphQL pattern
|
|
163
|
+
|
|
164
|
+
1. **Store** the bundle when running the detection pipeline.
|
|
165
|
+
2. **Load** the bundle from storage when serving a request.
|
|
166
|
+
3. **Call** `computeVerdictsForBaselineCompare` with the caller-specified baseline/compare source URIs.
|
|
167
|
+
|
|
168
|
+
```typescript
|
|
169
|
+
import {
|
|
170
|
+
computeVerdictsForBaselineCompare,
|
|
171
|
+
getAvailableSourceKeysFromBundle,
|
|
172
|
+
} from '@knapsack/source-conflicts-adapter';
|
|
173
|
+
import type { MdxConflictBundle } from '@knapsack/source-conflicts-adapter';
|
|
174
|
+
|
|
175
|
+
// Load stored bundle from DB (JSON column → parse → use directly, no re-detection)
|
|
176
|
+
const bundle: MdxConflictBundle = JSON.parse(row.bundleJson);
|
|
177
|
+
|
|
178
|
+
// Discover which source URIs are available without re-detecting
|
|
179
|
+
const available = getAvailableSourceKeysFromBundle(bundle);
|
|
180
|
+
// e.g. ["knapsack://patterns/button", "storybook://components/button"]
|
|
181
|
+
|
|
182
|
+
// Derive verdicts for any baseline/compare combination — instant, no I/O
|
|
183
|
+
const verdicts = computeVerdictsForBaselineCompare(
|
|
184
|
+
bundle,
|
|
185
|
+
'knapsack://patterns/button', // baseline URI
|
|
186
|
+
['storybook://components/button'], // compare URIs
|
|
187
|
+
);
|
|
188
|
+
|
|
189
|
+
// Swap baseline without re-detecting — just call again
|
|
190
|
+
const swappedVerdicts = computeVerdictsForBaselineCompare(
|
|
191
|
+
bundle,
|
|
192
|
+
'storybook://components/button',
|
|
193
|
+
['knapsack://patterns/button'],
|
|
194
|
+
);
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
### `getAvailableSourceKeysFromBundle`
|
|
198
|
+
|
|
199
|
+
```typescript
|
|
200
|
+
function getAvailableSourceKeysFromBundle(bundle: MdxConflictBundle): string[];
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
Returns the frontmatter source URI (`sourceKey`) for every item in the bundle. Any of these can be passed as `baselineSourceKey` to `computeVerdictsForBaselineCompare` without re-running detection. Sources in `bundle.excludedSourceKeys` (if any, when `MAX_COMPARE_SOURCES` is exceeded) are **not** in the bundle and cannot be used as baseline without a full re-detect.
|
|
204
|
+
|
|
205
|
+
---
|
|
206
|
+
|
|
207
|
+
## Comparison rules
|
|
208
|
+
|
|
209
|
+
Sections are compared using a chain of canonicalization rules. The first rule that applies to all sections and produces a single hash bucket wins (result: `EXACT` match method). If no rule unifies, a fallback whitespace rule produces a `FALLBACK` result.
|
|
210
|
+
|
|
211
|
+
| Rule | ID | What it does |
|
|
212
|
+
| -------------------------- | -------------------- | ------------------------------------------- |
|
|
213
|
+
| `ruleExact` | `exact` | Exact string equality |
|
|
214
|
+
| `ruleWhitespace` | `ws_v1` | Collapse whitespace, normalize line endings |
|
|
215
|
+
| `ruleTables` | `table_v1` | Parse and re-serialize Markdown tables |
|
|
216
|
+
| `ruleJsonFences` | `json_fences_v1` | Normalize JSON inside fenced code blocks |
|
|
217
|
+
| `makeRuleAst()` | `ast_v1` | Full MDX AST comparison (strips positions) |
|
|
218
|
+
| `makeRulePrettierFences()` | `prettier_fences_v1` | Format code fences with Prettier |
|
|
219
|
+
|
|
220
|
+
---
|
|
221
|
+
|
|
222
|
+
## Supported file types
|
|
223
|
+
|
|
224
|
+
Both `.mdx` and `.md` files are supported. Non-markdown files (e.g. `.json`, `.css`) are indexed but skipped during conflict detection.
|
|
225
|
+
|
|
226
|
+
---
|
|
227
|
+
|
|
228
|
+
## Source file layout
|
|
229
|
+
|
|
230
|
+
```
|
|
231
|
+
src/
|
|
232
|
+
├── index.ts # Adapter export + public API re-exports
|
|
233
|
+
├── types.ts # SourceConflictsConfig, ArtifactRef, ConflictGroup, VERDICT, Rule
|
|
234
|
+
├── validator.ts # validateConfig / validateFull
|
|
235
|
+
├── parser.ts # parse() — indexes entities, writes manifest
|
|
236
|
+
├── transformer.ts # transform() — runs detection, writes verdict bundles
|
|
237
|
+
├── analyzer.ts # analyze() — in-process detection, returns typed result
|
|
238
|
+
├── detect.ts # indexEntitiesDir / findConflictGroups (filesystem)
|
|
239
|
+
├── parse.ts # parseEntityKind / parseSourceType (filename parsing)
|
|
240
|
+
├── multiSourceCompare.ts # compareAnchorMultiSource (rule engine)
|
|
241
|
+
├── compare/
|
|
242
|
+
│ └── preview.ts # Preview/truncation helpers
|
|
243
|
+
├── mdx/
|
|
244
|
+
│ ├── mdxConflicts.ts # detectMdxConflictBundle / computeVerdictsForBaselineCompare
|
|
245
|
+
│ ├── mdxRules.ts # Built-in canonicalization rules
|
|
246
|
+
│ ├── tableMdx.ts # Table parsing / canonicalization
|
|
247
|
+
│ └── sharedProcessor.ts # Shared remark processor
|
|
248
|
+
└── utils/
|
|
249
|
+
├── canonicalCache.ts # In-memory canonical result cache (sha256)
|
|
250
|
+
└── frontmatter.ts # Frontmatter parsing helpers
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
---
|
|
254
|
+
|
|
255
|
+
## Development
|
|
256
|
+
|
|
257
|
+
```bash
|
|
258
|
+
# Build
|
|
259
|
+
pnpm run build
|
|
260
|
+
|
|
261
|
+
# Watch
|
|
262
|
+
pnpm run dev
|
|
263
|
+
|
|
264
|
+
# Test
|
|
265
|
+
pnpm run test
|
|
266
|
+
|
|
267
|
+
# Lint
|
|
268
|
+
pnpm run lint
|
|
269
|
+
```
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { Logger } from '@knapsack/adapter-core';
|
|
2
|
+
import type { SourceConflictsConfig } from './types.js';
|
|
3
|
+
import type { AnchorVerdictView, MdxConflictBundle } from './mdx/mdxConflicts.js';
|
|
4
|
+
import type { ConflictGroup } from './types.js';
|
|
5
|
+
export type ConflictGroupResult = {
|
|
6
|
+
group: ConflictGroup;
|
|
7
|
+
bundle: MdxConflictBundle;
|
|
8
|
+
/** Frontmatter sourceKey URI of the baseline source (e.g. "knapsack://patterns/button"). */
|
|
9
|
+
baselineSourceKey: string;
|
|
10
|
+
/** Frontmatter sourceKey URIs of the compare sources. */
|
|
11
|
+
compareSourceKeys: string[];
|
|
12
|
+
verdicts: AnchorVerdictView[];
|
|
13
|
+
};
|
|
14
|
+
export type SourceConflictsAnalysisResult = {
|
|
15
|
+
groupResults: ConflictGroupResult[];
|
|
16
|
+
/** Groups that were skipped (non-MDX or not enough sources). */
|
|
17
|
+
skippedGroupKeys: string[];
|
|
18
|
+
};
|
|
19
|
+
export declare function analyze(config: SourceConflictsConfig, deps: Pick<{
|
|
20
|
+
logger: Logger;
|
|
21
|
+
}, 'logger'>): Promise<SourceConflictsAnalysisResult>;
|
|
22
|
+
/**
|
|
23
|
+
* Returns the source keys present in a stored bundle.
|
|
24
|
+
* Any of these can be passed as `baselineSourceKey` to
|
|
25
|
+
* `computeVerdictsForBaselineCompare` without re-running detection.
|
|
26
|
+
* Sources in `bundle.excludedSourceKeys` are NOT available.
|
|
27
|
+
*/
|
|
28
|
+
export declare function getAvailableSourceKeysFromBundle(bundle: MdxConflictBundle): string[];
|
|
29
|
+
//# sourceMappingURL=analyzer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"analyzer.d.ts","sourceRoot":"","sources":["../src/analyzer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAc,MAAM,wBAAwB,CAAC;AACjE,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AAQxD,OAAO,KAAK,EACV,iBAAiB,EACjB,iBAAiB,EAClB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAEhD,MAAM,MAAM,mBAAmB,GAAG;IAChC,KAAK,EAAE,aAAa,CAAC;IACrB,MAAM,EAAE,iBAAiB,CAAC;IAC1B,4FAA4F;IAC5F,iBAAiB,EAAE,MAAM,CAAC;IAC1B,yDAAyD;IACzD,iBAAiB,EAAE,MAAM,EAAE,CAAC;IAC5B,QAAQ,EAAE,iBAAiB,EAAE,CAAC;CAC/B,CAAC;AAEF,MAAM,MAAM,6BAA6B,GAAG;IAC1C,YAAY,EAAE,mBAAmB,EAAE,CAAC;IACpC,gEAAgE;IAChE,gBAAgB,EAAE,MAAM,EAAE,CAAC;CAC5B,CAAC;AAEF,wBAAsB,OAAO,CAC3B,MAAM,EAAE,qBAAqB,EAC7B,IAAI,EAAE,IAAI,CAAC;IAAE,MAAM,EAAE,MAAM,CAAA;CAAE,EAAE,QAAQ,CAAC,GACvC,OAAO,CAAC,6BAA6B,CAAC,CAoExC;AAED;;;;;GAKG;AACH,wBAAgB,gCAAgC,CAC9C,MAAM,EAAE,iBAAiB,GACxB,MAAM,EAAE,CAEV"}
|
package/dist/analyzer.js
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { indexEntitiesDir, findConflictGroups } from './detect.js';
|
|
2
|
+
import { detectMdxConflictBundle, computeVerdictsForBaselineCompare, MAX_COMPARE_SOURCES, MIN_COMPARE_SOURCES, } from './mdx/mdxConflicts.js';
|
|
3
|
+
export async function analyze(config, deps) {
|
|
4
|
+
const { logger } = deps;
|
|
5
|
+
const index = await indexEntitiesDir(config.entitiesRootAbs, logger);
|
|
6
|
+
const groups = findConflictGroups(index, logger);
|
|
7
|
+
const groupResults = [];
|
|
8
|
+
const skippedGroupKeys = [];
|
|
9
|
+
for (const group of groups) {
|
|
10
|
+
if (!group.relPath.endsWith('.mdx') && !group.relPath.endsWith('.md')) {
|
|
11
|
+
skippedGroupKeys.push(group.key);
|
|
12
|
+
continue;
|
|
13
|
+
}
|
|
14
|
+
const sources = [
|
|
15
|
+
...new Set(group.artifacts.map((a) => a.sourceKey)),
|
|
16
|
+
].sort();
|
|
17
|
+
if (sources.length < 1 + MIN_COMPARE_SOURCES) {
|
|
18
|
+
skippedGroupKeys.push(group.key);
|
|
19
|
+
continue;
|
|
20
|
+
}
|
|
21
|
+
const baselineSourceKey = sources[0];
|
|
22
|
+
const compareSourceKeys = sources.slice(1, 1 + MAX_COMPARE_SOURCES);
|
|
23
|
+
const bundle = await detectMdxConflictBundle({
|
|
24
|
+
groupKey: group.key,
|
|
25
|
+
artifacts: group.artifacts,
|
|
26
|
+
baselineSourceKey,
|
|
27
|
+
compareSourceKeys,
|
|
28
|
+
siteId: config.siteId,
|
|
29
|
+
userId: config.userId,
|
|
30
|
+
configId: config.configId,
|
|
31
|
+
logger,
|
|
32
|
+
});
|
|
33
|
+
if (!bundle) {
|
|
34
|
+
skippedGroupKeys.push(group.key);
|
|
35
|
+
continue;
|
|
36
|
+
}
|
|
37
|
+
// Map filename-parsed SourceType → frontmatter URI using bundle.items.
|
|
38
|
+
const getUri = (st) => bundle.items.find((i) => i.sourceType === st)?.sourceKey ?? st;
|
|
39
|
+
const baselineUri = getUri(baselineSourceKey);
|
|
40
|
+
const compareUris = compareSourceKeys.map(getUri);
|
|
41
|
+
const verdicts = computeVerdictsForBaselineCompare(bundle, baselineUri, compareUris);
|
|
42
|
+
groupResults.push({
|
|
43
|
+
group,
|
|
44
|
+
bundle,
|
|
45
|
+
baselineSourceKey: baselineUri,
|
|
46
|
+
compareSourceKeys: compareUris,
|
|
47
|
+
verdicts,
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
return { groupResults, skippedGroupKeys };
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Returns the source keys present in a stored bundle.
|
|
54
|
+
* Any of these can be passed as `baselineSourceKey` to
|
|
55
|
+
* `computeVerdictsForBaselineCompare` without re-running detection.
|
|
56
|
+
* Sources in `bundle.excludedSourceKeys` are NOT available.
|
|
57
|
+
*/
|
|
58
|
+
export function getAvailableSourceKeysFromBundle(bundle) {
|
|
59
|
+
return bundle.items.map((item) => item.sourceKey);
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=analyzer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"analyzer.js","sourceRoot":"","sources":["../src/analyzer.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"analyzer.vitest.d.ts","sourceRoot":"","sources":["../src/analyzer.vitest.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { getAvailableSourceKeysFromBundle } from './analyzer.js';
|
|
3
|
+
function makeBundle(items) {
|
|
4
|
+
return {
|
|
5
|
+
conflict: {
|
|
6
|
+
entityKey: 'component/button.react',
|
|
7
|
+
entityType: 'COMPONENT',
|
|
8
|
+
entityRelPath: 'button.react',
|
|
9
|
+
fingerprint: 'cf_v1_abc',
|
|
10
|
+
createdAt: '2025-01-01T00:00:00Z',
|
|
11
|
+
updatedAt: '2025-01-01T00:00:00Z',
|
|
12
|
+
},
|
|
13
|
+
items,
|
|
14
|
+
anchorDefinitions: [],
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
describe('getAvailableSourceKeysFromBundle', () => {
|
|
18
|
+
it('returns URI sourceKeys for all items in the bundle', () => {
|
|
19
|
+
const bundle = makeBundle([
|
|
20
|
+
{
|
|
21
|
+
fingerprint: 'fp1',
|
|
22
|
+
sourceType: 'KNAPSACK',
|
|
23
|
+
sourceKey: 'knapsack://patterns/button',
|
|
24
|
+
frontmatterSchemaVersion: 1,
|
|
25
|
+
frontmatter: {},
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
fingerprint: 'fp2',
|
|
29
|
+
sourceType: 'STORYBOOK',
|
|
30
|
+
sourceKey: 'storybook://components/button',
|
|
31
|
+
frontmatterSchemaVersion: 1,
|
|
32
|
+
frontmatter: {},
|
|
33
|
+
},
|
|
34
|
+
]);
|
|
35
|
+
const keys = getAvailableSourceKeysFromBundle(bundle);
|
|
36
|
+
expect(keys).toEqual([
|
|
37
|
+
'knapsack://patterns/button',
|
|
38
|
+
'storybook://components/button',
|
|
39
|
+
]);
|
|
40
|
+
});
|
|
41
|
+
it('returns an empty array for a bundle with no items', () => {
|
|
42
|
+
const bundle = makeBundle([]);
|
|
43
|
+
expect(getAvailableSourceKeysFromBundle(bundle)).toEqual([]);
|
|
44
|
+
});
|
|
45
|
+
it('returns a single URI for a bundle with one item', () => {
|
|
46
|
+
const bundle = makeBundle([
|
|
47
|
+
{
|
|
48
|
+
fingerprint: 'fp1',
|
|
49
|
+
sourceType: 'KNAPSACK',
|
|
50
|
+
sourceKey: 'knapsack://patterns/button',
|
|
51
|
+
frontmatterSchemaVersion: 1,
|
|
52
|
+
frontmatter: {},
|
|
53
|
+
},
|
|
54
|
+
]);
|
|
55
|
+
expect(getAvailableSourceKeysFromBundle(bundle)).toEqual([
|
|
56
|
+
'knapsack://patterns/button',
|
|
57
|
+
]);
|
|
58
|
+
});
|
|
59
|
+
});
|
|
60
|
+
//# sourceMappingURL=analyzer.vitest.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"analyzer.vitest.js","sourceRoot":"","sources":["../src/analyzer.vitest.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAE9C,OAAO,EAAE,gCAAgC,EAAE,MAAM,eAAe,CAAC;AAEjE,SAAS,UAAU,CAAC,KAAiC;IACnD,OAAO;QACL,QAAQ,EAAE;YACR,SAAS,EAAE,wBAAwB;YACnC,UAAU,EAAE,WAAW;YACvB,aAAa,EAAE,cAAc;YAC7B,WAAW,EAAE,WAAW;YACxB,SAAS,EAAE,sBAAsB;YACjC,SAAS,EAAE,sBAAsB;SAClC;QACD,KAAK;QACL,iBAAiB,EAAE,EAAE;KACtB,CAAC;AACJ,CAAC;AAED,QAAQ,CAAC,kCAAkC,EAAE,GAAG,EAAE;IAChD,EAAE,CAAC,oDAAoD,EAAE,GAAG,EAAE;QAC5D,MAAM,MAAM,GAAG,UAAU,CAAC;YACxB;gBACE,WAAW,EAAE,KAAK;gBAClB,UAAU,EAAE,UAAU;gBACtB,SAAS,EAAE,4BAA4B;gBACvC,wBAAwB,EAAE,CAAC;gBAC3B,WAAW,EAAE,EAAE;aAChB;YACD;gBACE,WAAW,EAAE,KAAK;gBAClB,UAAU,EAAE,WAAW;gBACvB,SAAS,EAAE,+BAA+B;gBAC1C,wBAAwB,EAAE,CAAC;gBAC3B,WAAW,EAAE,EAAE;aAChB;SACF,CAAC,CAAC;QAEH,MAAM,IAAI,GAAG,gCAAgC,CAAC,MAAM,CAAC,CAAC;QACtD,MAAM,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC;YACnB,4BAA4B;YAC5B,+BAA+B;SAChC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,mDAAmD,EAAE,GAAG,EAAE;QAC3D,MAAM,MAAM,GAAG,UAAU,CAAC,EAAE,CAAC,CAAC;QAC9B,MAAM,CAAC,gCAAgC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IAC/D,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,iDAAiD,EAAE,GAAG,EAAE;QACzD,MAAM,MAAM,GAAG,UAAU,CAAC;YACxB;gBACE,WAAW,EAAE,KAAK;gBAClB,UAAU,EAAE,UAAU;gBACtB,SAAS,EAAE,4BAA4B;gBACvC,wBAAwB,EAAE,CAAC;gBAC3B,WAAW,EAAE,EAAE;aAChB;SACF,CAAC,CAAC;QACH,MAAM,CAAC,gCAAgC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC;YACvD,4BAA4B;SAC7B,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { TableNode } from '../mdx/tableMdx.js';
|
|
2
|
+
/** Default bounds for preview size; overridable via PreviewBounds. */
|
|
3
|
+
export declare const DEFAULT_MAX_DEFINITION_TEXT: number;
|
|
4
|
+
export declare const DEFAULT_MAX_DEFINITIONS = 10;
|
|
5
|
+
export declare const DEFAULT_MAX_SOURCES_PER_DEFINITION = 10;
|
|
6
|
+
/** Truncates string to max length and appends a truncation marker. */
|
|
7
|
+
export declare function truncate(s: string, max?: number): string;
|
|
8
|
+
/** Builds bounded preview.definitions from groups (capped counts); includes table value when present. */
|
|
9
|
+
export declare function stablePreviewBounded(args: {
|
|
10
|
+
groups: Array<{
|
|
11
|
+
hash: string;
|
|
12
|
+
sources: string[];
|
|
13
|
+
table?: TableNode;
|
|
14
|
+
}>;
|
|
15
|
+
maxDefinitions?: number;
|
|
16
|
+
maxSourcesPerDefinition?: number;
|
|
17
|
+
}): {
|
|
18
|
+
definitionCount: number;
|
|
19
|
+
definitions: Array<{
|
|
20
|
+
hash: string;
|
|
21
|
+
sources: string[];
|
|
22
|
+
value?: {
|
|
23
|
+
kind: 'TABLE';
|
|
24
|
+
table: TableNode;
|
|
25
|
+
};
|
|
26
|
+
}>;
|
|
27
|
+
};
|
|
28
|
+
//# sourceMappingURL=preview.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"preview.d.ts","sourceRoot":"","sources":["../../src/compare/preview.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAEpD,sEAAsE;AACtE,eAAO,MAAM,2BAA2B,QAAW,CAAC;AACpD,eAAO,MAAM,uBAAuB,KAAK,CAAC;AAC1C,eAAO,MAAM,kCAAkC,KAAK,CAAC;AAErD,sEAAsE;AACtE,wBAAgB,QAAQ,CAAC,CAAC,EAAE,MAAM,EAAE,GAAG,SAAO,GAAG,MAAM,CAGtD;AAED,yGAAyG;AACzG,wBAAgB,oBAAoB,CAAC,IAAI,EAAE;IACzC,MAAM,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,EAAE,CAAC;QAAC,KAAK,CAAC,EAAE,SAAS,CAAA;KAAE,CAAC,CAAC;IACtE,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,uBAAuB,CAAC,EAAE,MAAM,CAAC;CAClC,GAAG;IACF,eAAe,EAAE,MAAM,CAAC;IACxB,WAAW,EAAE,KAAK,CAAC;QACjB,IAAI,EAAE,MAAM,CAAC;QACb,OAAO,EAAE,MAAM,EAAE,CAAC;QAClB,KAAK,CAAC,EAAE;YAAE,IAAI,EAAE,OAAO,CAAC;YAAC,KAAK,EAAE,SAAS,CAAA;SAAE,CAAC;KAC7C,CAAC,CAAC;CACJ,CAiBA"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/** Default bounds for preview size; overridable via PreviewBounds. */
|
|
2
|
+
export const DEFAULT_MAX_DEFINITION_TEXT = 8 * 1024; // 8KB
|
|
3
|
+
export const DEFAULT_MAX_DEFINITIONS = 10;
|
|
4
|
+
export const DEFAULT_MAX_SOURCES_PER_DEFINITION = 10;
|
|
5
|
+
/** Truncates string to max length and appends a truncation marker. */
|
|
6
|
+
export function truncate(s, max = 2000) {
|
|
7
|
+
if (s.length <= max)
|
|
8
|
+
return s;
|
|
9
|
+
return `${s.slice(0, max)}\n…(truncated)…`;
|
|
10
|
+
}
|
|
11
|
+
/** Builds bounded preview.definitions from groups (capped counts); includes table value when present. */
|
|
12
|
+
export function stablePreviewBounded(args) {
|
|
13
|
+
const maxDefinitions = args.maxDefinitions ?? DEFAULT_MAX_DEFINITIONS;
|
|
14
|
+
const maxSources = args.maxSourcesPerDefinition ?? DEFAULT_MAX_SOURCES_PER_DEFINITION;
|
|
15
|
+
const definitions = args.groups.slice(0, maxDefinitions).map((g) => ({
|
|
16
|
+
hash: g.hash,
|
|
17
|
+
sources: g.sources.slice(0, maxSources),
|
|
18
|
+
...(g.table != null
|
|
19
|
+
? { value: { kind: 'TABLE', table: g.table } }
|
|
20
|
+
: {}),
|
|
21
|
+
}));
|
|
22
|
+
return {
|
|
23
|
+
definitionCount: args.groups.length,
|
|
24
|
+
definitions,
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=preview.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"preview.js","sourceRoot":"","sources":["../../src/compare/preview.ts"],"names":[],"mappings":"AAEA,sEAAsE;AACtE,MAAM,CAAC,MAAM,2BAA2B,GAAG,CAAC,GAAG,IAAI,CAAC,CAAC,MAAM;AAC3D,MAAM,CAAC,MAAM,uBAAuB,GAAG,EAAE,CAAC;AAC1C,MAAM,CAAC,MAAM,kCAAkC,GAAG,EAAE,CAAC;AAErD,sEAAsE;AACtE,MAAM,UAAU,QAAQ,CAAC,CAAS,EAAE,GAAG,GAAG,IAAI;IAC5C,IAAI,CAAC,CAAC,MAAM,IAAI,GAAG;QAAE,OAAO,CAAC,CAAC;IAC9B,OAAO,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,iBAAiB,CAAC;AAC7C,CAAC;AAED,yGAAyG;AACzG,MAAM,UAAU,oBAAoB,CAAC,IAIpC;IAQC,MAAM,cAAc,GAAG,IAAI,CAAC,cAAc,IAAI,uBAAuB,CAAC;IACtE,MAAM,UAAU,GACd,IAAI,CAAC,uBAAuB,IAAI,kCAAkC,CAAC;IAErE,MAAM,WAAW,GAAG,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,cAAc,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QACnE,IAAI,EAAE,CAAC,CAAC,IAAI;QACZ,OAAO,EAAE,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,UAAU,CAAC;QACvC,GAAG,CAAC,CAAC,CAAC,KAAK,IAAI,IAAI;YACjB,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,OAAgB,EAAE,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,EAAE;YACvD,CAAC,CAAC,EAAE,CAAC;KACR,CAAC,CAAC,CAAC;IAEJ,OAAO;QACL,eAAe,EAAE,IAAI,CAAC,MAAM,CAAC,MAAM;QACnC,WAAW;KACZ,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"preview.vitest.d.ts","sourceRoot":"","sources":["../../src/compare/preview.vitest.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { truncate, stablePreviewBounded, DEFAULT_MAX_DEFINITIONS, } from './preview.js';
|
|
3
|
+
describe('truncate', () => {
|
|
4
|
+
it('returns string unchanged when within max', () => {
|
|
5
|
+
const s = 'short';
|
|
6
|
+
expect(truncate(s)).toBe(s);
|
|
7
|
+
expect(truncate(s, 10)).toBe(s);
|
|
8
|
+
});
|
|
9
|
+
it('truncates and appends marker when over max', () => {
|
|
10
|
+
const s = 'a'.repeat(100);
|
|
11
|
+
const out = truncate(s, 20);
|
|
12
|
+
expect(out).toHaveLength(20 + '\n…(truncated)…'.length);
|
|
13
|
+
expect(out.startsWith('a'.repeat(20))).toBe(true);
|
|
14
|
+
expect(out.endsWith('…(truncated)…')).toBe(true);
|
|
15
|
+
});
|
|
16
|
+
it('uses default max 2000 when not provided', () => {
|
|
17
|
+
const s = 'x'.repeat(3000);
|
|
18
|
+
const out = truncate(s);
|
|
19
|
+
expect(out.slice(0, 2000)).toBe('x'.repeat(2000));
|
|
20
|
+
expect(out.endsWith('…(truncated)…')).toBe(true);
|
|
21
|
+
});
|
|
22
|
+
});
|
|
23
|
+
describe('stablePreviewBounded', () => {
|
|
24
|
+
const minimalTable = {
|
|
25
|
+
columns: ['a'],
|
|
26
|
+
keyColumn: 'a',
|
|
27
|
+
rows: [{ a: '1' }],
|
|
28
|
+
};
|
|
29
|
+
it('slices definitions by maxDefinitions', () => {
|
|
30
|
+
const groups = [
|
|
31
|
+
{ hash: 'h1', sources: ['s1'] },
|
|
32
|
+
{ hash: 'h2', sources: ['s2'] },
|
|
33
|
+
{ hash: 'h3', sources: ['s3'] },
|
|
34
|
+
];
|
|
35
|
+
const out = stablePreviewBounded({ groups, maxDefinitions: 2 });
|
|
36
|
+
expect(out.definitionCount).toBe(3);
|
|
37
|
+
expect(out.definitions).toHaveLength(2);
|
|
38
|
+
expect(out.definitions[0].hash).toBe('h1');
|
|
39
|
+
expect(out.definitions[1].hash).toBe('h2');
|
|
40
|
+
});
|
|
41
|
+
it('slices sources per definition by maxSourcesPerDefinition', () => {
|
|
42
|
+
const groups = [{ hash: 'h1', sources: ['s1', 's2', 's3', 's4', 's5'] }];
|
|
43
|
+
const out = stablePreviewBounded({
|
|
44
|
+
groups,
|
|
45
|
+
maxSourcesPerDefinition: 2,
|
|
46
|
+
});
|
|
47
|
+
expect(out.definitions[0].sources).toEqual(['s1', 's2']);
|
|
48
|
+
});
|
|
49
|
+
it('includes table value when present', () => {
|
|
50
|
+
const groups = [{ hash: 'h1', sources: ['s1'], table: minimalTable }];
|
|
51
|
+
const out = stablePreviewBounded({ groups });
|
|
52
|
+
expect(out.definitions[0].value).toEqual({
|
|
53
|
+
kind: 'TABLE',
|
|
54
|
+
table: minimalTable,
|
|
55
|
+
});
|
|
56
|
+
});
|
|
57
|
+
it('uses default max definitions and sources when omitted', () => {
|
|
58
|
+
const groups = Array.from({ length: 20 }, (_, i) => ({
|
|
59
|
+
hash: `h${i}`,
|
|
60
|
+
sources: ['s1'],
|
|
61
|
+
}));
|
|
62
|
+
const out = stablePreviewBounded({ groups });
|
|
63
|
+
expect(out.definitions).toHaveLength(DEFAULT_MAX_DEFINITIONS);
|
|
64
|
+
expect(out.definitionCount).toBe(20);
|
|
65
|
+
});
|
|
66
|
+
});
|
|
67
|
+
//# sourceMappingURL=preview.vitest.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"preview.vitest.js","sourceRoot":"","sources":["../../src/compare/preview.vitest.ts"],"names":[],"mappings":"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"}
|
package/dist/detect.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { Logger } from '@knapsack/adapter-core';
|
|
2
|
+
import type { ArtifactRef, ConflictGroup } from './types.js';
|
|
3
|
+
export type { ArtifactRef, ConflictGroup } from './types.js';
|
|
4
|
+
/**
|
|
5
|
+
* Index filesystem artifacts by (entityKind + canonical relPath).
|
|
6
|
+
*
|
|
7
|
+
* Expected layout: entities/<entityKind>/<base>.<sourceType>-<hash>.<ext>
|
|
8
|
+
* Same entity = same entityKind + same base name (e.g. button.react.mdx or button.react.md);
|
|
9
|
+
* sourceType and hash are read from the filename.
|
|
10
|
+
*/
|
|
11
|
+
export declare function indexEntitiesDir(entitiesRootAbs: string, logger: Logger): Promise<Map<string, ArtifactRef[]>>;
|
|
12
|
+
export declare function findConflictGroups(index: Map<string, ArtifactRef[]>, logger: Logger): ConflictGroup[];
|
|
13
|
+
//# sourceMappingURL=detect.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"detect.d.ts","sourceRoot":"","sources":["../src/detect.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAGrD,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAE7D,YAAY,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAiD7D;;;;;;GAMG;AACH,wBAAsB,gBAAgB,CACpC,eAAe,EAAE,MAAM,EACvB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,WAAW,EAAE,CAAC,CAAC,CAoCrC;AAED,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,WAAW,EAAE,CAAC,EACjC,MAAM,EAAE,MAAM,GACb,aAAa,EAAE,CAmBjB"}
|