@seedprotocol/mapping 0.6.0 → 0.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,16 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.7.0
4
+
5
+ - Relation lookup is an edge-local stored intent: `FieldMapping.lookup.entries` as `{ value, ref }[]`. `ref` is opaque (`seedLocalId` or `seedUid`). Empty entries are a valid unassigned map.
6
+ - `applyMapping` (sync) applies lookup entries and emits refs. Unmatched values are omitted. `applyMappingAsync` reports unmatched on `errors[]` and no longer calls the host `resolve` callback for lookup.
7
+ - `autoMap` pairs alias matches such as `author` → List-of-Relation `authors` with `resolve: 'lookup'` and no invented refs.
8
+ - `FieldMapper` `renderLookup?: (row: FieldMapperLookupRow) => ReactNode` — host picker on lookup rows (same split as `renderRowAccessory`). Package uid editor is a fallback only.
9
+ - `useFieldMapper.setLookupEntries`. Row `sampleValue` and `data-state="needsLookup"` when the current sample has no matching entry.
10
+ - `TargetProperty` stays Seed-accurate (`List` + `refValueType: 'Relation'` + `ref`). No `multiple` flag.
11
+ - `MappingDocument.lookups` / `lookups` + `onLookupsChange` are deprecated read/write fallbacks for 0.6.0 documents.
12
+ - `_pendingResolve` is extract/file only; lookup hits appear in the preview bag.
13
+
3
14
  ## 0.6.1
4
15
 
5
16
  - `FieldMapper` `renderRowAccessory?: (row: FieldMapperRow) => ReactNode` — host chrome slot on each rows-layout row (`.fm-row-accessory` / `classNames.rowAccessory`), after the transform control and before remove. Package does not fetch or preview; hosts return `null` when idle (e.g. show **Preview** only for `resolve: 'extract' | 'file'`).
package/README.md CHANGED
@@ -7,12 +7,12 @@ Use this package to:
7
7
  1. Parse markdown or RSS/Atom into `SourceNode[]`
8
8
  2. Optionally expand URL sources with `buildResolvedSourceNodes` (extract / file candidates)
9
9
  3. Author `FieldMapping` edges (manually, via `autoMap`, or via `FieldMapper`)
10
- 4. `applyMapping` (sync copy) or `applyMappingAsync` (host resolve callback) → property bag
10
+ 4. `applyMapping` (sync copy + stored lookup) or `applyMappingAsync` (host extract/file callback) → property bag
11
11
 
12
12
  Mappings are an edge list: one source may fan out to multiple properties (e.g. RSS
13
13
  `link` → `importUrl` and `canonicalUrl`). Each property is exclusive — at most one
14
- source may map to it. Optional `resolve: 'extract' | 'file' | 'lookup'` marks
15
- transforms the **host** (or a persisted value map) performs; the package never
14
+ source may map to it. `resolve: 'extract' | 'file'` is applied by the host callback.
15
+ `resolve: 'lookup'` is a stored string → ref table on the edge — the package never
16
16
  fetches, runs Readability, or loads Seed Identity items.
17
17
 
18
18
  ## Install
@@ -74,7 +74,7 @@ const mappings = autoMap(itemSources, postTargets)
74
74
  // link → importUrl/canonicalUrl (copy); missing body → link extract→html;
75
75
  // image URLs → featureImage with resolve:'file'
76
76
 
77
- // Sync preview skips resolve edges:
77
+ // Sync preview applies lookup entries; extract/file stay pending:
78
78
  const preview = applyMapping(itemSources, mappings, postTargets)
79
79
 
80
80
  // Publish path — host owns HTTP / extract / store:
