@chelone/core 0.6.0 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (255) hide show
  1. package/dist/assistant/assistant-session.d.ts +6 -0
  2. package/dist/assistant/assistant-session.js +204 -181
  3. package/dist/assistant/echo-transport.js +26 -29
  4. package/dist/assistant/http-transport.d.ts +10 -0
  5. package/dist/assistant/http-transport.js +98 -0
  6. package/dist/assistant/types.d.ts +1 -7
  7. package/dist/auth/access-control.d.ts +13 -5
  8. package/dist/auth/access-control.js +25 -21
  9. package/dist/auth/auth-options.d.ts +23 -17
  10. package/dist/auth/auth-options.js +82 -48
  11. package/dist/auth/permission-matrix.d.ts +12 -0
  12. package/dist/auth/permission-matrix.js +67 -0
  13. package/dist/auth/types.d.ts +14 -4
  14. package/dist/block-editor/block-document.d.ts +64 -0
  15. package/dist/block-editor/block-document.js +147 -0
  16. package/dist/block-editor/data-blocks.d.ts +63 -0
  17. package/dist/block-editor/data-blocks.js +117 -0
  18. package/dist/chart/chart-data.js +46 -44
  19. package/dist/command-menu/hotkey.js +58 -47
  20. package/dist/command-menu/recents.d.ts +4 -0
  21. package/dist/command-menu/recents.js +12 -11
  22. package/dist/command-menu/registry.d.ts +9 -5
  23. package/dist/command-menu/registry.js +36 -46
  24. package/dist/controller/calendar-dates.d.ts +12 -0
  25. package/dist/controller/calendar-dates.js +94 -113
  26. package/dist/controller/calendar-events.js +93 -88
  27. package/dist/controller/client-list-controller.d.ts +2 -2
  28. package/dist/controller/client-list-controller.js +251 -254
  29. package/dist/controller/data-table-columns.d.ts +2 -0
  30. package/dist/controller/data-table-columns.js +50 -56
  31. package/dist/controller/deep-equal.d.ts +1 -0
  32. package/dist/controller/deep-equal.js +14 -0
  33. package/dist/controller/filter-toggle.js +36 -44
  34. package/dist/controller/in-place-editor.d.ts +43 -0
  35. package/dist/controller/in-place-editor.js +43 -0
  36. package/dist/controller/infinite-list-controller.js +219 -189
  37. package/dist/controller/inspector.d.ts +55 -0
  38. package/dist/controller/inspector.js +70 -0
  39. package/dist/controller/job-monitor.d.ts +10 -4
  40. package/dist/controller/job-monitor.js +46 -47
  41. package/dist/controller/kanban-board.js +45 -24
  42. package/dist/controller/list-controller.d.ts +8 -5
  43. package/dist/controller/list-controller.js +447 -400
  44. package/dist/controller/list-params.js +96 -87
  45. package/dist/controller/pivot-grid.d.ts +4 -4
  46. package/dist/controller/pivot-grid.js +89 -95
  47. package/dist/controller/prev-next.d.ts +2 -2
  48. package/dist/controller/prev-next.js +74 -54
  49. package/dist/controller/record-controllers.d.ts +14 -6
  50. package/dist/controller/record-controllers.js +288 -257
  51. package/dist/controller/record-diff.d.ts +21 -0
  52. package/dist/controller/record-diff.js +50 -0
  53. package/dist/controller/record-timeline.d.ts +5 -5
  54. package/dist/controller/record-timeline.js +42 -30
  55. package/dist/controller/record-tree.js +57 -47
  56. package/dist/controller/record-workflow.d.ts +38 -16
  57. package/dist/controller/record-workflow.js +85 -64
  58. package/dist/controller/reference-many-controller.d.ts +2 -0
  59. package/dist/controller/reference-many-controller.js +199 -192
  60. package/dist/controller/reference-one-controller.d.ts +1 -1
  61. package/dist/controller/reference-one-controller.js +63 -56
  62. package/dist/controller/saved-queries.js +104 -91
  63. package/dist/controller/translate-fallback.js +10 -6
  64. package/dist/csv/export.d.ts +4 -3
  65. package/dist/csv/export.js +43 -40
  66. package/dist/csv/import-controller.d.ts +4 -0
  67. package/dist/csv/import-controller.js +189 -169
  68. package/dist/csv/match-headers.js +29 -22
  69. package/dist/csv/parse-with.js +60 -54
  70. package/dist/csv/run-import.js +69 -72
  71. package/dist/csv/validate-rows.d.ts +1 -1
  72. package/dist/csv/validate-rows.js +65 -52
  73. package/dist/data/cache-ops.d.ts +5 -4
  74. package/dist/data/cache-ops.js +208 -188
  75. package/dist/data/combine-data-providers.js +25 -23
  76. package/dist/data/data-provider-log.d.ts +45 -0
  77. package/dist/data/data-provider-log.js +93 -0
  78. package/dist/data/errors.js +14 -10
  79. package/dist/data/fake-provider.d.ts +6 -3
  80. package/dist/data/fake-provider.js +135 -114
  81. package/dist/data/fetch-utils.js +61 -44
  82. package/dist/data/filter-branch.d.ts +5 -0
  83. package/dist/data/filter-branch.js +10 -0
  84. package/dist/data/get-many-aggregate.js +84 -76
  85. package/dist/data/http-error.js +17 -12
  86. package/dist/data/keys.js +50 -36
  87. package/dist/data/mutation-options.d.ts +14 -9
  88. package/dist/data/mutation-options.js +93 -109
  89. package/dist/data/query-options.js +73 -68
  90. package/dist/data/remove-empty.d.ts +3 -0
  91. package/dist/data/remove-empty.js +11 -0
  92. package/dist/data/undoable.d.ts +2 -2
  93. package/dist/data/undoable.js +190 -174
  94. package/dist/data/with-lifecycle-callbacks.d.ts +45 -17
  95. package/dist/data/with-lifecycle-callbacks.js +66 -52
  96. package/dist/environment/application-update-store.js +58 -55
  97. package/dist/environment/offline-store.js +21 -21
  98. package/dist/form/array-binding.d.ts +30 -11
  99. package/dist/form/array-binding.js +184 -166
  100. package/dist/form/choice-ids.d.ts +7 -0
  101. package/dist/form/choice-ids.js +11 -0
  102. package/dist/form/choices-controller.d.ts +22 -2
  103. package/dist/form/choices-controller.js +315 -275
  104. package/dist/form/date-format.d.ts +38 -0
  105. package/dist/form/date-format.js +89 -0
  106. package/dist/form/dirty-values.d.ts +2 -2
  107. package/dist/form/dirty-values.js +22 -11
  108. package/dist/form/duration.d.ts +22 -0
  109. package/dist/form/duration.js +49 -0
  110. package/dist/form/edit-create-form.d.ts +12 -5
  111. package/dist/form/edit-create-form.js +243 -188
  112. package/dist/form/event-value.d.ts +6 -0
  113. package/dist/form/event-value.js +17 -0
  114. package/dist/form/field-error.d.ts +14 -0
  115. package/dist/form/field-error.js +28 -0
  116. package/dist/form/field-name.d.ts +20 -0
  117. package/dist/form/field-name.js +6 -0
  118. package/dist/form/filter-form-values.js +63 -49
  119. package/dist/form/form-controller.d.ts +9 -1
  120. package/dist/form/form-controller.js +165 -160
  121. package/dist/form/form-groups.d.ts +4 -3
  122. package/dist/form/form-groups.js +79 -79
  123. package/dist/form/form-handle.d.ts +175 -0
  124. package/dist/form/form-handle.js +68 -0
  125. package/dist/form/input-binding.d.ts +56 -31
  126. package/dist/form/input-binding.js +171 -118
  127. package/dist/form/input-values.d.ts +140 -0
  128. package/dist/form/input-values.js +206 -0
  129. package/dist/form/json-text.d.ts +11 -0
  130. package/dist/form/json-text.js +62 -37
  131. package/dist/form/save-pipeline.d.ts +6 -8
  132. package/dist/form/save-pipeline.js +91 -82
  133. package/dist/form/set-form-values.d.ts +6 -0
  134. package/dist/form/set-form-values.js +10 -0
  135. package/dist/form/source.js +97 -65
  136. package/dist/form/text-of.d.ts +2 -0
  137. package/dist/form/text-of.js +7 -0
  138. package/dist/form/validators.d.ts +58 -19
  139. package/dist/form/validators.js +97 -71
  140. package/dist/geo/bbox.d.ts +5 -4
  141. package/dist/geo/bbox.js +69 -48
  142. package/dist/geo/bounds.d.ts +14 -3
  143. package/dist/geo/bounds.js +98 -68
  144. package/dist/geo/constraints.js +88 -93
  145. package/dist/geo/coordinates.d.ts +10 -0
  146. package/dist/geo/coordinates.js +44 -23
  147. package/dist/geo/editor.d.ts +13 -13
  148. package/dist/geo/editor.js +176 -153
  149. package/dist/geo/geocoding.d.ts +4 -4
  150. package/dist/geo/geocoding.js +38 -41
  151. package/dist/geo/geojson.d.ts +12 -74
  152. package/dist/geo/geojson.js +52 -40
  153. package/dist/geo/geometry-math.d.ts +4 -4
  154. package/dist/geo/geometry-math.js +100 -93
  155. package/dist/geo/index.d.ts +9 -8
  156. package/dist/geo/map-layers.d.ts +42 -7
  157. package/dist/geo/map-layers.js +88 -62
  158. package/dist/geo/map-style.d.ts +12 -0
  159. package/dist/geo/map-style.js +43 -32
  160. package/dist/geo/messages.js +48 -45
  161. package/dist/geo/nominatim.js +88 -80
  162. package/dist/geo/osm-presets.d.ts +4 -3
  163. package/dist/geo/osm-presets.js +108 -86
  164. package/dist/geo/osm-tags.js +14 -12
  165. package/dist/geo/overpass.d.ts +14 -2
  166. package/dist/geo/overpass.js +83 -90
  167. package/dist/geo/shape-value.d.ts +9 -5
  168. package/dist/geo/shape-value.js +169 -146
  169. package/dist/geo/snap-to-roads.d.ts +3 -3
  170. package/dist/geo/snap-to-roads.js +55 -50
  171. package/dist/geo/throttle.js +36 -39
  172. package/dist/guards.d.ts +44 -0
  173. package/dist/guards.js +77 -0
  174. package/dist/i18n/default-messages.js +34 -29
  175. package/dist/i18n/english-messages.d.ts +172 -0
  176. package/dist/i18n/english-messages.js +359 -189
  177. package/dist/i18n/i18n.d.ts +2 -2
  178. package/dist/i18n/i18n.js +47 -60
  179. package/dist/i18n/inflection.d.ts +34 -0
  180. package/dist/i18n/inflection.js +82 -0
  181. package/dist/i18n/messages.d.ts +10 -2
  182. package/dist/i18n/messages.js +17 -4
  183. package/dist/i18n/missing-keys.d.ts +4 -0
  184. package/dist/i18n/missing-keys.js +70 -62
  185. package/dist/i18n/translatable.d.ts +16 -1
  186. package/dist/i18n/translatable.js +40 -47
  187. package/dist/index.d.ts +87 -39
  188. package/dist/index.js +54 -301
  189. package/dist/json/deep-equal.d.ts +8 -0
  190. package/dist/json/deep-equal.js +24 -0
  191. package/dist/json/strip-json-comments.js +38 -42
  192. package/dist/noop.d.ts +2 -0
  193. package/dist/noop.js +4 -0
  194. package/dist/notification/error-message.d.ts +2 -0
  195. package/dist/notification/error-message.js +10 -0
  196. package/dist/notification/notification-store.d.ts +3 -2
  197. package/dist/notification/notification-store.js +41 -45
  198. package/dist/onboarding-tour/placement.d.ts +2 -0
  199. package/dist/onboarding-tour/placement.js +65 -78
  200. package/dist/onboarding-tour/tour-controller.js +46 -54
  201. package/dist/realtime/add-events-for-mutations.js +75 -81
  202. package/dist/realtime/announce-lock.js +16 -13
  203. package/dist/realtime/broadcast-channel-transport.js +65 -59
  204. package/dist/realtime/copy-members.js +22 -14
  205. package/dist/realtime/in-memory-lock-provider.js +40 -48
  206. package/dist/realtime/live.js +95 -101
  207. package/dist/realtime/lock-options.js +16 -16
  208. package/dist/realtime/lock-session.js +91 -78
  209. package/dist/realtime/memory-transport.js +25 -25
  210. package/dist/realtime/presence.js +120 -122
  211. package/dist/realtime/realtime-data-provider.d.ts +10 -0
  212. package/dist/realtime/realtime-data-provider.js +45 -42
  213. package/dist/realtime/reconnect-backoff.js +17 -0
  214. package/dist/realtime/sse-transport.d.ts +31 -0
  215. package/dist/realtime/sse-transport.js +235 -0
  216. package/dist/realtime/status-store.js +23 -28
  217. package/dist/realtime/topic-hub.js +62 -71
  218. package/dist/realtime/topics.js +10 -12
  219. package/dist/realtime/types.js +10 -12
  220. package/dist/realtime/unread-count.js +21 -21
  221. package/dist/realtime/websocket-transport.d.ts +32 -0
  222. package/dist/realtime/websocket-transport.js +306 -0
  223. package/dist/resource/describe-resource.d.ts +2 -0
  224. package/dist/resource/describe-resource.js +247 -219
  225. package/dist/resource/get-at-path.js +29 -14
  226. package/dist/resource/identifier.d.ts +18 -0
  227. package/dist/resource/identifier.js +27 -0
  228. package/dist/resource/record.d.ts +4 -0
  229. package/dist/resource/record.js +10 -0
  230. package/dist/resource/register.d.ts +7 -0
  231. package/dist/resource/registry-store.d.ts +45 -15
  232. package/dist/resource/registry-store.js +67 -60
  233. package/dist/resource/registry.d.ts +10 -0
  234. package/dist/resource/registry.js +8 -4
  235. package/dist/resource/source-path.d.ts +23 -2
  236. package/dist/rich-text/rich-text-extras.d.ts +134 -0
  237. package/dist/rich-text/rich-text-extras.js +181 -0
  238. package/dist/rich-text/rich-text-image.d.ts +124 -0
  239. package/dist/rich-text/rich-text-image.js +163 -0
  240. package/dist/rich-text/rich-text.d.ts +6 -0
  241. package/dist/rich-text/rich-text.js +125 -88
  242. package/dist/router/location.d.ts +24 -4
  243. package/dist/router/location.js +43 -18
  244. package/dist/router/match.js +47 -39
  245. package/dist/router/paths.js +40 -34
  246. package/dist/router/record-from-location.d.ts +1 -1
  247. package/dist/router/record-from-location.js +25 -17
  248. package/dist/store/adapters.js +51 -55
  249. package/dist/store/micro-store.js +57 -59
  250. package/dist/store/shallow-equal.d.ts +12 -0
  251. package/dist/store/shallow-equal.js +20 -0
  252. package/dist/store/store.js +54 -57
  253. package/dist/ui-defaults.d.ts +15 -0
  254. package/dist/ui-defaults.js +17 -0
  255. package/package.json +13 -11
