@seedprotocol/mapping 0.7.0 → 0.7.2-next.593.gd5bd4ea
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/autoMap-Dh9SiWhT.js.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/react.js +5 -17
- package/dist/react.js.map +1 -1
- package/package.json +7 -2
- package/dist/autoMap-OMvtOG0S.js +0 -549
- package/dist/autoMap-OMvtOG0S.js.map +0 -1
- package/dist/autoMap-PTFd4l-9.js +0 -534
- package/dist/autoMap-PTFd4l-9.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"autoMap-Dh9SiWhT.js","names":[],"sources":["../src/relationLookup.ts","../src/classifyUrl.ts","../src/resolvedSources.ts","../src/applyMapping.ts","../src/edgeMapping.ts","../src/autoMap.ts"],"sourcesContent":["import type {\n FieldMapping,\n LookupEntry,\n MappingLookups,\n SourceNode,\n TargetProperty,\n} from './types'\n\n/**\n * True when the target expects a Seed relation uid (or list of uids)\n * rather than a copied scalar string.\n */\nexport function isRelationLookupTarget(target: TargetProperty): boolean {\n if (target.dataType === 'Relation') return true\n if (target.dataType === 'List') {\n return target.refValueType === 'Relation' || Boolean(target.ref)\n }\n return false\n}\n\n/** Trim and collapse internal whitespace for lookup dictionary keys. */\nexport function normalizeLookupKey(raw: string): string {\n return raw.replace(/\\s+/g, ' ').trim()\n}\n\n/** Normalized sample string for a source node (value, then label). */\nexport function sampleValueFromSource(source: SourceNode | undefined): string {\n if (!source) return ''\n return normalizeLookupKey(source.value || source.label)\n}\n\n/**\n * Shape a looked-up uid value for the target dataType.\n * Relation → single string; List → string[].\n */\nexport function shapeLookupValue(\n mapped: string | string[],\n target: TargetProperty,\n): string | string[] {\n if (target.dataType === 'List') {\n if (Array.isArray(mapped)) {\n return mapped.map((u) => String(u).trim()).filter(Boolean)\n }\n const one = String(mapped).trim()\n return one ? [one] : []\n }\n // Relation (or any non-List lookup target): single uid\n if (Array.isArray(mapped)) {\n return String(mapped[0] ?? '').trim()\n }\n return String(mapped).trim()\n}\n\n/** Entries stored on a lookup edge. Missing `lookup` is an empty assignment. */\nexport function lookupEntriesFromMapping(\n mapping: FieldMapping | undefined,\n): LookupEntry[] {\n return mapping?.lookup?.entries ?? []\n}\n\n/**\n * First entry whose normalized `value` matches `rawValue`.\n * Empty / whitespace-only refs are ignored.\n */\nexport function lookupRefFromEntries(\n entries: LookupEntry[] | undefined,\n rawValue: string,\n): string | undefined {\n const key = normalizeLookupKey(rawValue)\n if (!key || !entries?.length) return undefined\n for (const entry of entries) {\n if (normalizeLookupKey(entry.value) !== key) continue\n const ref = String(entry.ref ?? '').trim()\n if (ref) return ref\n }\n return undefined\n}\n\n/**\n * @deprecated Document-level table. Prefer `lookupRefFromEntries`.\n */\nexport function lookupRefFromTable(\n lookups: MappingLookups | undefined,\n propertyName: string,\n rawKey: string,\n): string | string[] | undefined {\n if (!lookups) return undefined\n const table = lookups[propertyName]\n if (!table) return undefined\n if (Object.prototype.hasOwnProperty.call(table, rawKey)) {\n return table[rawKey]\n }\n return undefined\n}\n\n/**\n * Resolve a lookup ref: edge entries first, then deprecated document table.\n */\nexport function resolveLookupMapped(\n mapping: FieldMapping,\n rawValue: string,\n lookups?: MappingLookups,\n): string | string[] | undefined {\n const key = normalizeLookupKey(rawValue)\n const fromEntries = lookupRefFromEntries(mapping.lookup?.entries, key)\n if (fromEntries !== undefined) return fromEntries\n return lookupRefFromTable(lookups, mapping.propertyName, key)\n}\n\nexport function withLookupEntries(\n edge: FieldMapping,\n entries: LookupEntry[],\n): FieldMapping {\n if (entries.length === 0) {\n if (!edge.lookup) return edge\n const { lookup: _lookup, ...rest } = edge\n return rest\n }\n return { ...edge, lookup: { entries } }\n}\n\n/** Drop `lookup` when the edge is no longer a lookup job. */\nexport function stripLookup(edge: FieldMapping): FieldMapping {\n if (!edge.lookup) return edge\n const { lookup: _lookup, ...rest } = edge\n return rest\n}\n","import type { UrlMediaClass } from './types'\n\nexport type ClassifyUrlInput = {\n url: string\n contentType?: string | null\n}\n\nfunction normalizeMime(contentType: string): string {\n return contentType.split(';')[0]?.trim().toLowerCase() ?? ''\n}\n\nfunction classFromMime(mime: string): UrlMediaClass | null {\n if (!mime) return null\n if (mime.startsWith('image/')) return 'image'\n if (mime.startsWith('audio/')) return 'audio'\n if (mime.startsWith('video/')) return 'video'\n if (\n mime === 'text/html' ||\n mime === 'application/xhtml+xml' ||\n mime === 'application/xhtml'\n ) {\n return 'html'\n }\n return null\n}\n\nfunction pathFromUrl(url: string): string {\n const trimmed = url.trim()\n try {\n const u = new URL(trimmed)\n return u.pathname.toLowerCase()\n } catch {\n const noQuery = trimmed.split('?')[0]?.split('#')[0] ?? trimmed\n return noQuery.toLowerCase()\n }\n}\n\nfunction classFromPath(pathname: string): UrlMediaClass {\n if (/\\.(html?|xhtml|php|asp|aspx|jsp)$/i.test(pathname)) return 'html'\n if (/\\.(jpe?g|png|gif|webp|avif|svg|bmp|ico|tiff?)$/i.test(pathname)) {\n return 'image'\n }\n if (/\\.(mp3|m4a|aac|ogg|oga|opus|wav|flac|aiff?)$/i.test(pathname)) {\n return 'audio'\n }\n if (/\\.(mp4|m4v|webm|ogv|mov|avi|mkv)$/i.test(pathname)) return 'video'\n return 'unknown'\n}\n\n/**\n * Pure MIME / URL-shape classifier for import mapping.\n * Prefer `contentType` when present; fall back to path extension.\n * No I/O. Distinct from `@seedprotocol/sdk` `classifyMediaRef` (Seed ref identity).\n */\nexport function classifyUrl(input: ClassifyUrlInput): UrlMediaClass {\n const url = typeof input.url === 'string' ? input.url.trim() : ''\n if (!url) return 'unknown'\n\n if (input.contentType) {\n const fromMime = classFromMime(normalizeMime(String(input.contentType)))\n if (fromMime) return fromMime\n }\n\n return classFromPath(pathFromUrl(url))\n}\n\n/** True when the string looks like an absolute http(s) / blob / data URL. */\nexport function looksLikeUrl(value: string): boolean {\n const v = value.trim().toLowerCase()\n return (\n v.startsWith('http://') ||\n v.startsWith('https://') ||\n v.startsWith('blob:') ||\n v.startsWith('data:')\n )\n}\n","import { classifyUrl, looksLikeUrl } from './classifyUrl'\nimport type {\n FieldMapping,\n ResolveJob,\n SourceNode,\n UrlMediaClass,\n} from './types'\n\nexport const RESOLVE_EXTRACT_SUFFIX = '@extract'\nexport const RESOLVE_FILE_SUFFIX = '@file'\n\nfunction contentTypeFromMeta(meta?: Record<string, unknown>): string | undefined {\n if (!meta) return undefined\n const ct = meta.contentType ?? meta.type\n return typeof ct === 'string' && ct.trim() ? ct.trim() : undefined\n}\n\nfunction mediaClassFromSource(source: SourceNode): UrlMediaClass {\n const metaClass = source.meta?.class\n if (\n metaClass === 'html' ||\n metaClass === 'image' ||\n metaClass === 'audio' ||\n metaClass === 'video' ||\n metaClass === 'unknown'\n ) {\n return metaClass\n }\n const url =\n typeof source.meta?.url === 'string' && source.meta.url.trim()\n ? source.meta.url.trim()\n : source.value\n return classifyUrl({\n url,\n contentType: contentTypeFromMeta(source.meta),\n })\n}\n\nfunction isUrlCandidate(source: SourceNode): boolean {\n if (source.kind === 'resolved') return false\n if (source.kind === 'full' || source.kind === 'section') return false\n const url =\n typeof source.meta?.url === 'string' && source.meta.url.trim()\n ? source.meta.url.trim()\n : source.value\n return looksLikeUrl(url)\n}\n\n/**\n * Parse a package-owned derived source id (`origin@extract` / `origin@file`).\n */\nexport function parseResolvedSourceId(\n sourceId: string,\n): { originId: string; resolve: ResolveJob } | null {\n if (sourceId.endsWith(RESOLVE_EXTRACT_SUFFIX)) {\n return {\n originId: sourceId.slice(0, -RESOLVE_EXTRACT_SUFFIX.length),\n resolve: 'extract',\n }\n }\n if (sourceId.endsWith(RESOLVE_FILE_SUFFIX)) {\n return {\n originId: sourceId.slice(0, -RESOLVE_FILE_SUFFIX.length),\n resolve: 'file',\n }\n }\n return null\n}\n\n/**\n * Normalize a UI selection (possibly a derived `@extract` / `@file` node)\n * into a persistable FieldMapping with `resolve` on the origin source.\n */\nexport function normalizeMappingFromSourceId(\n sourceId: string,\n propertyName: string,\n): FieldMapping {\n const parsed = parseResolvedSourceId(sourceId)\n if (!parsed) {\n return { sourceId, propertyName }\n }\n return {\n sourceId: parsed.originId,\n propertyName,\n resolve: parsed.resolve,\n }\n}\n\n/**\n * Stable display id for a derived resolve candidate.\n */\nexport function resolvedSourceId(originId: string, job: ResolveJob): string {\n if (job === 'extract') return `${originId}${RESOLVE_EXTRACT_SUFFIX}`\n if (job === 'file') return `${originId}${RESOLVE_FILE_SUFFIX}`\n return originId\n}\n\n/**\n * Expand URL-classifiable sources with package-owned extract/file candidates\n * for FieldMapper / autoMap. Original nodes are preserved.\n *\n * Prefer mapping derived nodes in the UI; persist via\n * `normalizeMappingFromSourceId` so documents store origin + `resolve`.\n */\nexport function buildResolvedSourceNodes(sources: SourceNode[]): SourceNode[] {\n const out: SourceNode[] = [...sources]\n const existing = new Set(sources.map((s) => s.id))\n\n for (const source of sources) {\n if (!isUrlCandidate(source)) continue\n\n const url =\n typeof source.meta?.url === 'string' && source.meta.url.trim()\n ? source.meta.url.trim()\n : source.value.trim()\n const contentType = contentTypeFromMeta(source.meta)\n const mediaClass = mediaClassFromSource(source)\n\n const extractId = resolvedSourceId(source.id, 'extract')\n if (!existing.has(extractId)) {\n out.push({\n id: extractId,\n label: `${source.label} → extract HTML`,\n kind: 'resolved',\n value: url,\n meta: {\n originId: source.id,\n resolve: 'extract' satisfies ResolveJob,\n class: 'html' satisfies UrlMediaClass,\n contentType,\n url,\n },\n })\n existing.add(extractId)\n }\n\n const fileId = resolvedSourceId(source.id, 'file')\n if (!existing.has(fileId)) {\n out.push({\n id: fileId,\n label: `${source.label} → file`,\n kind: 'resolved',\n value: url,\n meta: {\n originId: source.id,\n resolve: 'file' satisfies ResolveJob,\n class: mediaClass,\n contentType,\n url,\n },\n })\n existing.add(fileId)\n }\n }\n\n return out\n}\n\n/**\n * Look up the origin source for a mapping (handles resolve edges).\n */\nexport function resolveMappingSource(\n sources: SourceNode[],\n mapping: FieldMapping,\n): SourceNode | undefined {\n const byId = new Map(sources.map((s) => [s.id, s]))\n if (!mapping.sourceId) return undefined\n const direct = byId.get(mapping.sourceId)\n if (direct) return direct\n if (mapping.resolve) {\n const derived = byId.get(resolvedSourceId(mapping.sourceId, mapping.resolve))\n if (derived) return derived\n }\n return undefined\n}\n","import {\n isRelationLookupTarget,\n normalizeLookupKey,\n resolveLookupMapped,\n shapeLookupValue,\n} from './relationLookup'\nimport { resolveMappingSource } from './resolvedSources'\nimport type {\n ApplyMappingAsyncResult,\n FieldMapping,\n MappingLookups,\n PropertyBag,\n ResolveCallback,\n ResolveContext,\n SourceNode,\n TargetProperty,\n UrlMediaClass,\n} from './types'\n\n/**\n * Coerce a raw string value to the Seed model property dataType.\n */\nexport function coerceValue(rawValue: string, dataType: string): unknown {\n if (dataType === 'Number') {\n return parseFloat(String(rawValue)) || 0\n }\n if (dataType === 'Boolean') {\n return (\n rawValue === 'true' ||\n rawValue === '1' ||\n String(rawValue).toLowerCase() === 'yes'\n )\n }\n if (dataType === 'Json') {\n try {\n return JSON.parse(rawValue)\n } catch {\n return rawValue\n }\n }\n if (dataType === 'Date') {\n const d = new Date(String(rawValue))\n return Number.isNaN(d.getTime()) ? rawValue : d.getTime()\n }\n return String(rawValue ?? '')\n}\n\nfunction coerceResolved(raw: unknown, dataType: string): unknown {\n if (typeof raw === 'string') {\n return coerceValue(raw, dataType)\n }\n if (raw == null) {\n return coerceValue('', dataType)\n }\n // Host may return seed refs, blobs, or already-shaped values for File/Image.\n if (\n dataType === 'Image' ||\n dataType === 'File' ||\n dataType === 'Relation' ||\n dataType === 'List' ||\n dataType === 'Json'\n ) {\n return raw\n }\n return coerceValue(String(raw), dataType)\n}\n\nfunction urlFromSource(source: SourceNode): string {\n if (typeof source.meta?.url === 'string' && source.meta.url.trim()) {\n return source.meta.url.trim()\n }\n return (source.value || source.label).trim()\n}\n\nfunction contentTypeFromSource(source: SourceNode): string | undefined {\n const ct = source.meta?.contentType ?? source.meta?.type\n return typeof ct === 'string' && ct.trim() ? ct.trim() : undefined\n}\n\nfunction classFromSource(source: SourceNode): UrlMediaClass | undefined {\n const c = source.meta?.class\n if (\n c === 'html' ||\n c === 'image' ||\n c === 'audio' ||\n c === 'video' ||\n c === 'unknown'\n ) {\n return c\n }\n return undefined\n}\n\nfunction applyLookupEdge(\n mapping: FieldMapping,\n source: SourceNode,\n target: TargetProperty,\n lookups: MappingLookups | undefined,\n): { value: string | string[] } | { unmatched: string } {\n const rawValue = normalizeLookupKey(source.value || source.label)\n const mapped = resolveLookupMapped(mapping, rawValue, lookups)\n if (mapped === undefined) {\n return { unmatched: rawValue }\n }\n return { value: shapeLookupValue(mapped, target) }\n}\n\n/**\n * Apply field mappings to produce a property bag for createItem / publish.\n * Missing sources or unknown target properties are skipped (no throw).\n * `resolve: 'extract' | 'file' | 'derive' | 'assemble'` edges are skipped.\n * Use `applyMappingAsync` for extract/file. Derive/assemble stay host-applied.\n * `resolve: 'lookup'` is applied from stored entries (or deprecated document lookups).\n */\nexport function applyMapping(\n sources: SourceNode[],\n mappings: FieldMapping[],\n targets: TargetProperty[],\n options?: { lookups?: MappingLookups },\n): PropertyBag {\n const byId = new Map(sources.map((s) => [s.id, s]))\n const byName = new Map(targets.map((t) => [t.name, t]))\n const properties: PropertyBag = {}\n\n for (const mapping of mappings) {\n if (mapping.resolve && mapping.resolve !== 'lookup') continue\n\n const source = mapping.sourceId ? byId.get(mapping.sourceId) : undefined\n const target = byName.get(mapping.propertyName)\n if (!source || !target) continue\n\n if (mapping.resolve === 'lookup') {\n const result = applyLookupEdge(mapping, source, target, options?.lookups)\n if ('value' in result) {\n properties[mapping.propertyName] = result.value\n }\n continue\n }\n\n // Never copy a raw string onto relation / list-of-relation targets.\n if (isRelationLookupTarget(target)) continue\n\n const raw = source.value || source.label\n properties[mapping.propertyName] = coerceValue(raw, target.dataType)\n }\n\n return properties\n}\n\nexport type ApplyMappingAsyncOptions = {\n /** Required for extract/file edges. Not called for lookup. */\n resolve?: ResolveCallback\n /**\n * String → seed uid dictionaries keyed by property name.\n * @deprecated Prefer `FieldMapping.lookup.entries`. Read as a fallback only.\n */\n lookups?: MappingLookups\n}\n\n/**\n * Async apply: copy+coerce plain edges; apply lookup entries; for extract/file\n * call the host callback then coerce. `derive` / `assemble` are skipped —\n * host apply stays host-owned. Partial success — failed resolve edges\n * are listed in `errors` and omitted from `properties`.\n */\nexport async function applyMappingAsync(\n sources: SourceNode[],\n mappings: FieldMapping[],\n targets: TargetProperty[],\n options: ApplyMappingAsyncOptions = {},\n): Promise<ApplyMappingAsyncResult> {\n const byName = new Map(targets.map((t) => [t.name, t]))\n const properties: PropertyBag = {}\n const errors: ApplyMappingAsyncResult['errors'] = []\n\n for (const mapping of mappings) {\n const target = byName.get(mapping.propertyName)\n if (!target) continue\n\n if (mapping.resolve === 'derive' || mapping.resolve === 'assemble') {\n continue\n }\n\n if (!mapping.resolve) {\n const source = mapping.sourceId\n ? sources.find((s) => s.id === mapping.sourceId)\n : undefined\n if (!source) continue\n if (isRelationLookupTarget(target)) continue\n const raw = source.value || source.label\n properties[mapping.propertyName] = coerceValue(raw, target.dataType)\n continue\n }\n\n if (mapping.resolve === 'lookup') {\n const source = mapping.sourceId\n ? sources.find((s) => s.id === mapping.sourceId)\n : undefined\n if (!source) {\n errors.push({\n sourceId: mapping.sourceId,\n propertyName: mapping.propertyName,\n resolve: 'lookup',\n message: `Source not found: ${mapping.sourceId}`,\n })\n continue\n }\n\n const result = applyLookupEdge(mapping, source, target, options.lookups)\n if ('value' in result) {\n properties[mapping.propertyName] = result.value\n } else {\n errors.push({\n sourceId: mapping.sourceId,\n propertyName: mapping.propertyName,\n resolve: 'lookup',\n message: `No lookup entry for \"${result.unmatched}\"`,\n })\n }\n continue\n }\n\n const source = resolveMappingSource(sources, mapping)\n if (!source) {\n errors.push({\n sourceId: mapping.sourceId,\n propertyName: mapping.propertyName,\n resolve: mapping.resolve,\n message: `Source not found: ${mapping.sourceId}`,\n })\n continue\n }\n\n if (!options.resolve) {\n errors.push({\n sourceId: mapping.sourceId,\n propertyName: mapping.propertyName,\n resolve: mapping.resolve,\n message: `No resolve callback for ${mapping.resolve}`,\n })\n continue\n }\n\n const ctx: ResolveContext = {\n job: mapping.resolve,\n url: urlFromSource(source),\n source,\n target,\n contentType: contentTypeFromSource(source),\n class: classFromSource(source),\n }\n\n try {\n const resolved = await options.resolve(ctx)\n properties[mapping.propertyName] = coerceResolved(resolved, target.dataType)\n } catch (err) {\n errors.push({\n sourceId: mapping.sourceId,\n propertyName: mapping.propertyName,\n resolve: mapping.resolve,\n message: err instanceof Error ? err.message : String(err),\n })\n }\n }\n\n return { properties, errors }\n}\n","import { stripLookup } from './relationLookup'\nimport type { AssembleSpec, DeriveSpec, FieldMapping, ResolveJob } from './types'\n\n/** True when the edge covers a property for coverage / row presence. */\nexport function isPresentEdge(mapping: FieldMapping): boolean {\n if (!mapping.propertyName) return false\n if (mapping.sourceId) return true\n return mapping.resolve === 'derive'\n}\n\n/** Drop empty `sourceId` so derive-only edges do not persist `''`. */\nexport function omitEmptySourceId(edge: FieldMapping): FieldMapping {\n if (edge.sourceId) return edge\n const { sourceId: _sourceId, ...rest } = edge\n return rest\n}\n\nexport function isDeriveKeepOnClear(prev: FieldMapping): boolean {\n return prev.resolve === 'derive' || Boolean(prev.derive)\n}\n\n/** Source-less derive edge after the origin is cleared. */\nexport function clearSourceKeepDerive(prev: FieldMapping): FieldMapping {\n return omitEmptySourceId({\n propertyName: prev.propertyName,\n resolve: 'derive',\n ...(prev.derive ? { derive: prev.derive } : {}),\n })\n}\n\nexport function withDeriveSpec(\n edge: FieldMapping,\n spec: DeriveSpec | null,\n): FieldMapping {\n if (!spec) {\n if (!edge.derive) return omitEmptySourceId(edge)\n const { derive: _derive, ...rest } = edge\n return omitEmptySourceId(rest)\n }\n return omitEmptySourceId({ ...edge, derive: spec })\n}\n\nexport function withAssembleBlocks(\n edge: FieldMapping,\n blocks: string[],\n): FieldMapping {\n return omitEmptySourceId({ ...edge, assemble: { blocks } })\n}\n\n/**\n * Next edge after a transform change.\n * Copy keeps `derive` (fallback). Assemble keeps `assemble`. Lookup keeps `lookup`.\n */\nexport function applyResolveToEdge(\n prev: FieldMapping,\n nextResolve: ResolveJob | null,\n): FieldMapping {\n const base: FieldMapping = {\n propertyName: prev.propertyName,\n ...(prev.sourceId ? { sourceId: prev.sourceId } : {}),\n }\n\n if (!nextResolve) {\n if (!prev.sourceId && isDeriveKeepOnClear(prev)) {\n return clearSourceKeepDerive(prev)\n }\n if (prev.derive) base.derive = prev.derive\n return omitEmptySourceId(base)\n }\n\n if (nextResolve === 'derive') {\n return omitEmptySourceId({\n ...base,\n resolve: 'derive',\n ...(prev.derive ? { derive: prev.derive } : {}),\n })\n }\n\n if (nextResolve === 'assemble') {\n return omitEmptySourceId({\n ...base,\n resolve: 'assemble',\n ...(prev.assemble ? { assemble: prev.assemble } : {}),\n })\n }\n\n if (nextResolve === 'lookup') {\n return omitEmptySourceId({\n ...base,\n resolve: 'lookup',\n ...(prev.lookup ? { lookup: prev.lookup } : {}),\n })\n }\n\n return omitEmptySourceId({ ...base, resolve: nextResolve })\n}\n\n/**\n * Copy prior `derive` / `assemble` onto a newly connected origin\n * when the next edge did not already set a conflicting job.\n */\nexport function withPreservedExtras(\n next: FieldMapping,\n prev: FieldMapping | undefined,\n): FieldMapping {\n if (!prev) return omitEmptySourceId(stripLookupUnlessLookup(next))\n let out: FieldMapping = { ...next }\n\n if (!out.resolve) {\n if (prev.resolve === 'assemble') {\n out = {\n ...out,\n resolve: 'assemble',\n ...(prev.assemble ? { assemble: prev.assemble } : {}),\n }\n } else if (prev.resolve === 'derive') {\n out = { ...out, resolve: 'derive' }\n }\n }\n\n if (prev.derive && (!out.resolve || out.resolve === 'derive')) {\n out = { ...out, derive: out.derive ?? prev.derive }\n }\n\n if (out.resolve === 'assemble' && prev.assemble && !out.assemble) {\n out = { ...out, assemble: prev.assemble }\n }\n\n return omitEmptySourceId(stripLookupUnlessLookup(out))\n}\n\nfunction stripLookupUnlessLookup(edge: FieldMapping): FieldMapping {\n return edge.resolve === 'lookup' ? edge : stripLookup(edge)\n}\n","import { classifyUrl, looksLikeUrl } from './classifyUrl'\nimport { isRelationLookupTarget } from './relationLookup'\nimport type { FieldMapping, SourceNode, TargetProperty, UrlMediaClass } from './types'\n\nconst FULL_DOC_PROP_NAMES = ['text', 'content', 'body', 'fulltext', 'markdown']\nconst HTML_PROP_NAMES = ['html', 'content', 'body', 'text']\nconst IMAGE_PROP_ALIASES = [\n 'featureimage',\n 'feature_image',\n 'image',\n 'cover',\n 'coverimage',\n]\nconst FILE_PROP_ALIASES = ['file', 'audio', 'video', 'enclosure', 'attachment', 'media']\nconst URL_PROP_ALIASES = ['importurl', 'canonicalurl', 'url', 'link', 'permalink']\n\nfunction normalizeName(name: string): string {\n return name.toLowerCase().replace(/\\s+/g, '').replace(/[:_-]/g, '')\n}\n\nfunction namesMatch(a: string, b: string): boolean {\n const na = normalizeName(a)\n const nb = normalizeName(b)\n return na === nb || na.includes(nb) || nb.includes(na)\n}\n\n/**\n * Sources that fan out to every unused target matching any alias.\n * Keys are normalized source label/id fragments.\n */\nconst FAN_OUT_ALIASES: Record<string, string[]> = {\n link: URL_PROP_ALIASES,\n url: URL_PROP_ALIASES,\n}\n\nfunction fanOutAliasesForSource(source: SourceNode): string[] | undefined {\n if (source.kind === 'resolved') return undefined\n const labelKey = normalizeName(source.label)\n const idKey = normalizeName(source.id.replace(/^rss-/, '').replace(/^fm-/, ''))\n return FAN_OUT_ALIASES[labelKey] ?? FAN_OUT_ALIASES[idKey]\n}\n\nfunction contentTypeFromMeta(meta?: Record<string, unknown>): string | undefined {\n if (!meta) return undefined\n const ct = meta.contentType ?? meta.type\n return typeof ct === 'string' && ct.trim() ? ct.trim() : undefined\n}\n\nfunction mediaClassOf(source: SourceNode): UrlMediaClass {\n const metaClass = source.meta?.class\n if (\n metaClass === 'html' ||\n metaClass === 'image' ||\n metaClass === 'audio' ||\n metaClass === 'video' ||\n metaClass === 'unknown'\n ) {\n return metaClass\n }\n const url =\n typeof source.meta?.url === 'string' && source.meta.url.trim()\n ? source.meta.url.trim()\n : source.value\n return classifyUrl({\n url,\n contentType: contentTypeFromMeta(source.meta),\n })\n}\n\nfunction isRawUrlSource(source: SourceNode): boolean {\n if (source.kind === 'resolved') return false\n if (source.kind === 'full' || source.kind === 'section') return false\n // content:encoded / description HTML bodies are not \"raw URL\" sources\n const labelKey = normalizeName(source.label)\n if (\n labelKey === 'contentencoded' ||\n labelKey === 'content' ||\n labelKey === 'description' ||\n labelKey === 'summary' ||\n labelKey === 'title'\n ) {\n return false\n }\n const url =\n typeof source.meta?.url === 'string' && source.meta.url.trim()\n ? source.meta.url.trim()\n : source.value\n return looksLikeUrl(url) && !url.trim().includes('<')\n}\n\nfunction isHtmlLikeTarget(target: TargetProperty): boolean {\n const n = normalizeName(target.name)\n return (\n HTML_PROP_NAMES.some((p) => namesMatch(n, p)) ||\n target.dataType === 'Html' ||\n target.dataType === 'Text'\n )\n}\n\nfunction isRichMediaTarget(target: TargetProperty): boolean {\n const n = normalizeName(target.name)\n if (\n target.dataType === 'Image' ||\n target.dataType === 'File' ||\n target.dataType === 'Relation'\n ) {\n return (\n IMAGE_PROP_ALIASES.some((a) => namesMatch(n, a)) ||\n FILE_PROP_ALIASES.some((a) => namesMatch(n, a)) ||\n target.dataType === 'Image' ||\n target.dataType === 'File'\n )\n }\n return (\n IMAGE_PROP_ALIASES.some((a) => namesMatch(n, a)) ||\n FILE_PROP_ALIASES.some((a) => namesMatch(n, a))\n )\n}\n\nfunction isUrlOnlyTarget(target: TargetProperty): boolean {\n const n = normalizeName(target.name)\n return URL_PROP_ALIASES.some((a) => namesMatch(n, a))\n}\n\nfunction findImageTarget(\n targets: TargetProperty[],\n usedProps: Set<string>,\n): TargetProperty | undefined {\n return targets.find((p) => {\n if (usedProps.has(p.name)) return false\n const n = normalizeName(p.name)\n return (\n p.dataType === 'Image' ||\n IMAGE_PROP_ALIASES.some((a) => namesMatch(n, a))\n )\n })\n}\n\nfunction findFileTarget(\n targets: TargetProperty[],\n usedProps: Set<string>,\n mediaClass: UrlMediaClass,\n): TargetProperty | undefined {\n return targets.find((p) => {\n if (usedProps.has(p.name)) return false\n const n = normalizeName(p.name)\n if (mediaClass === 'audio' && namesMatch(n, 'audio')) return true\n if (mediaClass === 'video' && namesMatch(n, 'video')) return true\n return p.dataType === 'File' || FILE_PROP_ALIASES.some((a) => namesMatch(n, a))\n })\n}\n\nfunction findHtmlTarget(\n targets: TargetProperty[],\n usedProps: Set<string>,\n): TargetProperty | undefined {\n return targets.find((p) => {\n if (usedProps.has(p.name)) return false\n const n = normalizeName(p.name)\n return (\n p.dataType === 'Html' ||\n HTML_PROP_NAMES.some((alias) => namesMatch(n, alias))\n )\n })\n}\n\n/**\n * Heuristic auto-map: full-document / full-text first, then RSS aliases,\n * URL fan-out (copy only), media file/extract jobs, then fuzzy name match.\n * Never maps a raw URL onto html / Image / File without `resolve`.\n */\nexport function autoMap(\n sources: SourceNode[],\n targets: TargetProperty[],\n): FieldMapping[] {\n const mappings: FieldMapping[] = []\n const usedProps = new Set<string>()\n const usedSources = new Set<string>()\n\n // Skip derived resolve nodes in the main pass; we emit resolve jobs from origins.\n const baseSources = sources.filter((s) => s.kind !== 'resolved')\n\n const fullSource = baseSources.find((s) => s.kind === 'full')\n if (fullSource) {\n const fullDocMatch = targets.find((p) =>\n FULL_DOC_PROP_NAMES.includes(p.name.toLowerCase()),\n )\n if (fullDocMatch) {\n mappings.push({\n sourceId: fullSource.id,\n propertyName: fullDocMatch.name,\n })\n usedProps.add(fullDocMatch.name)\n usedSources.add(fullSource.id)\n }\n }\n\n const rssAliases: Record<string, string[]> = {\n title: ['title', 'name', 'headline'],\n 'content:encoded': ['html', 'content', 'body', 'text'],\n content: ['html', 'content', 'body', 'text'],\n description: ['summary', 'description', 'excerpt'],\n summary: ['summary', 'description', 'excerpt'],\n featureimage: ['featureimage', 'feature_image', 'image', 'cover'],\n feature_image: ['featureimage', 'feature_image', 'image', 'cover'],\n link: ['url', 'link', 'permalink'],\n creator: ['author', 'authors', 'creator', 'byline'],\n author: ['author', 'authors', 'creator', 'byline'],\n }\n\n // Prefer full-text RSS → html (copy) before URL extract\n for (const source of baseSources) {\n if (usedSources.has(source.id)) continue\n const labelKey = normalizeName(source.label)\n const idKey = source.id.replace(/^rss-/, '').replace(/^fm-/, '')\n if (\n labelKey === 'contentencoded' ||\n normalizeName(idKey) === 'contentencoded' ||\n (labelKey === 'content' && source.value.includes('<'))\n ) {\n const htmlTarget = findHtmlTarget(targets, usedProps)\n if (htmlTarget) {\n mappings.push({ sourceId: source.id, propertyName: htmlTarget.name })\n usedProps.add(htmlTarget.name)\n usedSources.add(source.id)\n }\n }\n }\n\n for (const source of baseSources) {\n if (usedSources.has(source.id)) continue\n\n const fanOutAliases = fanOutAliasesForSource(source)\n if (fanOutAliases) {\n for (const target of targets) {\n if (usedProps.has(target.name)) continue\n if (isRichMediaTarget(target) && !isUrlOnlyTarget(target)) continue\n if (isHtmlLikeTarget(target) && !isUrlOnlyTarget(target)) {\n // Do not fan raw link into html — handled later as extract if needed\n const n = normalizeName(target.name)\n if (n === 'html' || target.dataType === 'Html') continue\n }\n const matches = fanOutAliases.some((alias) =>\n namesMatch(target.name, alias),\n )\n if (matches) {\n mappings.push({ sourceId: source.id, propertyName: target.name })\n usedProps.add(target.name)\n }\n }\n continue\n }\n\n // Media URL sources → resolve:file onto Image/File targets\n if (isRawUrlSource(source)) {\n const mediaClass = mediaClassOf(source)\n if (mediaClass === 'image') {\n const imageTarget = findImageTarget(targets, usedProps)\n if (imageTarget) {\n mappings.push({\n sourceId: source.id,\n propertyName: imageTarget.name,\n resolve: 'file',\n })\n usedProps.add(imageTarget.name)\n usedSources.add(source.id)\n continue\n }\n }\n if (mediaClass === 'audio' || mediaClass === 'video') {\n const fileTarget = findFileTarget(targets, usedProps, mediaClass)\n if (fileTarget) {\n mappings.push({\n sourceId: source.id,\n propertyName: fileTarget.name,\n resolve: 'file',\n })\n usedProps.add(fileTarget.name)\n usedSources.add(source.id)\n continue\n }\n }\n // Unknown / html-class URLs: do not map onto rich media without resolve\n // (extract handled in a later pass for link-like sources)\n }\n\n const labelKey = normalizeName(source.label)\n const idKey = source.id.replace(/^rss-/, '').replace(/^fm-/, '')\n const aliasKeys = [\n ...(rssAliases[source.label] ?? []),\n ...(rssAliases[idKey] ?? []),\n ...(rssAliases[labelKey] ?? []),\n ]\n\n let match: TargetProperty | undefined\n\n for (const alias of aliasKeys) {\n match = targets.find(\n (p) => !usedProps.has(p.name) && namesMatch(p.name, alias),\n )\n if (match) break\n }\n\n if (!match) {\n match = targets.find(\n (p) =>\n !usedProps.has(p.name) &&\n (namesMatch(p.name, source.label) || namesMatch(p.name, idKey)),\n )\n }\n\n if (match) {\n // Block raw URL → html / image / file without resolve\n if (\n isRawUrlSource(source) &&\n (isHtmlLikeTarget(match) || isRichMediaTarget(match)) &&\n !isUrlOnlyTarget(match)\n ) {\n // skip — extract / file jobs handled separately\n } else if (\n isRawUrlSource(source) &&\n mediaClassOf(source) === 'image' &&\n isRichMediaTarget(match)\n ) {\n mappings.push({\n sourceId: source.id,\n propertyName: match.name,\n resolve: 'file',\n })\n usedProps.add(match.name)\n usedSources.add(source.id)\n } else if (isRelationLookupTarget(match)) {\n mappings.push({\n sourceId: source.id,\n propertyName: match.name,\n resolve: 'lookup',\n })\n usedProps.add(match.name)\n usedSources.add(source.id)\n } else {\n mappings.push({ sourceId: source.id, propertyName: match.name })\n usedProps.add(match.name)\n usedSources.add(source.id)\n }\n }\n }\n\n // If no HTML body filled, prefer extract from link/permalink\n const htmlStillFree = findHtmlTarget(targets, usedProps)\n if (htmlStillFree) {\n const linkSource = baseSources.find((s) => {\n if (usedSources.has(s.id) && !fanOutAliasesForSource(s)) return false\n const labelKey = normalizeName(s.label)\n const idKey = normalizeName(s.id.replace(/^rss-/, '').replace(/^fm-/, ''))\n return (\n (labelKey === 'link' ||\n labelKey === 'url' ||\n idKey === 'link' ||\n idKey === 'url' ||\n labelKey === 'permalink') &&\n looksLikeUrl(s.value)\n )\n })\n if (linkSource) {\n mappings.push({\n sourceId: linkSource.id,\n propertyName: htmlStillFree.name,\n resolve: 'extract',\n })\n usedProps.add(htmlStillFree.name)\n }\n }\n\n return mappings\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"autoMap-Dh9SiWhT.js","names":["contentTypeFromMeta","isRelationLookupTarget","target","normalizeLookupKey","raw","sampleValueFromSource","source","shapeLookupValue","mapped","u","one","lookupEntriesFromMapping","mapping","lookupRefFromEntries","key","rawValue","entries","entry","ref","lookupRefFromTable","lookups","table","propertyName","rawKey","resolveLookupMapped","fromEntries","withLookupEntries","edge","_lookup","rest","stripLookup","normalizeMime","contentType","classFromMime","mime","pathFromUrl","trimmed","url","classFromPath","pathname","classifyUrl","input","fromMime","looksLikeUrl","v","value","RESOLVE_EXTRACT_SUFFIX","RESOLVE_FILE_SUFFIX","contentTypeFromMeta$1","meta","ct","mediaClassFromSource","metaClass","isUrlCandidate","parseResolvedSourceId","sourceId","normalizeMappingFromSourceId","parsed","resolvedSourceId","job","originId","buildResolvedSourceNodes","out","sources","existing","s","mediaClass","extractId","fileId","resolveMappingSource","byId","direct","derived","coerceValue","dataType","d","coerceResolved","urlFromSource","contentTypeFromSource","classFromSource","c","applyLookupEdge","applyMapping","byName","targets","t","properties","mappings","result","options","applyMappingAsync","errors","ctx","resolved","err","isPresentEdge","omitEmptySourceId","_sourceId","isDeriveKeepOnClear","prev","clearSourceKeepDerive","withDeriveSpec","spec","_derive","withAssembleBlocks","applyResolveToEdge","base","nextResolve","withPreservedExtras","stripLookupUnlessLookup","next","FULL_DOC_PROP_NAMES","HTML_PROP_NAMES","IMAGE_PROP_ALIASES","FILE_PROP_ALIASES","URL_PROP_ALIASES","normalizeName","name","namesMatch","na","a","nb","b","FAN_OUT_ALIASES","fanOutAliasesForSource","labelKey","idKey","contentTypeFromMeta","mediaClassOf","isRawUrlSource","isHtmlLikeTarget","n","p","isRichMediaTarget","isUrlOnlyTarget","findImageTarget","usedProps","findFileTarget","findHtmlTarget","alias","autoMap","usedSources","baseSources","fullSource","fullDocMatch","rssAliases","htmlTarget","fanOutAliases","imageTarget","fileTarget","aliasKeys","match","htmlStillFree","linkSource"],"sources":["../src/relationLookup.ts","../src/classifyUrl.ts","../src/resolvedSources.ts","../src/applyMapping.ts","../src/edgeMapping.ts","../src/autoMap.ts"],"sourcesContent":["import type {\n FieldMapping,\n LookupEntry,\n MappingLookups,\n SourceNode,\n TargetProperty,\n} from './types'\n\n/**\n * True when the target expects a Seed relation uid (or list of uids)\n * rather than a copied scalar string.\n */\nexport function isRelationLookupTarget(target: TargetProperty): boolean {\n if (target.dataType === 'Relation') return true\n if (target.dataType === 'List') {\n return target.refValueType === 'Relation' || Boolean(target.ref)\n }\n return false\n}\n\n/** Trim and collapse internal whitespace for lookup dictionary keys. */\nexport function normalizeLookupKey(raw: string): string {\n return raw.replace(/\\s+/g, ' ').trim()\n}\n\n/** Normalized sample string for a source node (value, then label). */\nexport function sampleValueFromSource(source: SourceNode | undefined): string {\n if (!source) return ''\n return normalizeLookupKey(source.value || source.label)\n}\n\n/**\n * Shape a looked-up uid value for the target dataType.\n * Relation → single string; List → string[].\n */\nexport function shapeLookupValue(\n mapped: string | string[],\n target: TargetProperty,\n): string | string[] {\n if (target.dataType === 'List') {\n if (Array.isArray(mapped)) {\n return mapped.map((u) => String(u).trim()).filter(Boolean)\n }\n const one = String(mapped).trim()\n return one ? [one] : []\n }\n // Relation (or any non-List lookup target): single uid\n if (Array.isArray(mapped)) {\n return String(mapped[0] ?? '').trim()\n }\n return String(mapped).trim()\n}\n\n/** Entries stored on a lookup edge. Missing `lookup` is an empty assignment. */\nexport function lookupEntriesFromMapping(\n mapping: FieldMapping | undefined,\n): LookupEntry[] {\n return mapping?.lookup?.entries ?? []\n}\n\n/**\n * First entry whose normalized `value` matches `rawValue`.\n * Empty / whitespace-only refs are ignored.\n */\nexport function lookupRefFromEntries(\n entries: LookupEntry[] | undefined,\n rawValue: string,\n): string | undefined {\n const key = normalizeLookupKey(rawValue)\n if (!key || !entries?.length) return undefined\n for (const entry of entries) {\n if (normalizeLookupKey(entry.value) !== key) continue\n const ref = String(entry.ref ?? '').trim()\n if (ref) return ref\n }\n return undefined\n}\n\n/**\n * @deprecated Document-level table. Prefer `lookupRefFromEntries`.\n */\nexport function lookupRefFromTable(\n lookups: MappingLookups | undefined,\n propertyName: string,\n rawKey: string,\n): string | string[] | undefined {\n if (!lookups) return undefined\n const table = lookups[propertyName]\n if (!table) return undefined\n if (Object.prototype.hasOwnProperty.call(table, rawKey)) {\n return table[rawKey]\n }\n return undefined\n}\n\n/**\n * Resolve a lookup ref: edge entries first, then deprecated document table.\n */\nexport function resolveLookupMapped(\n mapping: FieldMapping,\n rawValue: string,\n lookups?: MappingLookups,\n): string | string[] | undefined {\n const key = normalizeLookupKey(rawValue)\n const fromEntries = lookupRefFromEntries(mapping.lookup?.entries, key)\n if (fromEntries !== undefined) return fromEntries\n return lookupRefFromTable(lookups, mapping.propertyName, key)\n}\n\nexport function withLookupEntries(\n edge: FieldMapping,\n entries: LookupEntry[],\n): FieldMapping {\n if (entries.length === 0) {\n if (!edge.lookup) return edge\n const { lookup: _lookup, ...rest } = edge\n return rest\n }\n return { ...edge, lookup: { entries } }\n}\n\n/** Drop `lookup` when the edge is no longer a lookup job. */\nexport function stripLookup(edge: FieldMapping): FieldMapping {\n if (!edge.lookup) return edge\n const { lookup: _lookup, ...rest } = edge\n return rest\n}\n","import type { UrlMediaClass } from './types'\n\nexport type ClassifyUrlInput = {\n url: string\n contentType?: string | null\n}\n\nfunction normalizeMime(contentType: string): string {\n return contentType.split(';')[0]?.trim().toLowerCase() ?? ''\n}\n\nfunction classFromMime(mime: string): UrlMediaClass | null {\n if (!mime) return null\n if (mime.startsWith('image/')) return 'image'\n if (mime.startsWith('audio/')) return 'audio'\n if (mime.startsWith('video/')) return 'video'\n if (\n mime === 'text/html' ||\n mime === 'application/xhtml+xml' ||\n mime === 'application/xhtml'\n ) {\n return 'html'\n }\n return null\n}\n\nfunction pathFromUrl(url: string): string {\n const trimmed = url.trim()\n try {\n const u = new URL(trimmed)\n return u.pathname.toLowerCase()\n } catch {\n const noQuery = trimmed.split('?')[0]?.split('#')[0] ?? trimmed\n return noQuery.toLowerCase()\n }\n}\n\nfunction classFromPath(pathname: string): UrlMediaClass {\n if (/\\.(html?|xhtml|php|asp|aspx|jsp)$/i.test(pathname)) return 'html'\n if (/\\.(jpe?g|png|gif|webp|avif|svg|bmp|ico|tiff?)$/i.test(pathname)) {\n return 'image'\n }\n if (/\\.(mp3|m4a|aac|ogg|oga|opus|wav|flac|aiff?)$/i.test(pathname)) {\n return 'audio'\n }\n if (/\\.(mp4|m4v|webm|ogv|mov|avi|mkv)$/i.test(pathname)) return 'video'\n return 'unknown'\n}\n\n/**\n * Pure MIME / URL-shape classifier for import mapping.\n * Prefer `contentType` when present; fall back to path extension.\n * No I/O. Distinct from `@seedprotocol/sdk` `classifyMediaRef` (Seed ref identity).\n */\nexport function classifyUrl(input: ClassifyUrlInput): UrlMediaClass {\n const url = typeof input.url === 'string' ? input.url.trim() : ''\n if (!url) return 'unknown'\n\n if (input.contentType) {\n const fromMime = classFromMime(normalizeMime(String(input.contentType)))\n if (fromMime) return fromMime\n }\n\n return classFromPath(pathFromUrl(url))\n}\n\n/** True when the string looks like an absolute http(s) / blob / data URL. */\nexport function looksLikeUrl(value: string): boolean {\n const v = value.trim().toLowerCase()\n return (\n v.startsWith('http://') ||\n v.startsWith('https://') ||\n v.startsWith('blob:') ||\n v.startsWith('data:')\n )\n}\n","import { classifyUrl, looksLikeUrl } from './classifyUrl'\nimport type {\n FieldMapping,\n ResolveJob,\n SourceNode,\n UrlMediaClass,\n} from './types'\n\nexport const RESOLVE_EXTRACT_SUFFIX = '@extract'\nexport const RESOLVE_FILE_SUFFIX = '@file'\n\nfunction contentTypeFromMeta(meta?: Record<string, unknown>): string | undefined {\n if (!meta) return undefined\n const ct = meta.contentType ?? meta.type\n return typeof ct === 'string' && ct.trim() ? ct.trim() : undefined\n}\n\nfunction mediaClassFromSource(source: SourceNode): UrlMediaClass {\n const metaClass = source.meta?.class\n if (\n metaClass === 'html' ||\n metaClass === 'image' ||\n metaClass === 'audio' ||\n metaClass === 'video' ||\n metaClass === 'unknown'\n ) {\n return metaClass\n }\n const url =\n typeof source.meta?.url === 'string' && source.meta.url.trim()\n ? source.meta.url.trim()\n : source.value\n return classifyUrl({\n url,\n contentType: contentTypeFromMeta(source.meta),\n })\n}\n\nfunction isUrlCandidate(source: SourceNode): boolean {\n if (source.kind === 'resolved') return false\n if (source.kind === 'full' || source.kind === 'section') return false\n const url =\n typeof source.meta?.url === 'string' && source.meta.url.trim()\n ? source.meta.url.trim()\n : source.value\n return looksLikeUrl(url)\n}\n\n/**\n * Parse a package-owned derived source id (`origin@extract` / `origin@file`).\n */\nexport function parseResolvedSourceId(\n sourceId: string,\n): { originId: string; resolve: ResolveJob } | null {\n if (sourceId.endsWith(RESOLVE_EXTRACT_SUFFIX)) {\n return {\n originId: sourceId.slice(0, -RESOLVE_EXTRACT_SUFFIX.length),\n resolve: 'extract',\n }\n }\n if (sourceId.endsWith(RESOLVE_FILE_SUFFIX)) {\n return {\n originId: sourceId.slice(0, -RESOLVE_FILE_SUFFIX.length),\n resolve: 'file',\n }\n }\n return null\n}\n\n/**\n * Normalize a UI selection (possibly a derived `@extract` / `@file` node)\n * into a persistable FieldMapping with `resolve` on the origin source.\n */\nexport function normalizeMappingFromSourceId(\n sourceId: string,\n propertyName: string,\n): FieldMapping {\n const parsed = parseResolvedSourceId(sourceId)\n if (!parsed) {\n return { sourceId, propertyName }\n }\n return {\n sourceId: parsed.originId,\n propertyName,\n resolve: parsed.resolve,\n }\n}\n\n/**\n * Stable display id for a derived resolve candidate.\n */\nexport function resolvedSourceId(originId: string, job: ResolveJob): string {\n if (job === 'extract') return `${originId}${RESOLVE_EXTRACT_SUFFIX}`\n if (job === 'file') return `${originId}${RESOLVE_FILE_SUFFIX}`\n return originId\n}\n\n/**\n * Expand URL-classifiable sources with package-owned extract/file candidates\n * for FieldMapper / autoMap. Original nodes are preserved.\n *\n * Prefer mapping derived nodes in the UI; persist via\n * `normalizeMappingFromSourceId` so documents store origin + `resolve`.\n */\nexport function buildResolvedSourceNodes(sources: SourceNode[]): SourceNode[] {\n const out: SourceNode[] = [...sources]\n const existing = new Set(sources.map((s) => s.id))\n\n for (const source of sources) {\n if (!isUrlCandidate(source)) continue\n\n const url =\n typeof source.meta?.url === 'string' && source.meta.url.trim()\n ? source.meta.url.trim()\n : source.value.trim()\n const contentType = contentTypeFromMeta(source.meta)\n const mediaClass = mediaClassFromSource(source)\n\n const extractId = resolvedSourceId(source.id, 'extract')\n if (!existing.has(extractId)) {\n out.push({\n id: extractId,\n label: `${source.label} → extract HTML`,\n kind: 'resolved',\n value: url,\n meta: {\n originId: source.id,\n resolve: 'extract' satisfies ResolveJob,\n class: 'html' satisfies UrlMediaClass,\n contentType,\n url,\n },\n })\n existing.add(extractId)\n }\n\n const fileId = resolvedSourceId(source.id, 'file')\n if (!existing.has(fileId)) {\n out.push({\n id: fileId,\n label: `${source.label} → file`,\n kind: 'resolved',\n value: url,\n meta: {\n originId: source.id,\n resolve: 'file' satisfies ResolveJob,\n class: mediaClass,\n contentType,\n url,\n },\n })\n existing.add(fileId)\n }\n }\n\n return out\n}\n\n/**\n * Look up the origin source for a mapping (handles resolve edges).\n */\nexport function resolveMappingSource(\n sources: SourceNode[],\n mapping: FieldMapping,\n): SourceNode | undefined {\n const byId = new Map(sources.map((s) => [s.id, s]))\n if (!mapping.sourceId) return undefined\n const direct = byId.get(mapping.sourceId)\n if (direct) return direct\n if (mapping.resolve) {\n const derived = byId.get(resolvedSourceId(mapping.sourceId, mapping.resolve))\n if (derived) return derived\n }\n return undefined\n}\n","import {\n isRelationLookupTarget,\n normalizeLookupKey,\n resolveLookupMapped,\n shapeLookupValue,\n} from './relationLookup'\nimport { resolveMappingSource } from './resolvedSources'\nimport type {\n ApplyMappingAsyncResult,\n FieldMapping,\n MappingLookups,\n PropertyBag,\n ResolveCallback,\n ResolveContext,\n SourceNode,\n TargetProperty,\n UrlMediaClass,\n} from './types'\n\n/**\n * Coerce a raw string value to the Seed model property dataType.\n */\nexport function coerceValue(rawValue: string, dataType: string): unknown {\n if (dataType === 'Number') {\n return parseFloat(String(rawValue)) || 0\n }\n if (dataType === 'Boolean') {\n return (\n rawValue === 'true' ||\n rawValue === '1' ||\n String(rawValue).toLowerCase() === 'yes'\n )\n }\n if (dataType === 'Json') {\n try {\n return JSON.parse(rawValue)\n } catch {\n return rawValue\n }\n }\n if (dataType === 'Date') {\n const d = new Date(String(rawValue))\n return Number.isNaN(d.getTime()) ? rawValue : d.getTime()\n }\n return String(rawValue ?? '')\n}\n\nfunction coerceResolved(raw: unknown, dataType: string): unknown {\n if (typeof raw === 'string') {\n return coerceValue(raw, dataType)\n }\n if (raw == null) {\n return coerceValue('', dataType)\n }\n // Host may return seed refs, blobs, or already-shaped values for File/Image.\n if (\n dataType === 'Image' ||\n dataType === 'File' ||\n dataType === 'Relation' ||\n dataType === 'List' ||\n dataType === 'Json'\n ) {\n return raw\n }\n return coerceValue(String(raw), dataType)\n}\n\nfunction urlFromSource(source: SourceNode): string {\n if (typeof source.meta?.url === 'string' && source.meta.url.trim()) {\n return source.meta.url.trim()\n }\n return (source.value || source.label).trim()\n}\n\nfunction contentTypeFromSource(source: SourceNode): string | undefined {\n const ct = source.meta?.contentType ?? source.meta?.type\n return typeof ct === 'string' && ct.trim() ? ct.trim() : undefined\n}\n\nfunction classFromSource(source: SourceNode): UrlMediaClass | undefined {\n const c = source.meta?.class\n if (\n c === 'html' ||\n c === 'image' ||\n c === 'audio' ||\n c === 'video' ||\n c === 'unknown'\n ) {\n return c\n }\n return undefined\n}\n\nfunction applyLookupEdge(\n mapping: FieldMapping,\n source: SourceNode,\n target: TargetProperty,\n lookups: MappingLookups | undefined,\n): { value: string | string[] } | { unmatched: string } {\n const rawValue = normalizeLookupKey(source.value || source.label)\n const mapped = resolveLookupMapped(mapping, rawValue, lookups)\n if (mapped === undefined) {\n return { unmatched: rawValue }\n }\n return { value: shapeLookupValue(mapped, target) }\n}\n\n/**\n * Apply field mappings to produce a property bag for createItem / publish.\n * Missing sources or unknown target properties are skipped (no throw).\n * `resolve: 'extract' | 'file' | 'derive' | 'assemble'` edges are skipped.\n * Use `applyMappingAsync` for extract/file. Derive/assemble stay host-applied.\n * `resolve: 'lookup'` is applied from stored entries (or deprecated document lookups).\n */\nexport function applyMapping(\n sources: SourceNode[],\n mappings: FieldMapping[],\n targets: TargetProperty[],\n options?: { lookups?: MappingLookups },\n): PropertyBag {\n const byId = new Map(sources.map((s) => [s.id, s]))\n const byName = new Map(targets.map((t) => [t.name, t]))\n const properties: PropertyBag = {}\n\n for (const mapping of mappings) {\n if (mapping.resolve && mapping.resolve !== 'lookup') continue\n\n const source = mapping.sourceId ? byId.get(mapping.sourceId) : undefined\n const target = byName.get(mapping.propertyName)\n if (!source || !target) continue\n\n if (mapping.resolve === 'lookup') {\n const result = applyLookupEdge(mapping, source, target, options?.lookups)\n if ('value' in result) {\n properties[mapping.propertyName] = result.value\n }\n continue\n }\n\n // Never copy a raw string onto relation / list-of-relation targets.\n if (isRelationLookupTarget(target)) continue\n\n const raw = source.value || source.label\n properties[mapping.propertyName] = coerceValue(raw, target.dataType)\n }\n\n return properties\n}\n\nexport type ApplyMappingAsyncOptions = {\n /** Required for extract/file edges. Not called for lookup. */\n resolve?: ResolveCallback\n /**\n * String → seed uid dictionaries keyed by property name.\n * @deprecated Prefer `FieldMapping.lookup.entries`. Read as a fallback only.\n */\n lookups?: MappingLookups\n}\n\n/**\n * Async apply: copy+coerce plain edges; apply lookup entries; for extract/file\n * call the host callback then coerce. `derive` / `assemble` are skipped —\n * host apply stays host-owned. Partial success — failed resolve edges\n * are listed in `errors` and omitted from `properties`.\n */\nexport async function applyMappingAsync(\n sources: SourceNode[],\n mappings: FieldMapping[],\n targets: TargetProperty[],\n options: ApplyMappingAsyncOptions = {},\n): Promise<ApplyMappingAsyncResult> {\n const byName = new Map(targets.map((t) => [t.name, t]))\n const properties: PropertyBag = {}\n const errors: ApplyMappingAsyncResult['errors'] = []\n\n for (const mapping of mappings) {\n const target = byName.get(mapping.propertyName)\n if (!target) continue\n\n if (mapping.resolve === 'derive' || mapping.resolve === 'assemble') {\n continue\n }\n\n if (!mapping.resolve) {\n const source = mapping.sourceId\n ? sources.find((s) => s.id === mapping.sourceId)\n : undefined\n if (!source) continue\n if (isRelationLookupTarget(target)) continue\n const raw = source.value || source.label\n properties[mapping.propertyName] = coerceValue(raw, target.dataType)\n continue\n }\n\n if (mapping.resolve === 'lookup') {\n const source = mapping.sourceId\n ? sources.find((s) => s.id === mapping.sourceId)\n : undefined\n if (!source) {\n errors.push({\n sourceId: mapping.sourceId,\n propertyName: mapping.propertyName,\n resolve: 'lookup',\n message: `Source not found: ${mapping.sourceId}`,\n })\n continue\n }\n\n const result = applyLookupEdge(mapping, source, target, options.lookups)\n if ('value' in result) {\n properties[mapping.propertyName] = result.value\n } else {\n errors.push({\n sourceId: mapping.sourceId,\n propertyName: mapping.propertyName,\n resolve: 'lookup',\n message: `No lookup entry for \"${result.unmatched}\"`,\n })\n }\n continue\n }\n\n const source = resolveMappingSource(sources, mapping)\n if (!source) {\n errors.push({\n sourceId: mapping.sourceId,\n propertyName: mapping.propertyName,\n resolve: mapping.resolve,\n message: `Source not found: ${mapping.sourceId}`,\n })\n continue\n }\n\n if (!options.resolve) {\n errors.push({\n sourceId: mapping.sourceId,\n propertyName: mapping.propertyName,\n resolve: mapping.resolve,\n message: `No resolve callback for ${mapping.resolve}`,\n })\n continue\n }\n\n const ctx: ResolveContext = {\n job: mapping.resolve,\n url: urlFromSource(source),\n source,\n target,\n contentType: contentTypeFromSource(source),\n class: classFromSource(source),\n }\n\n try {\n const resolved = await options.resolve(ctx)\n properties[mapping.propertyName] = coerceResolved(resolved, target.dataType)\n } catch (err) {\n errors.push({\n sourceId: mapping.sourceId,\n propertyName: mapping.propertyName,\n resolve: mapping.resolve,\n message: err instanceof Error ? err.message : String(err),\n })\n }\n }\n\n return { properties, errors }\n}\n","import { stripLookup } from './relationLookup'\nimport type { AssembleSpec, DeriveSpec, FieldMapping, ResolveJob } from './types'\n\n/** True when the edge covers a property for coverage / row presence. */\nexport function isPresentEdge(mapping: FieldMapping): boolean {\n if (!mapping.propertyName) return false\n if (mapping.sourceId) return true\n return mapping.resolve === 'derive'\n}\n\n/** Drop empty `sourceId` so derive-only edges do not persist `''`. */\nexport function omitEmptySourceId(edge: FieldMapping): FieldMapping {\n if (edge.sourceId) return edge\n const { sourceId: _sourceId, ...rest } = edge\n return rest\n}\n\nexport function isDeriveKeepOnClear(prev: FieldMapping): boolean {\n return prev.resolve === 'derive' || Boolean(prev.derive)\n}\n\n/** Source-less derive edge after the origin is cleared. */\nexport function clearSourceKeepDerive(prev: FieldMapping): FieldMapping {\n return omitEmptySourceId({\n propertyName: prev.propertyName,\n resolve: 'derive',\n ...(prev.derive ? { derive: prev.derive } : {}),\n })\n}\n\nexport function withDeriveSpec(\n edge: FieldMapping,\n spec: DeriveSpec | null,\n): FieldMapping {\n if (!spec) {\n if (!edge.derive) return omitEmptySourceId(edge)\n const { derive: _derive, ...rest } = edge\n return omitEmptySourceId(rest)\n }\n return omitEmptySourceId({ ...edge, derive: spec })\n}\n\nexport function withAssembleBlocks(\n edge: FieldMapping,\n blocks: string[],\n): FieldMapping {\n return omitEmptySourceId({ ...edge, assemble: { blocks } })\n}\n\n/**\n * Next edge after a transform change.\n * Copy keeps `derive` (fallback). Assemble keeps `assemble`. Lookup keeps `lookup`.\n */\nexport function applyResolveToEdge(\n prev: FieldMapping,\n nextResolve: ResolveJob | null,\n): FieldMapping {\n const base: FieldMapping = {\n propertyName: prev.propertyName,\n ...(prev.sourceId ? { sourceId: prev.sourceId } : {}),\n }\n\n if (!nextResolve) {\n if (!prev.sourceId && isDeriveKeepOnClear(prev)) {\n return clearSourceKeepDerive(prev)\n }\n if (prev.derive) base.derive = prev.derive\n return omitEmptySourceId(base)\n }\n\n if (nextResolve === 'derive') {\n return omitEmptySourceId({\n ...base,\n resolve: 'derive',\n ...(prev.derive ? { derive: prev.derive } : {}),\n })\n }\n\n if (nextResolve === 'assemble') {\n return omitEmptySourceId({\n ...base,\n resolve: 'assemble',\n ...(prev.assemble ? { assemble: prev.assemble } : {}),\n })\n }\n\n if (nextResolve === 'lookup') {\n return omitEmptySourceId({\n ...base,\n resolve: 'lookup',\n ...(prev.lookup ? { lookup: prev.lookup } : {}),\n })\n }\n\n return omitEmptySourceId({ ...base, resolve: nextResolve })\n}\n\n/**\n * Copy prior `derive` / `assemble` onto a newly connected origin\n * when the next edge did not already set a conflicting job.\n */\nexport function withPreservedExtras(\n next: FieldMapping,\n prev: FieldMapping | undefined,\n): FieldMapping {\n if (!prev) return omitEmptySourceId(stripLookupUnlessLookup(next))\n let out: FieldMapping = { ...next }\n\n if (!out.resolve) {\n if (prev.resolve === 'assemble') {\n out = {\n ...out,\n resolve: 'assemble',\n ...(prev.assemble ? { assemble: prev.assemble } : {}),\n }\n } else if (prev.resolve === 'derive') {\n out = { ...out, resolve: 'derive' }\n }\n }\n\n if (prev.derive && (!out.resolve || out.resolve === 'derive')) {\n out = { ...out, derive: out.derive ?? prev.derive }\n }\n\n if (out.resolve === 'assemble' && prev.assemble && !out.assemble) {\n out = { ...out, assemble: prev.assemble }\n }\n\n return omitEmptySourceId(stripLookupUnlessLookup(out))\n}\n\nfunction stripLookupUnlessLookup(edge: FieldMapping): FieldMapping {\n return edge.resolve === 'lookup' ? edge : stripLookup(edge)\n}\n","import { classifyUrl, looksLikeUrl } from './classifyUrl'\nimport { isRelationLookupTarget } from './relationLookup'\nimport type { FieldMapping, SourceNode, TargetProperty, UrlMediaClass } from './types'\n\nconst FULL_DOC_PROP_NAMES = ['text', 'content', 'body', 'fulltext', 'markdown']\nconst HTML_PROP_NAMES = ['html', 'content', 'body', 'text']\nconst IMAGE_PROP_ALIASES = [\n 'featureimage',\n 'feature_image',\n 'image',\n 'cover',\n 'coverimage',\n]\nconst FILE_PROP_ALIASES = ['file', 'audio', 'video', 'enclosure', 'attachment', 'media']\nconst URL_PROP_ALIASES = ['importurl', 'canonicalurl', 'url', 'link', 'permalink']\n\nfunction normalizeName(name: string): string {\n return name.toLowerCase().replace(/\\s+/g, '').replace(/[:_-]/g, '')\n}\n\nfunction namesMatch(a: string, b: string): boolean {\n const na = normalizeName(a)\n const nb = normalizeName(b)\n return na === nb || na.includes(nb) || nb.includes(na)\n}\n\n/**\n * Sources that fan out to every unused target matching any alias.\n * Keys are normalized source label/id fragments.\n */\nconst FAN_OUT_ALIASES: Record<string, string[]> = {\n link: URL_PROP_ALIASES,\n url: URL_PROP_ALIASES,\n}\n\nfunction fanOutAliasesForSource(source: SourceNode): string[] | undefined {\n if (source.kind === 'resolved') return undefined\n const labelKey = normalizeName(source.label)\n const idKey = normalizeName(source.id.replace(/^rss-/, '').replace(/^fm-/, ''))\n return FAN_OUT_ALIASES[labelKey] ?? FAN_OUT_ALIASES[idKey]\n}\n\nfunction contentTypeFromMeta(meta?: Record<string, unknown>): string | undefined {\n if (!meta) return undefined\n const ct = meta.contentType ?? meta.type\n return typeof ct === 'string' && ct.trim() ? ct.trim() : undefined\n}\n\nfunction mediaClassOf(source: SourceNode): UrlMediaClass {\n const metaClass = source.meta?.class\n if (\n metaClass === 'html' ||\n metaClass === 'image' ||\n metaClass === 'audio' ||\n metaClass === 'video' ||\n metaClass === 'unknown'\n ) {\n return metaClass\n }\n const url =\n typeof source.meta?.url === 'string' && source.meta.url.trim()\n ? source.meta.url.trim()\n : source.value\n return classifyUrl({\n url,\n contentType: contentTypeFromMeta(source.meta),\n })\n}\n\nfunction isRawUrlSource(source: SourceNode): boolean {\n if (source.kind === 'resolved') return false\n if (source.kind === 'full' || source.kind === 'section') return false\n // content:encoded / description HTML bodies are not \"raw URL\" sources\n const labelKey = normalizeName(source.label)\n if (\n labelKey === 'contentencoded' ||\n labelKey === 'content' ||\n labelKey === 'description' ||\n labelKey === 'summary' ||\n labelKey === 'title'\n ) {\n return false\n }\n const url =\n typeof source.meta?.url === 'string' && source.meta.url.trim()\n ? source.meta.url.trim()\n : source.value\n return looksLikeUrl(url) && !url.trim().includes('<')\n}\n\nfunction isHtmlLikeTarget(target: TargetProperty): boolean {\n const n = normalizeName(target.name)\n return (\n HTML_PROP_NAMES.some((p) => namesMatch(n, p)) ||\n target.dataType === 'Html' ||\n target.dataType === 'Text'\n )\n}\n\nfunction isRichMediaTarget(target: TargetProperty): boolean {\n const n = normalizeName(target.name)\n if (\n target.dataType === 'Image' ||\n target.dataType === 'File' ||\n target.dataType === 'Relation'\n ) {\n return (\n IMAGE_PROP_ALIASES.some((a) => namesMatch(n, a)) ||\n FILE_PROP_ALIASES.some((a) => namesMatch(n, a)) ||\n target.dataType === 'Image' ||\n target.dataType === 'File'\n )\n }\n return (\n IMAGE_PROP_ALIASES.some((a) => namesMatch(n, a)) ||\n FILE_PROP_ALIASES.some((a) => namesMatch(n, a))\n )\n}\n\nfunction isUrlOnlyTarget(target: TargetProperty): boolean {\n const n = normalizeName(target.name)\n return URL_PROP_ALIASES.some((a) => namesMatch(n, a))\n}\n\nfunction findImageTarget(\n targets: TargetProperty[],\n usedProps: Set<string>,\n): TargetProperty | undefined {\n return targets.find((p) => {\n if (usedProps.has(p.name)) return false\n const n = normalizeName(p.name)\n return (\n p.dataType === 'Image' ||\n IMAGE_PROP_ALIASES.some((a) => namesMatch(n, a))\n )\n })\n}\n\nfunction findFileTarget(\n targets: TargetProperty[],\n usedProps: Set<string>,\n mediaClass: UrlMediaClass,\n): TargetProperty | undefined {\n return targets.find((p) => {\n if (usedProps.has(p.name)) return false\n const n = normalizeName(p.name)\n if (mediaClass === 'audio' && namesMatch(n, 'audio')) return true\n if (mediaClass === 'video' && namesMatch(n, 'video')) return true\n return p.dataType === 'File' || FILE_PROP_ALIASES.some((a) => namesMatch(n, a))\n })\n}\n\nfunction findHtmlTarget(\n targets: TargetProperty[],\n usedProps: Set<string>,\n): TargetProperty | undefined {\n return targets.find((p) => {\n if (usedProps.has(p.name)) return false\n const n = normalizeName(p.name)\n return (\n p.dataType === 'Html' ||\n HTML_PROP_NAMES.some((alias) => namesMatch(n, alias))\n )\n })\n}\n\n/**\n * Heuristic auto-map: full-document / full-text first, then RSS aliases,\n * URL fan-out (copy only), media file/extract jobs, then fuzzy name match.\n * Never maps a raw URL onto html / Image / File without `resolve`.\n */\nexport function autoMap(\n sources: SourceNode[],\n targets: TargetProperty[],\n): FieldMapping[] {\n const mappings: FieldMapping[] = []\n const usedProps = new Set<string>()\n const usedSources = new Set<string>()\n\n // Skip derived resolve nodes in the main pass; we emit resolve jobs from origins.\n const baseSources = sources.filter((s) => s.kind !== 'resolved')\n\n const fullSource = baseSources.find((s) => s.kind === 'full')\n if (fullSource) {\n const fullDocMatch = targets.find((p) =>\n FULL_DOC_PROP_NAMES.includes(p.name.toLowerCase()),\n )\n if (fullDocMatch) {\n mappings.push({\n sourceId: fullSource.id,\n propertyName: fullDocMatch.name,\n })\n usedProps.add(fullDocMatch.name)\n usedSources.add(fullSource.id)\n }\n }\n\n const rssAliases: Record<string, string[]> = {\n title: ['title', 'name', 'headline'],\n 'content:encoded': ['html', 'content', 'body', 'text'],\n content: ['html', 'content', 'body', 'text'],\n description: ['summary', 'description', 'excerpt'],\n summary: ['summary', 'description', 'excerpt'],\n featureimage: ['featureimage', 'feature_image', 'image', 'cover'],\n feature_image: ['featureimage', 'feature_image', 'image', 'cover'],\n link: ['url', 'link', 'permalink'],\n creator: ['author', 'authors', 'creator', 'byline'],\n author: ['author', 'authors', 'creator', 'byline'],\n }\n\n // Prefer full-text RSS → html (copy) before URL extract\n for (const source of baseSources) {\n if (usedSources.has(source.id)) continue\n const labelKey = normalizeName(source.label)\n const idKey = source.id.replace(/^rss-/, '').replace(/^fm-/, '')\n if (\n labelKey === 'contentencoded' ||\n normalizeName(idKey) === 'contentencoded' ||\n (labelKey === 'content' && source.value.includes('<'))\n ) {\n const htmlTarget = findHtmlTarget(targets, usedProps)\n if (htmlTarget) {\n mappings.push({ sourceId: source.id, propertyName: htmlTarget.name })\n usedProps.add(htmlTarget.name)\n usedSources.add(source.id)\n }\n }\n }\n\n for (const source of baseSources) {\n if (usedSources.has(source.id)) continue\n\n const fanOutAliases = fanOutAliasesForSource(source)\n if (fanOutAliases) {\n for (const target of targets) {\n if (usedProps.has(target.name)) continue\n if (isRichMediaTarget(target) && !isUrlOnlyTarget(target)) continue\n if (isHtmlLikeTarget(target) && !isUrlOnlyTarget(target)) {\n // Do not fan raw link into html — handled later as extract if needed\n const n = normalizeName(target.name)\n if (n === 'html' || target.dataType === 'Html') continue\n }\n const matches = fanOutAliases.some((alias) =>\n namesMatch(target.name, alias),\n )\n if (matches) {\n mappings.push({ sourceId: source.id, propertyName: target.name })\n usedProps.add(target.name)\n }\n }\n continue\n }\n\n // Media URL sources → resolve:file onto Image/File targets\n if (isRawUrlSource(source)) {\n const mediaClass = mediaClassOf(source)\n if (mediaClass === 'image') {\n const imageTarget = findImageTarget(targets, usedProps)\n if (imageTarget) {\n mappings.push({\n sourceId: source.id,\n propertyName: imageTarget.name,\n resolve: 'file',\n })\n usedProps.add(imageTarget.name)\n usedSources.add(source.id)\n continue\n }\n }\n if (mediaClass === 'audio' || mediaClass === 'video') {\n const fileTarget = findFileTarget(targets, usedProps, mediaClass)\n if (fileTarget) {\n mappings.push({\n sourceId: source.id,\n propertyName: fileTarget.name,\n resolve: 'file',\n })\n usedProps.add(fileTarget.name)\n usedSources.add(source.id)\n continue\n }\n }\n // Unknown / html-class URLs: do not map onto rich media without resolve\n // (extract handled in a later pass for link-like sources)\n }\n\n const labelKey = normalizeName(source.label)\n const idKey = source.id.replace(/^rss-/, '').replace(/^fm-/, '')\n const aliasKeys = [\n ...(rssAliases[source.label] ?? []),\n ...(rssAliases[idKey] ?? []),\n ...(rssAliases[labelKey] ?? []),\n ]\n\n let match: TargetProperty | undefined\n\n for (const alias of aliasKeys) {\n match = targets.find(\n (p) => !usedProps.has(p.name) && namesMatch(p.name, alias),\n )\n if (match) break\n }\n\n if (!match) {\n match = targets.find(\n (p) =>\n !usedProps.has(p.name) &&\n (namesMatch(p.name, source.label) || namesMatch(p.name, idKey)),\n )\n }\n\n if (match) {\n // Block raw URL → html / image / file without resolve\n if (\n isRawUrlSource(source) &&\n (isHtmlLikeTarget(match) || isRichMediaTarget(match)) &&\n !isUrlOnlyTarget(match)\n ) {\n // skip — extract / file jobs handled separately\n } else if (\n isRawUrlSource(source) &&\n mediaClassOf(source) === 'image' &&\n isRichMediaTarget(match)\n ) {\n mappings.push({\n sourceId: source.id,\n propertyName: match.name,\n resolve: 'file',\n })\n usedProps.add(match.name)\n usedSources.add(source.id)\n } else if (isRelationLookupTarget(match)) {\n mappings.push({\n sourceId: source.id,\n propertyName: match.name,\n resolve: 'lookup',\n })\n usedProps.add(match.name)\n usedSources.add(source.id)\n } else {\n mappings.push({ sourceId: source.id, propertyName: match.name })\n usedProps.add(match.name)\n usedSources.add(source.id)\n }\n }\n }\n\n // If no HTML body filled, prefer extract from link/permalink\n const htmlStillFree = findHtmlTarget(targets, usedProps)\n if (htmlStillFree) {\n const linkSource = baseSources.find((s) => {\n if (usedSources.has(s.id) && !fanOutAliasesForSource(s)) return false\n const labelKey = normalizeName(s.label)\n const idKey = normalizeName(s.id.replace(/^rss-/, '').replace(/^fm-/, ''))\n return (\n (labelKey === 'link' ||\n labelKey === 'url' ||\n idKey === 'link' ||\n idKey === 'url' ||\n labelKey === 'permalink') &&\n looksLikeUrl(s.value)\n )\n })\n if (linkSource) {\n mappings.push({\n sourceId: linkSource.id,\n propertyName: htmlStillFree.name,\n resolve: 'extract',\n })\n usedProps.add(htmlStillFree.name)\n }\n }\n\n return mappings\n}\n"],"mappings":"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"}
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../src/adapters/markdown.ts","../src/adapters/rss.ts"],"sourcesContent":["import type { SourceNode } from '../types'\n\nexport const SECTION_FULL_ID = 'section-full'\n\ntype FrontmatterField = {\n id: string\n key: string\n value: string\n valueType: 'string' | 'boolean' | 'array'\n}\n\ntype ParsedMarkdown = {\n frontmatter: FrontmatterField[]\n body: string\n}\n\ntype MarkdownSection = {\n id: string\n heading: string\n level: number\n content: string\n}\n\n/**\n * Parse YAML-like frontmatter (flat keys only) and body.\n * Mirrors desktop MarkdownMapper limits: no nested YAML.\n */\nexport function parseMarkdownWithFrontmatter(\n markdownContent: string,\n): ParsedMarkdown {\n try {\n const match = markdownContent.match(\n /^---\\r?\\n([\\s\\S]*?)\\r?\\n---\\r?\\n?([\\s\\S]*)$/,\n )\n if (!match) return { frontmatter: [], body: markdownContent }\n\n const yamlBlock = match[1] ?? ''\n const body = (match[2] ?? '').trimStart()\n const frontmatter: FrontmatterField[] = []\n const data: Record<string, unknown> = {}\n\n for (const line of yamlBlock.split('\\n')) {\n const keyMatch = line.match(/^([a-zA-Z_][a-zA-Z0-9_-]*):\\s*(.*)$/)\n if (!keyMatch) continue\n\n const key = keyMatch[1]!\n const raw = keyMatch[2]!.trim()\n let val: unknown = raw\n\n if (raw === 'true') val = true\n else if (raw === 'false') val = false\n else if (raw === 'null' || raw === '') val = null\n else if (raw.startsWith('[') && raw.endsWith(']')) {\n try {\n val = JSON.parse(raw.replace(/'/g, '\"'))\n } catch {\n val = raw\n .slice(1, -1)\n .split(',')\n .map((s: string) => s.trim().replace(/^['\"]|['\"]$/g, ''))\n }\n } else if (raw.startsWith('\"') || raw.startsWith(\"'\")) {\n val = raw.slice(1, -1).replace(/\\\\\"/g, '\"')\n }\n\n data[key] = val\n }\n\n for (const [key, val] of Object.entries(data)) {\n let valueType: 'string' | 'boolean' | 'array' = 'string'\n let value: string\n\n if (Array.isArray(val)) {\n valueType = 'array'\n value = val\n .map((v) => (typeof v === 'object' ? JSON.stringify(v) : String(v)))\n .join(', ')\n } else if (typeof val === 'boolean') {\n valueType = 'boolean'\n value = String(val)\n } else if (val != null && typeof val === 'object') {\n value = JSON.stringify(val)\n } else {\n value = val != null ? String(val) : ''\n }\n\n frontmatter.push({\n id: `fm-${key}`,\n key,\n value,\n valueType,\n })\n }\n\n return { frontmatter, body }\n } catch {\n return { frontmatter: [], body: markdownContent }\n }\n}\n\n/**\n * Split markdown body into H1/H2 sections (###+ ignored as section breaks).\n */\nexport function parseMarkdownSections(md: string): MarkdownSection[] {\n const lines = md.split('\\n')\n const sections: MarkdownSection[] = []\n let current: MarkdownSection | null = null\n\n for (const line of lines) {\n const h2Match = line.match(/^## (.+)/)\n const h1Match = line.match(/^# (.+)/)\n\n if (h1Match) {\n if (current) sections.push(current)\n current = {\n id: `section-${sections.length}`,\n heading: h1Match[1]!,\n level: 1,\n content: '',\n }\n } else if (h2Match) {\n if (current) sections.push(current)\n current = {\n id: `section-${sections.length}`,\n heading: h2Match[1]!,\n level: 2,\n content: '',\n }\n } else if (current) {\n current.content += (current.content ? '\\n' : '') + line\n }\n }\n if (current) sections.push(current)\n return sections\n}\n\n/**\n * Convert markdown into SourceNodes for FieldMapper / applyMapping.\n * Order: frontmatter fields, full document body, then H1/H2 sections.\n */\nexport function markdownToSources(markdown: string): SourceNode[] {\n const parsed = parseMarkdownWithFrontmatter(markdown)\n const sections = parseMarkdownSections(parsed.body)\n const sources: SourceNode[] = []\n\n for (const fm of parsed.frontmatter) {\n sources.push({\n id: fm.id,\n label: fm.key,\n kind: 'frontmatter',\n value: fm.value,\n meta: { valueType: fm.valueType },\n })\n }\n\n sources.push({\n id: SECTION_FULL_ID,\n label: 'Full document',\n kind: 'full',\n value: parsed.body,\n })\n\n for (const section of sections) {\n const value =\n section.content.trim().length > 0 ? section.content.trim() : section.heading\n sources.push({\n id: section.id,\n label: section.heading,\n kind: 'section',\n value,\n meta: { level: section.level },\n })\n }\n\n return sources\n}\n","import Parser from 'rss-parser'\nimport { classifyUrl } from '../classifyUrl'\nimport type { SourceNode } from '../types'\n\nexport type ParsedRssChannel = {\n title?: string\n link?: string\n description?: string\n /** Plain serializable item records (dates become ISO strings). */\n items: Record<string, unknown>[]\n}\n\nfunction toPlainItem(item: unknown): Record<string, unknown> {\n try {\n return JSON.parse(JSON.stringify(item)) as Record<string, unknown>\n } catch {\n return { ...(item as Record<string, unknown>) }\n }\n}\n\n/**\n * Same shape and customFields as @seedprotocol/feed `parseRssString`\n * so RSS mapping stays aligned without importing feed's heavy barrel.\n * Also pulls enclosure / media:content for structured media nodes.\n */\nconst parser = new Parser({\n customFields: {\n item: [\n 'featureImage',\n 'feature_image',\n 'content:encoded',\n 'seedUid',\n 'SeedUid',\n ['media:content', 'mediaContent'],\n ['media:thumbnail', 'mediaThumbnail'],\n ],\n },\n})\n\nasync function parseRssString(xml: string): Promise<ParsedRssChannel> {\n const feed = await parser.parseString(xml)\n return {\n title: feed.title,\n link: feed.link,\n description: feed.description,\n items: (feed.items ?? []).map(toPlainItem),\n }\n}\n\nfunction coerceFieldValue(val: unknown): string | null {\n if (val == null) return null\n if (typeof val === 'string') {\n const t = val.trim()\n return t.length > 0 ? t : null\n }\n if (typeof val === 'number' || typeof val === 'boolean') {\n return String(val)\n }\n if (Array.isArray(val)) {\n try {\n return JSON.stringify(val)\n } catch {\n return null\n }\n }\n if (typeof val === 'object') {\n const obj = val as Record<string, unknown>\n if (typeof obj._ === 'string' && obj._.trim()) return obj._.trim()\n if (typeof obj.value === 'string' && obj.value.trim()) return obj.value.trim()\n try {\n return JSON.stringify(val)\n } catch {\n return null\n }\n }\n return null\n}\n\ntype MediaAttrs = {\n url: string\n contentType?: string\n length?: string\n}\n\nfunction pickMediaAttrs(raw: unknown): MediaAttrs | null {\n if (raw == null) return null\n if (typeof raw === 'string') {\n const url = raw.trim()\n return url ? { url } : null\n }\n if (typeof raw !== 'object') return null\n const obj = raw as Record<string, unknown>\n // rss-parser often nests attrs under `$`\n const dollar =\n obj.$ && typeof obj.$ === 'object'\n ? (obj.$ as Record<string, unknown>)\n : undefined\n const urlCandidate =\n (typeof obj.url === 'string' && obj.url) ||\n (typeof dollar?.url === 'string' && dollar.url) ||\n (typeof obj.link === 'string' && obj.link) ||\n null\n if (!urlCandidate || !String(urlCandidate).trim()) return null\n\n const typeRaw =\n (typeof obj.type === 'string' && obj.type) ||\n (typeof dollar?.type === 'string' && dollar.type) ||\n (typeof obj.medium === 'string' && obj.medium) ||\n undefined\n const lengthRaw =\n (typeof obj.length === 'string' && obj.length) ||\n (typeof obj.length === 'number' && String(obj.length)) ||\n (typeof dollar?.length === 'string' && dollar.length) ||\n (typeof dollar?.length === 'number' && String(dollar.length)) ||\n undefined\n\n return {\n url: String(urlCandidate).trim(),\n contentType: typeRaw ? String(typeRaw).trim() : undefined,\n length: lengthRaw ? String(lengthRaw).trim() : undefined,\n }\n}\n\nfunction mediaEntriesFromValue(raw: unknown): MediaAttrs[] {\n if (raw == null) return []\n if (Array.isArray(raw)) {\n return raw.map(pickMediaAttrs).filter((m): m is MediaAttrs => m != null)\n }\n const one = pickMediaAttrs(raw)\n return one ? [one] : []\n}\n\nconst MEDIA_KEYS = new Set([\n 'enclosure',\n 'enclosures',\n 'media:content',\n 'mediaContent',\n 'media:thumbnail',\n 'mediaThumbnail',\n])\n\nfunction pushMediaNode(\n sources: SourceNode[],\n seen: Set<string>,\n id: string,\n label: string,\n media: MediaAttrs,\n): void {\n if (seen.has(id)) return\n seen.add(id)\n const mediaClass = classifyUrl({\n url: media.url,\n contentType: media.contentType,\n })\n sources.push({\n id,\n label,\n kind: 'rssField',\n value: media.url,\n meta: {\n url: media.url,\n contentType: media.contentType,\n length: media.length,\n class: mediaClass,\n },\n })\n}\n\n/**\n * Flatten a parsed RSS/Atom item into SourceNodes (one per string-coercible key).\n * Enclosure / media:content become url + type in `meta` (not stringified objects).\n * Stable ids: `rss-{key}`, `rss-enclosure-0`, …\n */\nexport function rssItemToSources(item: Record<string, unknown>): SourceNode[] {\n const sources: SourceNode[] = []\n const seen = new Set<string>()\n\n let enclosureIndex = 0\n for (const [key, raw] of Object.entries(item)) {\n if (key === 'items' || key.startsWith('$')) continue\n\n if (MEDIA_KEYS.has(key)) {\n const entries = mediaEntriesFromValue(raw)\n for (const media of entries) {\n const id =\n key === 'enclosure' || key === 'enclosures'\n ? `rss-enclosure-${enclosureIndex}`\n : `rss-${key}-${enclosureIndex}`\n const label =\n key === 'enclosure' || key === 'enclosures'\n ? `enclosure[${enclosureIndex}]`\n : `${key}[${enclosureIndex}]`\n pushMediaNode(sources, seen, id, label, media)\n enclosureIndex += 1\n }\n continue\n }\n\n const value = coerceFieldValue(raw)\n if (value == null) continue\n if (seen.has(key)) continue\n seen.add(key)\n\n const node: SourceNode = {\n id: `rss-${key}`,\n label: key,\n kind: 'rssField',\n value,\n }\n\n // Feature image URLs: attach class hint when value looks like a URL\n if (\n (key === 'featureImage' || key === 'feature_image') &&\n /^https?:\\/\\//i.test(value)\n ) {\n node.meta = {\n url: value,\n class: classifyUrl({ url: value }),\n }\n }\n\n sources.push(node)\n }\n\n return sources\n}\n\nexport type RssXmlSourcesResult = {\n channel: {\n title?: string\n link?: string\n description?: string\n }\n /** Source nodes for each feed item, in document order. */\n items: SourceNode[][]\n}\n\n/**\n * Parse RSS/Atom XML and map each item to SourceNodes via rssItemToSources.\n * Compatible with @seedprotocol/feed `parseRssString` field set.\n */\nexport async function rssXmlToSources(\n xml: string,\n): Promise<RssXmlSourcesResult> {\n const parsed = await parseRssString(xml)\n return {\n channel: {\n title: parsed.title,\n link: parsed.link,\n description: parsed.description,\n },\n items: parsed.items.map((item) => rssItemToSources(item)),\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":["withLookupEntries","lookupEntriesFromMapping","sampleValueFromSource","resolveLookupMapped","shapeLookupValue","isRelationLookupTarget","normalizeLookupKey","parseResolvedSourceId","isPresentEdge","classifyUrl","withDeriveSpec","normalizeMappingFromSourceId","buildResolvedSourceNodes","isDeriveKeepOnClear","withPreservedExtras","RESOLVE_FILE_SUFFIX","applyResolveToEdge","omitEmptySourceId","RESOLVE_EXTRACT_SUFFIX","clearSourceKeepDerive","withAssembleBlocks","autoMap","applyMapping","resolveMappingSource","lookupRefFromEntries","looksLikeUrl","resolvedSourceId","Parser","SECTION_FULL_ID","parseMarkdownWithFrontmatter","match","markdownContent","yamlBlock","body","frontmatter","data","line","keyMatch","key","raw","val","s","valueType","value","v","parseMarkdownSections","lines","md","sections","current","h2Match","h1Match","markdownToSources","parsed","markdown","sources","fm","section","toPlainItem","item","parser","parseRssString","feed","xml","coerceFieldValue","obj","pickMediaAttrs","url","dollar","urlCandidate","typeRaw","lengthRaw","mediaEntriesFromValue","m","one","MEDIA_KEYS","pushMediaNode","seen","id","mediaClass","media","rssItemToSources","enclosureIndex","entries","node","rssXmlToSources","applyMappingAsync","coerceValue"],"sources":["../src/adapters/markdown.ts","../src/adapters/rss.ts"],"sourcesContent":["import type { SourceNode } from '../types'\n\nexport const SECTION_FULL_ID = 'section-full'\n\ntype FrontmatterField = {\n id: string\n key: string\n value: string\n valueType: 'string' | 'boolean' | 'array'\n}\n\ntype ParsedMarkdown = {\n frontmatter: FrontmatterField[]\n body: string\n}\n\ntype MarkdownSection = {\n id: string\n heading: string\n level: number\n content: string\n}\n\n/**\n * Parse YAML-like frontmatter (flat keys only) and body.\n * Mirrors desktop MarkdownMapper limits: no nested YAML.\n */\nexport function parseMarkdownWithFrontmatter(\n markdownContent: string,\n): ParsedMarkdown {\n try {\n const match = markdownContent.match(\n /^---\\r?\\n([\\s\\S]*?)\\r?\\n---\\r?\\n?([\\s\\S]*)$/,\n )\n if (!match) return { frontmatter: [], body: markdownContent }\n\n const yamlBlock = match[1] ?? ''\n const body = (match[2] ?? '').trimStart()\n const frontmatter: FrontmatterField[] = []\n const data: Record<string, unknown> = {}\n\n for (const line of yamlBlock.split('\\n')) {\n const keyMatch = line.match(/^([a-zA-Z_][a-zA-Z0-9_-]*):\\s*(.*)$/)\n if (!keyMatch) continue\n\n const key = keyMatch[1]!\n const raw = keyMatch[2]!.trim()\n let val: unknown = raw\n\n if (raw === 'true') val = true\n else if (raw === 'false') val = false\n else if (raw === 'null' || raw === '') val = null\n else if (raw.startsWith('[') && raw.endsWith(']')) {\n try {\n val = JSON.parse(raw.replace(/'/g, '\"'))\n } catch {\n val = raw\n .slice(1, -1)\n .split(',')\n .map((s: string) => s.trim().replace(/^['\"]|['\"]$/g, ''))\n }\n } else if (raw.startsWith('\"') || raw.startsWith(\"'\")) {\n val = raw.slice(1, -1).replace(/\\\\\"/g, '\"')\n }\n\n data[key] = val\n }\n\n for (const [key, val] of Object.entries(data)) {\n let valueType: 'string' | 'boolean' | 'array' = 'string'\n let value: string\n\n if (Array.isArray(val)) {\n valueType = 'array'\n value = val\n .map((v) => (typeof v === 'object' ? JSON.stringify(v) : String(v)))\n .join(', ')\n } else if (typeof val === 'boolean') {\n valueType = 'boolean'\n value = String(val)\n } else if (val != null && typeof val === 'object') {\n value = JSON.stringify(val)\n } else {\n value = val != null ? String(val) : ''\n }\n\n frontmatter.push({\n id: `fm-${key}`,\n key,\n value,\n valueType,\n })\n }\n\n return { frontmatter, body }\n } catch {\n return { frontmatter: [], body: markdownContent }\n }\n}\n\n/**\n * Split markdown body into H1/H2 sections (###+ ignored as section breaks).\n */\nexport function parseMarkdownSections(md: string): MarkdownSection[] {\n const lines = md.split('\\n')\n const sections: MarkdownSection[] = []\n let current: MarkdownSection | null = null\n\n for (const line of lines) {\n const h2Match = line.match(/^## (.+)/)\n const h1Match = line.match(/^# (.+)/)\n\n if (h1Match) {\n if (current) sections.push(current)\n current = {\n id: `section-${sections.length}`,\n heading: h1Match[1]!,\n level: 1,\n content: '',\n }\n } else if (h2Match) {\n if (current) sections.push(current)\n current = {\n id: `section-${sections.length}`,\n heading: h2Match[1]!,\n level: 2,\n content: '',\n }\n } else if (current) {\n current.content += (current.content ? '\\n' : '') + line\n }\n }\n if (current) sections.push(current)\n return sections\n}\n\n/**\n * Convert markdown into SourceNodes for FieldMapper / applyMapping.\n * Order: frontmatter fields, full document body, then H1/H2 sections.\n */\nexport function markdownToSources(markdown: string): SourceNode[] {\n const parsed = parseMarkdownWithFrontmatter(markdown)\n const sections = parseMarkdownSections(parsed.body)\n const sources: SourceNode[] = []\n\n for (const fm of parsed.frontmatter) {\n sources.push({\n id: fm.id,\n label: fm.key,\n kind: 'frontmatter',\n value: fm.value,\n meta: { valueType: fm.valueType },\n })\n }\n\n sources.push({\n id: SECTION_FULL_ID,\n label: 'Full document',\n kind: 'full',\n value: parsed.body,\n })\n\n for (const section of sections) {\n const value =\n section.content.trim().length > 0 ? section.content.trim() : section.heading\n sources.push({\n id: section.id,\n label: section.heading,\n kind: 'section',\n value,\n meta: { level: section.level },\n })\n }\n\n return sources\n}\n","import Parser from 'rss-parser'\nimport { classifyUrl } from '../classifyUrl'\nimport type { SourceNode } from '../types'\n\nexport type ParsedRssChannel = {\n title?: string\n link?: string\n description?: string\n /** Plain serializable item records (dates become ISO strings). */\n items: Record<string, unknown>[]\n}\n\nfunction toPlainItem(item: unknown): Record<string, unknown> {\n try {\n return JSON.parse(JSON.stringify(item)) as Record<string, unknown>\n } catch {\n return { ...(item as Record<string, unknown>) }\n }\n}\n\n/**\n * Same shape and customFields as @seedprotocol/feed `parseRssString`\n * so RSS mapping stays aligned without importing feed's heavy barrel.\n * Also pulls enclosure / media:content for structured media nodes.\n */\nconst parser = new Parser({\n customFields: {\n item: [\n 'featureImage',\n 'feature_image',\n 'content:encoded',\n 'seedUid',\n 'SeedUid',\n ['media:content', 'mediaContent'],\n ['media:thumbnail', 'mediaThumbnail'],\n ],\n },\n})\n\nasync function parseRssString(xml: string): Promise<ParsedRssChannel> {\n const feed = await parser.parseString(xml)\n return {\n title: feed.title,\n link: feed.link,\n description: feed.description,\n items: (feed.items ?? []).map(toPlainItem),\n }\n}\n\nfunction coerceFieldValue(val: unknown): string | null {\n if (val == null) return null\n if (typeof val === 'string') {\n const t = val.trim()\n return t.length > 0 ? t : null\n }\n if (typeof val === 'number' || typeof val === 'boolean') {\n return String(val)\n }\n if (Array.isArray(val)) {\n try {\n return JSON.stringify(val)\n } catch {\n return null\n }\n }\n if (typeof val === 'object') {\n const obj = val as Record<string, unknown>\n if (typeof obj._ === 'string' && obj._.trim()) return obj._.trim()\n if (typeof obj.value === 'string' && obj.value.trim()) return obj.value.trim()\n try {\n return JSON.stringify(val)\n } catch {\n return null\n }\n }\n return null\n}\n\ntype MediaAttrs = {\n url: string\n contentType?: string\n length?: string\n}\n\nfunction pickMediaAttrs(raw: unknown): MediaAttrs | null {\n if (raw == null) return null\n if (typeof raw === 'string') {\n const url = raw.trim()\n return url ? { url } : null\n }\n if (typeof raw !== 'object') return null\n const obj = raw as Record<string, unknown>\n // rss-parser often nests attrs under `$`\n const dollar =\n obj.$ && typeof obj.$ === 'object'\n ? (obj.$ as Record<string, unknown>)\n : undefined\n const urlCandidate =\n (typeof obj.url === 'string' && obj.url) ||\n (typeof dollar?.url === 'string' && dollar.url) ||\n (typeof obj.link === 'string' && obj.link) ||\n null\n if (!urlCandidate || !String(urlCandidate).trim()) return null\n\n const typeRaw =\n (typeof obj.type === 'string' && obj.type) ||\n (typeof dollar?.type === 'string' && dollar.type) ||\n (typeof obj.medium === 'string' && obj.medium) ||\n undefined\n const lengthRaw =\n (typeof obj.length === 'string' && obj.length) ||\n (typeof obj.length === 'number' && String(obj.length)) ||\n (typeof dollar?.length === 'string' && dollar.length) ||\n (typeof dollar?.length === 'number' && String(dollar.length)) ||\n undefined\n\n return {\n url: String(urlCandidate).trim(),\n contentType: typeRaw ? String(typeRaw).trim() : undefined,\n length: lengthRaw ? String(lengthRaw).trim() : undefined,\n }\n}\n\nfunction mediaEntriesFromValue(raw: unknown): MediaAttrs[] {\n if (raw == null) return []\n if (Array.isArray(raw)) {\n return raw.map(pickMediaAttrs).filter((m): m is MediaAttrs => m != null)\n }\n const one = pickMediaAttrs(raw)\n return one ? [one] : []\n}\n\nconst MEDIA_KEYS = new Set([\n 'enclosure',\n 'enclosures',\n 'media:content',\n 'mediaContent',\n 'media:thumbnail',\n 'mediaThumbnail',\n])\n\nfunction pushMediaNode(\n sources: SourceNode[],\n seen: Set<string>,\n id: string,\n label: string,\n media: MediaAttrs,\n): void {\n if (seen.has(id)) return\n seen.add(id)\n const mediaClass = classifyUrl({\n url: media.url,\n contentType: media.contentType,\n })\n sources.push({\n id,\n label,\n kind: 'rssField',\n value: media.url,\n meta: {\n url: media.url,\n contentType: media.contentType,\n length: media.length,\n class: mediaClass,\n },\n })\n}\n\n/**\n * Flatten a parsed RSS/Atom item into SourceNodes (one per string-coercible key).\n * Enclosure / media:content become url + type in `meta` (not stringified objects).\n * Stable ids: `rss-{key}`, `rss-enclosure-0`, …\n */\nexport function rssItemToSources(item: Record<string, unknown>): SourceNode[] {\n const sources: SourceNode[] = []\n const seen = new Set<string>()\n\n let enclosureIndex = 0\n for (const [key, raw] of Object.entries(item)) {\n if (key === 'items' || key.startsWith('$')) continue\n\n if (MEDIA_KEYS.has(key)) {\n const entries = mediaEntriesFromValue(raw)\n for (const media of entries) {\n const id =\n key === 'enclosure' || key === 'enclosures'\n ? `rss-enclosure-${enclosureIndex}`\n : `rss-${key}-${enclosureIndex}`\n const label =\n key === 'enclosure' || key === 'enclosures'\n ? `enclosure[${enclosureIndex}]`\n : `${key}[${enclosureIndex}]`\n pushMediaNode(sources, seen, id, label, media)\n enclosureIndex += 1\n }\n continue\n }\n\n const value = coerceFieldValue(raw)\n if (value == null) continue\n if (seen.has(key)) continue\n seen.add(key)\n\n const node: SourceNode = {\n id: `rss-${key}`,\n label: key,\n kind: 'rssField',\n value,\n }\n\n // Feature image URLs: attach class hint when value looks like a URL\n if (\n (key === 'featureImage' || key === 'feature_image') &&\n /^https?:\\/\\//i.test(value)\n ) {\n node.meta = {\n url: value,\n class: classifyUrl({ url: value }),\n }\n }\n\n sources.push(node)\n }\n\n return sources\n}\n\nexport type RssXmlSourcesResult = {\n channel: {\n title?: string\n link?: string\n description?: string\n }\n /** Source nodes for each feed item, in document order. */\n items: SourceNode[][]\n}\n\n/**\n * Parse RSS/Atom XML and map each item to SourceNodes via rssItemToSources.\n * Compatible with @seedprotocol/feed `parseRssString` field set.\n */\nexport async function rssXmlToSources(\n xml: string,\n): Promise<RssXmlSourcesResult> {\n const parsed = await parseRssString(xml)\n return {\n channel: {\n title: parsed.title,\n link: parsed.link,\n description: parsed.description,\n },\n items: parsed.items.map((item) => rssItemToSources(item)),\n }\n}\n"],"mappings":"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"}
|
package/dist/react.js
CHANGED
|
@@ -1501,9 +1501,7 @@ function Fe({ sources: e, targets: t, mappings: n, onChange: r, lookups: i = {},
|
|
|
1501
1501
|
}
|
|
1502
1502
|
let c = [...i];
|
|
1503
1503
|
c[a] = s, x(c), n.resolve === "lookup" && s.resolve !== "lookup" && C([n.propertyName]);
|
|
1504
|
-
|
|
1505
|
-
}
|
|
1506
|
-
d((i) => {
|
|
1504
|
+
} else d((i) => {
|
|
1507
1505
|
let a = i.map((i) => {
|
|
1508
1506
|
if (i.id !== n) return i;
|
|
1509
1507
|
if (!r) return {
|
|
@@ -1550,9 +1548,7 @@ function Fe({ sources: e, targets: t, mappings: n, onChange: r, lookups: i = {},
|
|
|
1550
1548
|
}
|
|
1551
1549
|
let l = [...i];
|
|
1552
1550
|
l[a] = c, x(l), n.resolve === "lookup" && c.resolve !== "lookup" && C([n.propertyName]), n.propertyName !== r && n.resolve === "lookup" && c.resolve === "lookup" && C([n.propertyName]);
|
|
1553
|
-
|
|
1554
|
-
}
|
|
1555
|
-
d((i) => {
|
|
1551
|
+
} else d((i) => {
|
|
1556
1552
|
let a = i.map((i) => {
|
|
1557
1553
|
if (i.id !== n) return i;
|
|
1558
1554
|
let a = t.find((e) => e.name === r), o = i.sourceId ? B(e).find((e) => e.id === i.sourceId) : void 0, s = i.resolve;
|
|
@@ -1630,9 +1626,7 @@ function Fe({ sources: e, targets: t, mappings: n, onChange: r, lookups: i = {},
|
|
|
1630
1626
|
if (r >= 0) {
|
|
1631
1627
|
let e = n[r], i = [...n];
|
|
1632
1628
|
i[r] = h(e, t), x(i), e.resolve === "lookup" && t !== "lookup" && C([e.propertyName]);
|
|
1633
|
-
|
|
1634
|
-
}
|
|
1635
|
-
d((n) => {
|
|
1629
|
+
} else d((n) => {
|
|
1636
1630
|
let r = n.map((n) => n.id === e ? {
|
|
1637
1631
|
...n,
|
|
1638
1632
|
resolve: t ?? void 0
|
|
@@ -1652,11 +1646,7 @@ function Fe({ sources: e, targets: t, mappings: n, onChange: r, lookups: i = {},
|
|
|
1652
1646
|
setAssembleBlocks: K,
|
|
1653
1647
|
setDerive: q,
|
|
1654
1648
|
addRow: S((e) => {
|
|
1655
|
-
|
|
1656
|
-
e && l((t) => new Set(t).add(e));
|
|
1657
|
-
return;
|
|
1658
|
-
}
|
|
1659
|
-
d((t) => [...t, {
|
|
1649
|
+
o === "property" ? e && l((t) => new Set(t).add(e)) : d((t) => [...t, {
|
|
1660
1650
|
id: ce("draft"),
|
|
1661
1651
|
...e ? { propertyName: e } : {}
|
|
1662
1652
|
}]);
|
|
@@ -1676,9 +1666,7 @@ function Fe({ sources: e, targets: t, mappings: n, onChange: r, lookups: i = {},
|
|
|
1676
1666
|
if (n >= 0) {
|
|
1677
1667
|
let e = t[n];
|
|
1678
1668
|
x(t.filter((e, t) => t !== n)), e?.resolve === "lookup" && C([e.propertyName]);
|
|
1679
|
-
|
|
1680
|
-
}
|
|
1681
|
-
d((t) => t.filter((t) => t.id !== e));
|
|
1669
|
+
} else d((t) => t.filter((t) => t.id !== e));
|
|
1682
1670
|
}, [
|
|
1683
1671
|
o,
|
|
1684
1672
|
x,
|