@@ -95,7 +95,8 @@ const { properties, errors } = await applyMappingAsync(
95
95
  ### Relation lookup (`resolve: 'lookup'`)
96
96
 
97
97
  Map a string source (e.g. RSS `author`) onto a Relation or List-of-Relation
98
- target (e.g. `authors` → Identity) via a persisted dictionary and/or host callback:
98
+ target (e.g. `authors` → Identity) via **stored entries on the edge**. Use Seed
99
+ model vocabulary — not a `multiple` flag:
99
100
 
100
101
  ```ts
101
102
  const postTargets: TargetProperty[] = [
@@ -108,36 +109,40 @@ const postTargets: TargetProperty[] = [
108
109
  ]
109
110
 
110
111
  const mappings = [
111
- { sourceId: 'rss-author', propertyName: 'authors', resolve: 'lookup' as const },
112
+ {
113
+ sourceId: 'rss-author',
114
+ propertyName: 'authors',
115
+ resolve: 'lookup' as const,
116
+ lookup: {
117
+ entries: [{ value: 'Jane Doe', ref: 'identity-seed-uid' }],
118
+ },
119
+ },
112
120
  ]
113
121
 
114
122
  const doc: MappingDocument = {
115
123
  version: 1,
116
124
  sourceKind: 'rss',
117
125
  mappings,
118
- lookups: {
119
- authors: { 'Jane Doe': 'identity-seed-uid' },
120
- },
121
126
  }
122
127
 
128
+ // Sync apply emits refs from stored entries (extract/file still skipped):
129
+ const bag = applyMapping(itemSources, mappings, postTargets)
130
+ // bag.authors === ['identity-seed-uid']
131
+
123
132
  const { properties, errors } = await applyMappingAsync(
124
133
  itemSources,
125
134
  mappings,
126
135
  postTargets,
127
- {
128
- lookups: doc.lookups,
129
- // Optional: called only when the table has no entry for the trimmed source value
130
- resolve: async ({ job, rawValue }) => {
131
- if (job === 'lookup') return await findOrCreateIdentity(rawValue!)
132
- throw new Error(`unexpected job ${job}`)
133
- },
134
- },
135
136
  )
136
- // properties.authors === ['identity-seed-uid']
137
+ // Unmatched values are omitted from the bag and listed in errors[].
138
+ // Do not fetch identities inside apply — persist the assignment, then apply.
137
139
  ```
138
140
 
139
- `autoMap` never wires a plain string onto Relation / List-of-Relation targets —
140
- author those edges in FieldMapper or programmatically.
141
+ `autoMap` pairs alias matches such as `author` → `authors` with
142
+ `resolve: 'lookup'` and **empty** entries. It never invents refs.
143
+
144
+ `MappingDocument.lookups` / `applyMappingAsync({ lookups })` remain a read-only
145
+ fallback for 0.6.0 documents. Prefer `FieldMapping.lookup.entries`.
141
146
 
142
147
  `classifyUrl({ url, contentType? })` is a pure MIME/extension classifier
143
148
  (`html` | `image` | `audio` | `video` | `unknown`). Enclosure nodes expose
@@ -171,7 +176,6 @@ import {
171
176
  rssItemToSources,
172
177
  applyMappingAsync,
173
178
  type FieldMapping,
174
- type MappingLookups,
175
179
  } from '@seedprotocol/mapping'
176
180
  import { FieldMapper, useFieldMapper } from '@seedprotocol/mapping/react'
177
181
 
@@ -182,13 +186,19 @@ import { FieldMapper, useFieldMapper } from '@seedprotocol/mapping/react'
182
186
  targets={postTargets} // e.g. { name: 'html', dataType: 'Html', required: true }
183
187
  mappings={mappings}
184
188
  onChange={setMappings}
185
- lookups={lookups}
186
- onLookupsChange={setLookups}
189
+ slots={{ lookups: 'row', preview: 'row' }}
187
190
  renderRowAccessory={(row) =>
188
191
  row.mapping?.resolve === 'extract' || row.mapping?.resolve === 'file'
189
192
  ? <button type="button">Preview</button>
190
193
  : null
191
194
  }
195
+ renderLookup={(row) => (
196
+ <IdentityLookup
197
+ sampleValue={row.sampleValue}
198
+ entries={row.mapping?.lookup?.entries ?? []}
199
+ onChange={row.onLookupChange}
200
+ />
201
+ )}
192
202
  />
193
203
 
194
204
  // Rows — source-keyed
@@ -218,13 +228,13 @@ const mapper = useFieldMapper({
218
228
  // mapper.rows, mapper.coverage, mapper.setSource, mapper.setTransform, …
219
229
  ```
220
230
 
221
- Connecting a source to a Relation / List-of-Relation target sets `resolve: 'lookup'`
222
- and (when `onLookupsChange` is provided) shows a string → seed uid editor — per-row
223
- when `layout="rows"` (default `slots.lookups: 'row'`), or as a section when
224
- `layout="wires"` / `slots.lookups: 'section'`.
231
+ Connecting a source to a Relation / List-of-Relation target sets `resolve: 'lookup'`.
232
+ Pass `renderLookup` to paint the host picker (Identity, etc.) on that row. Without
233
+ `renderLookup`, `onLookupsChange` still enables the package uid-text fallback.
234
+ `lookups` / `onLookupsChange` are deprecated — persist `lookup.entries` on the edge.
225
235
 
226
- Row and JSON previews match sync `applyMapping` output (pending resolve edges listed
227
- under `_pendingResolve`; JSON sits behind a disclosure).
236
+ Row and JSON previews match sync `applyMapping` output. Lookup hits appear in the
237
+ bag; only extract/file stay under `_pendingResolve`. JSON sits behind a disclosure.
228
238
 
229
239
  **Theming**
230
240
 
@@ -238,6 +248,7 @@ under `_pendingResolve`; JSON sits behind a disclosure).
238
248
  | `components` | Optional host `Select` / `Button` / `Pill` (defaults are native controls) |
239
249
  | `slots` | Toggle chrome: `autoMap`, `filter`, `inspector`, `preview` (`'row' \| 'json' \| 'both' \| false`), `lookups` (`'row' \| 'section' \| false`; rows layout defaults to `'row'`, wires to `'section'`) |
240
250
  | `renderRowAccessory` | Optional `(row: FieldMapperRow) => ReactNode` for host chrome (e.g. extract/file **Preview**) in `.fm-row-accessory`. Unrelated to `slots.preview`. Package does not fetch. |
251
+ | `renderLookup` | Optional `(row: FieldMapperLookupRow) => ReactNode` for host lookup chrome on `resolve: 'lookup'` rows. Package does not fetch or list identities. |
241
252
  | `showPreview` | **Deprecated** — prefer `slots.preview` |
242
253
  | `connectionColors` | **Deprecated** optional stroke palette for wires; prefer `--sfm-map-*` / `--fm-map-*` / `--map-*` |
243
254
  | `layout="wires"` | **Deprecated** — prefer `layout="rows"` (now the default) |
@@ -247,9 +258,9 @@ under `_pendingResolve`; JSON sits behind a disclosure).
247
258
  **DOM hooks for host CSS**
248
259
 
249
260
  - Wires: mapped wells expose `data-mapping-index` / `data-pair={index % 8}` (kept for host CSS); pending `.active` only on the selected source.
250
- - Rows: `data-state="empty|mapped|needsResolve|conflict"`, `data-property-name`, `data-resolve`, `data-required`, `data-source-kind`.
261
+ - Rows: `data-state="empty|mapped|needsResolve|needsLookup|conflict"`, `data-property-name`, `data-resolve`, `data-required`, `data-source-kind`.
251
262
 
252
- Sync `applyMapping` preview lists pending resolve edges under `_pendingResolve`.
263
+ Sync `applyMapping` preview lists pending **extract/file** edges under `_pendingResolve`. Lookup refs from stored entries appear in the bag.
253
264
 
254
265
  See [FIELD_MAPPER_REDESIGN.md](../../docs/FIELD_MAPPER_REDESIGN.md) for the row-layout design study (Phases 1–5 shipped). PermaPress: [FIELD_MAPPER_PERMAPRESS_HANDOFF.md](../../docs/FIELD_MAPPER_PERMAPRESS_HANDOFF.md).
255
266
 
@@ -257,7 +268,7 @@ See [FIELD_MAPPER_REDESIGN.md](../../docs/FIELD_MAPPER_REDESIGN.md) for the row-
257
268
 
258
269
  | Type | Package | Meaning |
259
270
  |------|---------|---------|
260
- | `FieldMapping` / `MappingDocument` | `@seedprotocol/mapping` | Source id → **model property name** (1→N edges; optional `resolve`; optional `lookups`) |
271
+ | `FieldMapping` / `MappingDocument` | `@seedprotocol/mapping` | Source id → **model property name** (1→N edges; optional `resolve`; optional `lookup.entries`) |
261
272
  | `FeedFieldManifest` | `@seedprotocol/sdk` | Property/key → **role** (`image` / `audio` / `video` / `file` / `html` / `text`) for display |
262
273
 
263
274
  Compose them: map + resolve into a plain item, then optionally normalize roles for media/HTML display. Storage stays `Image` / `File` schema types — no separate Audio/Video dataTypes.
@@ -6,19 +6,25 @@ export declare function coerceValue(rawValue: string, dataType: string): unknown
6
6
  /**
7
7
  * Apply field mappings to produce a property bag for createItem / publish.
8
8
  * Missing sources or unknown target properties are skipped (no throw).
9
- * Mappings with `resolve` are skipped — use `applyMappingAsync` with a host callback.
9
+ * `resolve: 'extract' | 'file'` edges are skipped — use `applyMappingAsync`.
10
+ * `resolve: 'lookup'` is applied from stored entries (or deprecated document lookups).
10
11
  */
11
- export declare function applyMapping(sources: SourceNode[], mappings: FieldMapping[], targets: TargetProperty[]): PropertyBag;
12
+ export declare function applyMapping(sources: SourceNode[], mappings: FieldMapping[], targets: TargetProperty[], options?: {
13
+ lookups?: MappingLookups;
14
+ }): PropertyBag;
12
15
  export type ApplyMappingAsyncOptions = {
13
- /** Required for extract/file edges and lookup misses. */
16
+ /** Required for extract/file edges. Not called for lookup. */
14
17
  resolve?: ResolveCallback;
15
- /** String → seed uid dictionaries keyed by property name. */
18
+ /**
19
+ * String → seed uid dictionaries keyed by property name.
20
+ * @deprecated Prefer `FieldMapping.lookup.entries`. Read as a fallback only.
21
+ */
16
22
  lookups?: MappingLookups;
17
23
  };
18
24
  /**
19
- * Async apply: copy+coerce plain edges; for `resolve` edges call the host
20
- * callback (or apply lookups for `lookup`) then coerce. Partial success —
21
- * failed resolve edges are listed in `errors` and omitted from `properties`.
25
+ * Async apply: copy+coerce plain edges; apply lookup entries; for extract/file
26
+ * call the host callback then coerce. Partial success — failed resolve edges
27
+ * are listed in `errors` and omitted from `properties`.
22
28
  */
23
29
  export declare function applyMappingAsync(sources: SourceNode[], mappings: FieldMapping[], targets: TargetProperty[], options?: ApplyMappingAsyncOptions): Promise<ApplyMappingAsyncResult>;
24
30
  //# sourceMappingURL=applyMapping.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"applyMapping.d.ts","sourceRoot":"","sources":["../src/applyMapping.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EACV,uBAAuB,EACvB,YAAY,EACZ,cAAc,EACd,WAAW,EACX,eAAe,EAEf,UAAU,EACV,cAAc,EAEf,MAAM,SAAS,CAAA;AAEhB;;GAEG;AACH,wBAAgB,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAuBvE;AA8DD;;;;GAIG;AACH,wBAAgB,YAAY,CAC1B,OAAO,EAAE,UAAU,EAAE,EACrB,QAAQ,EAAE,YAAY,EAAE,EACxB,OAAO,EAAE,cAAc,EAAE,GACxB,WAAW,CAmBb;AAED,MAAM,MAAM,wBAAwB,GAAG;IACrC,yDAAyD;IACzD,OAAO,CAAC,EAAE,eAAe,CAAA;IACzB,6DAA6D;IAC7D,OAAO,CAAC,EAAE,cAAc,CAAA;CACzB,CAAA;AAED;;;;GAIG;AACH,wBAAsB,iBAAiB,CACrC,OAAO,EAAE,UAAU,EAAE,EACrB,QAAQ,EAAE,YAAY,EAAE,EACxB,OAAO,EAAE,cAAc,EAAE,EACzB,OAAO,GAAE,wBAA6B,GACrC,OAAO,CAAC,uBAAuB,CAAC,CAwIlC"}
1
+ {"version":3,"file":"applyMapping.d.ts","sourceRoot":"","sources":["../src/applyMapping.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EACV,uBAAuB,EACvB,YAAY,EACZ,cAAc,EACd,WAAW,EACX,eAAe,EAEf,UAAU,EACV,cAAc,EAEf,MAAM,SAAS,CAAA;AAEhB;;GAEG;AACH,wBAAgB,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAuBvE;AA8DD;;;;;GAKG;AACH,wBAAgB,YAAY,CAC1B,OAAO,EAAE,UAAU,EAAE,EACrB,QAAQ,EAAE,YAAY,EAAE,EACxB,OAAO,EAAE,cAAc,EAAE,EACzB,OAAO,CAAC,EAAE;IAAE,OAAO,CAAC,EAAE,cAAc,CAAA;CAAE,GACrC,WAAW,CA4Bb;AAED,MAAM,MAAM,wBAAwB,GAAG;IACrC,8DAA8D;IAC9D,OAAO,CAAC,EAAE,eAAe,CAAA;IACzB;;;OAGG;IACH,OAAO,CAAC,EAAE,cAAc,CAAA;CACzB,CAAA;AAED;;;;GAIG;AACH,wBAAsB,iBAAiB,CACrC,OAAO,EAAE,UAAU,EAAE,EACrB,QAAQ,EAAE,YAAY,EAAE,EACxB,OAAO,EAAE,cAAc,EAAE,EACzB,OAAO,GAAE,wBAA6B,GACrC,OAAO,CAAC,uBAAuB,CAAC,CAwFlC"}