@@ -2,174 +2,194 @@ import { createMicroStore } from "../store/micro-store.js";
2
2
  import { matchCsvHeaders } from "./match-headers.js";
3
3
  import { runCsvImport } from "./run-import.js";
4
4
  import { csvSchemaFields, validateCsvRows } from "./validate-rows.js";
5
- const STEPS = ["upload", "map", "preview", "commit"];
6
- const asError = (error) => error instanceof Error ? error : new Error(String(error));
5
+ // src/csv/import-controller.ts
6
+ var STEPS = [
7
+ "upload",
8
+ "map",
9
+ "preview",
10
+ "commit"
11
+ ];
12
+ /** How many rows either adapter's preview step lists. */
13
+ var PREVIEW_ROWS = 50;
14
+ /** What `readAsText` writes for each byte it cannot read as UTF-8. */
15
+ var REPLACEMENT_CHAR = "�";
16
+ var asError = (error) => error instanceof Error ? error : new Error(String(error));
7
17
  function createCsvImportController(options) {
8
- const fromSchema = csvSchemaFields(options.schema);
9
- const explicitFields = options.fields ?? fromSchema.fields;
10
- const requiredFields = options.requiredFields ?? (options.fields ? [] : fromSchema.required);
11
- const initialMapping = options.mapping ?? {};
12
- const initial = () => ({
13
- step: "upload",
14
- fileName: null,
15
- headers: [],
16
- rows: [],
17
- parseError: null,
18
- fields: explicitFields,
19
- requiredFields,
20
- mapping: initialMapping,
21
- validations: [],
22
- progress: { current: 0, total: 0 },
23
- status: "idle",
24
- report: null,
25
- error: null
26
- });
27
- const store = createMicroStore(initial());
28
- const state = () => store.getSnapshot();
29
- let mappingSettled = Object.keys(initialMapping).length > 0;
30
- let generation = 0;
31
- let busy = false;
32
- let created = false;
33
- let abort;
34
- const startImport = () => {
35
- const run = ++generation;
36
- const controller = new AbortController();
37
- abort = controller;
38
- const validations = state().validations;
39
- const total = validations.filter((v) => v.ok).length;
40
- store.setState({
41
- status: "running",
42
- progress: { current: 0, total },
43
- report: null,
44
- error: null
45
- });
46
- void (async () => {
47
- let report;
48
- try {
49
- report = await runCsvImport({
50
- dataProvider: options.dataProvider,
51
- resource: options.resource,
52
- validations,
53
- ...options.batchSize !== void 0 && {
54
- batchSize: options.batchSize
55
- },
56
- signal: controller.signal,
57
- onProgress: (progress) => {
58
- if (run === generation) store.setState({ progress });
59
- }
60
- });
61
- } catch (thrown) {
62
- if (run !== generation) return;
63
- const error = asError(thrown);
64
- store.setState({ status: "failed", error });
65
- options.onError?.(error);
66
- return;
67
- }
68
- if (run !== generation) return;
69
- if (report.created > 0) created = true;
70
- store.setState({ status: "done", report });
71
- options.onComplete?.(report);
72
- })();
73
- };
74
- const gate = (step) => {
75
- const s = state();
76
- switch (step) {
77
- case "upload":
78
- return s.rows.length > 0 && s.parseError === null;
79
- case "map":
80
- return s.requiredFields.every((field) => !!s.mapping[field]) && Object.values(s.mapping).some(Boolean);
81
- case "preview":
82
- return !created && s.validations.some((v) => v.ok);
83
- case "commit":
84
- return false;
85
- }
86
- };
87
- return {
88
- store,
89
- loadParsed(parsed, fileName) {
90
- if (state().status === "running" || busy) return;
91
- const first = parsed.errors[0];
92
- const parseError = first ? first.row === void 0 ? first.message : `Row ${first.row}: ${first.message}` : null;
93
- const fields = explicitFields.length > 0 ? explicitFields : parsed.headers;
94
- mappingSettled = Object.keys(initialMapping).length > 0;
95
- created = false;
96
- store.setState({
97
- ...initial(),
98
- fileName: fileName ?? null,
99
- headers: parsed.headers,
100
- rows: parseError === null ? parsed.rows : [],
101
- parseError,
102
- fields
103
- });
104
- },
105
- setMapping(field, header) {
106
- if (busy) return;
107
- mappingSettled = true;
108
- store.setState((prev) => ({
109
- mapping: { ...prev.mapping, [field]: header }
110
- }));
111
- },
112
- async next() {
113
- if (busy) return false;
114
- const s = state();
115
- if (s.status === "running") return false;
116
- const index = STEPS.indexOf(s.step);
117
- const target = STEPS[index + 1];
118
- if (!target || !gate(s.step)) return false;
119
- if (target === "map") {
120
- if (!mappingSettled) {
121
- mappingSettled = true;
122
- const mapping = explicitFields.length > 0 ? matchCsvHeaders(s.fields, s.headers) : Object.fromEntries(s.headers.map((h) => [h, h]));
123
- store.setState({ mapping });
124
- }
125
- store.setState({ step: "map" });
126
- } else if (target === "preview") {
127
- busy = true;
128
- const run = generation;
129
- try {
130
- const validations = await validateCsvRows(s.rows, {
131
- mapping: s.mapping,
132
- ...options.schema && { schema: options.schema },
133
- ...options.transform && { transform: options.transform }
134
- });
135
- if (run !== generation) return false;
136
- store.setState({ validations, step: "preview" });
137
- } finally {
138
- if (run === generation) busy = false;
139
- }
140
- } else {
141
- store.setState({ step: "commit" });
142
- startImport();
143
- }
144
- return true;
145
- },
146
- back() {
147
- const s = state();
148
- if (s.status === "running" || busy) return;
149
- const previous = STEPS[STEPS.indexOf(s.step) - 1];
150
- if (!previous) return;
151
- store.setState({
152
- step: previous,
153
- status: "idle",
154
- report: null,
155
- error: null,
156
- progress: { current: 0, total: 0 }
157
- });
158
- },
159
- cancel() {
160
- abort?.abort();
161
- },
162
- reset() {
163
- generation += 1;
164
- abort?.abort();
165
- abort = void 0;
166
- busy = false;
167
- created = false;
168
- mappingSettled = Object.keys(initialMapping).length > 0;
169
- store.setState(initial());
170
- }
171
- };
18
+ const fromSchema = csvSchemaFields(options.schema);
19
+ const explicitFields = options.fields ?? fromSchema.fields;
20
+ const requiredFields = options.requiredFields ?? (options.fields ? [] : fromSchema.required);
21
+ const initialMapping = options.mapping ?? {};
22
+ const initial = () => ({
23
+ step: "upload",
24
+ fileName: null,
25
+ headers: [],
26
+ rows: [],
27
+ parseError: null,
28
+ fields: explicitFields,
29
+ requiredFields,
30
+ mapping: initialMapping,
31
+ validations: [],
32
+ progress: {
33
+ current: 0,
34
+ total: 0
35
+ },
36
+ status: "idle",
37
+ report: null,
38
+ error: null
39
+ });
40
+ const store = createMicroStore(initial());
41
+ const state = () => store.getSnapshot();
42
+ let mappingSettled = Object.keys(initialMapping).length > 0;
43
+ let generation = 0;
44
+ let busy = false;
45
+ let created = false;
46
+ let abort;
47
+ const startImport = () => {
48
+ const run = ++generation;
49
+ const controller = new AbortController();
50
+ abort = controller;
51
+ const validations = state().validations;
52
+ const total = validations.filter((v) => v.ok).length;
53
+ store.setState({
54
+ status: "running",
55
+ progress: {
56
+ current: 0,
57
+ total
58
+ },
59
+ report: null,
60
+ error: null
61
+ });
62
+ (async () => {
63
+ let report;
64
+ try {
65
+ report = await runCsvImport({
66
+ dataProvider: options.dataProvider,
67
+ resource: options.resource,
68
+ validations,
69
+ ...options.batchSize !== void 0 && { batchSize: options.batchSize },
70
+ signal: controller.signal,
71
+ onProgress: (progress) => {
72
+ if (run === generation) store.setState({ progress });
73
+ }
74
+ });
75
+ } catch (thrown) {
76
+ if (run !== generation) return;
77
+ const error = asError(thrown);
78
+ store.setState({
79
+ status: "failed",
80
+ error
81
+ });
82
+ options.onError?.(error);
83
+ return;
84
+ }
85
+ if (run !== generation) return;
86
+ if (report.created > 0) created = true;
87
+ store.setState({
88
+ status: "done",
89
+ report
90
+ });
91
+ options.onComplete?.(report);
92
+ })();
93
+ };
94
+ const gate = (step) => {
95
+ const s = state();
96
+ switch (step) {
97
+ case "upload": return s.rows.length > 0 && s.parseError === null;
98
+ case "map": return s.requiredFields.every((field) => !!s.mapping[field]) && Object.values(s.mapping).some(Boolean);
99
+ case "preview": return !created && s.validations.some((v) => v.ok);
100
+ case "commit": return false;
101
+ }
102
+ };
103
+ return {
104
+ store,
105
+ loadParsed(parsed, fileName) {
106
+ if (state().status === "running" || busy) return;
107
+ const first = parsed.errors[0];
108
+ const parseError = first ? first.row === void 0 ? first.message : `Row ${first.row}: ${first.message}` : null;
109
+ const fields = explicitFields.length > 0 ? explicitFields : parsed.headers;
110
+ mappingSettled = Object.keys(initialMapping).length > 0;
111
+ created = false;
112
+ store.setState({
113
+ ...initial(),
114
+ fileName: fileName ?? null,
115
+ headers: parsed.headers,
116
+ rows: parseError === null ? parsed.rows : [],
117
+ parseError,
118
+ fields
119
+ });
120
+ },
121
+ setMapping(field, header) {
122
+ if (busy) return;
123
+ mappingSettled = true;
124
+ store.setState((prev) => ({ mapping: {
125
+ ...prev.mapping,
126
+ [field]: header
127
+ } }));
128
+ },
129
+ async next() {
130
+ if (busy) return false;
131
+ const s = state();
132
+ if (s.status === "running") return false;
133
+ const target = STEPS[STEPS.indexOf(s.step) + 1];
134
+ if (!target || !gate(s.step)) return false;
135
+ if (target === "map") {
136
+ if (!mappingSettled) {
137
+ mappingSettled = true;
138
+ const mapping = explicitFields.length > 0 ? matchCsvHeaders(s.fields, s.headers) : Object.fromEntries(s.headers.map((h) => [h, h]));
139
+ store.setState({ mapping });
140
+ }
141
+ store.setState({ step: "map" });
142
+ } else if (target === "preview") {
143
+ busy = true;
144
+ const run = generation;
145
+ try {
146
+ const validations = await validateCsvRows(s.rows, {
147
+ mapping: s.mapping,
148
+ ...options.schema && { schema: options.schema },
149
+ ...options.transform && { transform: options.transform }
150
+ });
151
+ if (run !== generation) return false;
152
+ store.setState({
153
+ validations,
154
+ step: "preview"
155
+ });
156
+ } finally {
157
+ if (run === generation) busy = false;
158
+ }
159
+ } else {
160
+ store.setState({ step: "commit" });
161
+ startImport();
162
+ }
163
+ return true;
164
+ },
165
+ back() {
166
+ const s = state();
167
+ if (s.status === "running" || busy) return;
168
+ const previous = STEPS[STEPS.indexOf(s.step) - 1];
169
+ if (!previous) return;
170
+ store.setState({
171
+ step: previous,
172
+ status: "idle",
173
+ report: null,
174
+ error: null,
175
+ progress: {
176
+ current: 0,
177
+ total: 0
178
+ }
179
+ });
180
+ },
181
+ cancel() {
182
+ abort?.abort();
183
+ },
184
+ reset() {
185
+ generation += 1;
186
+ abort?.abort();
187
+ abort = void 0;
188
+ busy = false;
189
+ created = false;
190
+ mappingSettled = Object.keys(initialMapping).length > 0;
191
+ store.setState(initial());
192
+ }
193
+ };
172
194
  }
173
- export {
174
- createCsvImportController
175
- };
195
+ export { PREVIEW_ROWS, REPLACEMENT_CHAR, createCsvImportController };
@@ -1,24 +1,31 @@
1
- const normalise = (name) => name.toLowerCase().replace(/[\s_-]+/g, "");
1
+ // src/csv/match-headers.ts
2
+ var normalise = (name) => name.toLowerCase().replace(/[\s_-]+/g, "");
3
+ /**
4
+ * Pairs each field with the CSV header it most likely names. Pass one takes an
5
+ * equal name, pass two a header that contains the field, pass three a header
6
+ * the field contains. A later match never takes a header an earlier one took.
7
+ */
2
8
  function matchCsvHeaders(fields, headers) {
3
- const free = headers.map((header) => ({ header, name: normalise(header) })).filter(({ name }) => name !== "");
4
- const result = /* @__PURE__ */ new Map();
5
- const pass = (matches) => {
6
- for (const field of fields) {
7
- if (result.has(field)) continue;
8
- const name = normalise(field);
9
- if (name === "") continue;
10
- const index = free.findIndex((entry) => matches(name, entry.name));
11
- const found = free[index];
12
- if (!found) continue;
13
- result.set(field, found.header);
14
- free.splice(index, 1);
15
- }
16
- };
17
- pass((field, header) => field === header);
18
- pass((field, header) => header.includes(field));
19
- pass((field, header) => field.includes(header));
20
- return Object.fromEntries(result);
9
+ const free = headers.map((header) => ({
10
+ header,
11
+ name: normalise(header)
12
+ })).filter(({ name }) => name !== "");
13
+ const result = /* @__PURE__ */ new Map();
14
+ const pass = (matches) => {
15
+ for (const field of fields) {
16
+ if (result.has(field)) continue;
17
+ const name = normalise(field);
18
+ if (name === "") continue;
19
+ const index = free.findIndex((entry) => matches(name, entry.name));
20
+ const found = free[index];
21
+ if (!found) continue;
22
+ result.set(field, found.header);
23
+ free.splice(index, 1);
24
+ }
25
+ };
26
+ pass((field, header) => field === header);
27
+ pass((field, header) => header.includes(field));
28
+ pass((field, header) => field.includes(header));
29
+ return Object.fromEntries(result);
21
30
  }
22
- export {
23
- matchCsvHeaders
24
- };
31
+ export { matchCsvHeaders };
@@ -1,58 +1,64 @@
1
- const OPTIONS = { header: false, skipEmptyLines: "greedy" };
2
- const IGNORED_CODES = /* @__PURE__ */ new Set(["UndetectableDelimiter"]);
1
+ // src/csv/parse-with.ts
2
+ var OPTIONS = {
3
+ header: false,
4
+ skipEmptyLines: "greedy"
5
+ };
6
+ var IGNORED_CODES = /* @__PURE__ */ new Set(["UndetectableDelimiter"]);
3
7
  function parseCsvWith(parser, text) {
4
- const result = parser.parse(text, OPTIONS);
5
- const body = text.replace(/^/, "");
6
- const [headerRow = [], ...records] = result.data;
7
- const headers = nameHeaders(headerRow);
8
- const rowOf = (error) => {
9
- if (error.row === void 0) return void 0;
10
- if (error.index === void 0) return error.row;
11
- const rows2 = parser.parse(body.slice(0, error.index), OPTIONS).data.length;
12
- return Math.max(rows2 - 1, 0);
13
- };
14
- const errors = [];
15
- for (const error of result.errors) {
16
- if (IGNORED_CODES.has(error.code)) continue;
17
- const { code, message } = error;
18
- const row = rowOf(error);
19
- errors.push(row === void 0 ? { code, message } : { code, row, message });
20
- }
21
- records.forEach((record, index) => {
22
- if (record.length === headers.length) return;
23
- const few = record.length < headers.length;
24
- errors.push({
25
- code: few ? "TooFewFields" : "TooManyFields",
26
- row: index + 1,
27
- message: `Too ${few ? "few" : "many"} fields: expected ${headers.length} fields but parsed ${record.length}`
28
- });
29
- });
30
- const rows = records.map(
31
- (record) => Object.fromEntries(
32
- headers.map((header, index) => [header, record[index] ?? ""])
33
- )
34
- );
35
- return { headers, rows, errors };
8
+ const result = parser.parse(text, OPTIONS);
9
+ const body = text.replace(/^/, "");
10
+ const [headerRow = [], ...records] = result.data;
11
+ const headers = nameHeaders(headerRow);
12
+ const rowOf = (error) => {
13
+ if (error.row === void 0) return void 0;
14
+ if (error.index === void 0) return error.row;
15
+ const rows = parser.parse(body.slice(0, error.index), OPTIONS).data.length;
16
+ return Math.max(rows - 1, 0);
17
+ };
18
+ const errors = [];
19
+ for (const error of result.errors) {
20
+ if (IGNORED_CODES.has(error.code)) continue;
21
+ const { code, message } = error;
22
+ const row = rowOf(error);
23
+ errors.push(row === void 0 ? {
24
+ code,
25
+ message
26
+ } : {
27
+ code,
28
+ row,
29
+ message
30
+ });
31
+ }
32
+ records.forEach((record, index) => {
33
+ if (record.length === headers.length) return;
34
+ const few = record.length < headers.length;
35
+ errors.push({
36
+ code: few ? "TooFewFields" : "TooManyFields",
37
+ row: index + 1,
38
+ message: `Too ${few ? "few" : "many"} fields: expected ${headers.length} fields but parsed ${record.length}`
39
+ });
40
+ });
41
+ return {
42
+ headers,
43
+ rows: records.map((record) => Object.fromEntries(headers.map((header, index) => [header, record[index] ?? ""]))),
44
+ errors
45
+ };
36
46
  }
37
47
  function nameHeaders(cells) {
38
- const trimmed = cells.map(
39
- (cell, index) => cell.trim() || `column_${index + 1}`
40
- );
41
- const taken = new Set(trimmed);
42
- const seen = /* @__PURE__ */ new Set();
43
- return trimmed.map((header) => {
44
- if (!seen.has(header)) {
45
- seen.add(header);
46
- return header;
47
- }
48
- let n = 1;
49
- while (taken.has(`${header}_${n}`)) n += 1;
50
- const renamed = `${header}_${n}`;
51
- taken.add(renamed);
52
- seen.add(renamed);
53
- return renamed;
54
- });
48
+ const trimmed = cells.map((cell, index) => cell.trim() || `column_${index + 1}`);
49
+ const taken = new Set(trimmed);
50
+ const seen = /* @__PURE__ */ new Set();
51
+ return trimmed.map((header) => {
52
+ if (!seen.has(header)) {
53
+ seen.add(header);
54
+ return header;
55
+ }
56
+ let n = 1;
57
+ while (taken.has(`${header}_${n}`)) n += 1;
58
+ const renamed = `${header}_${n}`;
59
+ taken.add(renamed);
60
+ seen.add(renamed);
61
+ return renamed;
62
+ });
55
63
  }
56
- export {
57
- parseCsvWith
58
- };
64
+ export { parseCsvWith };