@chelone/core 0.5.0 → 0.7.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 (253) hide show
  1. package/dist/assistant/assistant-session.d.ts +28 -0
  2. package/dist/assistant/assistant-session.js +208 -0
  3. package/dist/assistant/echo-transport.d.ts +7 -0
  4. package/dist/assistant/echo-transport.js +28 -0
  5. package/dist/assistant/http-transport.d.ts +10 -0
  6. package/dist/assistant/http-transport.js +98 -0
  7. package/dist/assistant/types.d.ts +54 -0
  8. package/dist/auth/access-control.d.ts +13 -5
  9. package/dist/auth/access-control.js +25 -21
  10. package/dist/auth/auth-options.d.ts +21 -17
  11. package/dist/auth/auth-options.js +80 -48
  12. package/dist/auth/permission-matrix.d.ts +12 -0
  13. package/dist/auth/permission-matrix.js +67 -0
  14. package/dist/auth/types.d.ts +14 -4
  15. package/dist/block-editor/block-document.d.ts +60 -0
  16. package/dist/block-editor/block-document.js +143 -0
  17. package/dist/block-editor/data-blocks.d.ts +63 -0
  18. package/dist/block-editor/data-blocks.js +117 -0
  19. package/dist/chart/chart-data.d.ts +25 -0
  20. package/dist/chart/chart-data.js +61 -0
  21. package/dist/command-menu/hotkey.js +58 -47
  22. package/dist/command-menu/recents.js +8 -11
  23. package/dist/command-menu/registry.d.ts +9 -5
  24. package/dist/command-menu/registry.js +36 -46
  25. package/dist/controller/calendar-dates.js +82 -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 +42 -0
  35. package/dist/controller/in-place-editor.js +42 -0
  36. package/dist/controller/infinite-list-controller.js +220 -190
  37. package/dist/controller/inspector.d.ts +49 -0
  38. package/dist/controller/inspector.js +64 -0
  39. package/dist/controller/job-monitor.d.ts +41 -0
  40. package/dist/controller/job-monitor.js +49 -0
  41. package/dist/controller/kanban-board.d.ts +2 -3
  42. package/dist/controller/kanban-board.js +43 -24
  43. package/dist/controller/list-controller.d.ts +5 -5
  44. package/dist/controller/list-controller.js +444 -400
  45. package/dist/controller/list-params.js +96 -87
  46. package/dist/controller/pivot-grid.d.ts +36 -0
  47. package/dist/controller/pivot-grid.js +99 -0
  48. package/dist/controller/prev-next.d.ts +2 -2
  49. package/dist/controller/prev-next.js +74 -54
  50. package/dist/controller/record-controllers.d.ts +14 -6
  51. package/dist/controller/record-controllers.js +288 -257
  52. package/dist/controller/record-diff.d.ts +21 -0
  53. package/dist/controller/record-diff.js +50 -0
  54. package/dist/controller/record-timeline.d.ts +35 -0
  55. package/dist/controller/record-timeline.js +48 -0
  56. package/dist/controller/record-tree.js +57 -47
  57. package/dist/controller/record-workflow.d.ts +38 -16
  58. package/dist/controller/record-workflow.js +85 -64
  59. package/dist/controller/reference-many-controller.js +198 -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 +2 -1
  65. package/dist/csv/export.js +43 -40
  66. package/dist/csv/import-controller.js +185 -169
  67. package/dist/csv/match-headers.js +29 -22
  68. package/dist/csv/parse-with.js +60 -54
  69. package/dist/csv/run-import.js +69 -72
  70. package/dist/csv/validate-rows.d.ts +1 -1
  71. package/dist/csv/validate-rows.js +65 -52
  72. package/dist/data/cache-ops.d.ts +5 -4
  73. package/dist/data/cache-ops.js +208 -190
  74. package/dist/data/combine-data-providers.js +25 -23
  75. package/dist/data/data-provider-log.d.ts +45 -0
  76. package/dist/data/data-provider-log.js +93 -0
  77. package/dist/data/errors.js +14 -10
  78. package/dist/data/fake-provider.d.ts +6 -3
  79. package/dist/data/fake-provider.js +129 -114
  80. package/dist/data/fetch-utils.js +61 -44
  81. package/dist/data/filter-branch.d.ts +5 -0
  82. package/dist/data/filter-branch.js +10 -0
  83. package/dist/data/get-many-aggregate.js +84 -76
  84. package/dist/data/http-error.js +17 -12
  85. package/dist/data/keys.js +50 -36
  86. package/dist/data/mutation-options.d.ts +14 -9
  87. package/dist/data/mutation-options.js +93 -109
  88. package/dist/data/query-options.js +73 -68
  89. package/dist/data/remove-empty.d.ts +3 -0
  90. package/dist/data/remove-empty.js +11 -0
  91. package/dist/data/undoable.d.ts +2 -2
  92. package/dist/data/undoable.js +190 -174
  93. package/dist/data/with-lifecycle-callbacks.d.ts +45 -17
  94. package/dist/data/with-lifecycle-callbacks.js +66 -52
  95. package/dist/environment/application-update-store.js +58 -55
  96. package/dist/environment/offline-store.js +21 -21
  97. package/dist/form/array-binding.d.ts +30 -11
  98. package/dist/form/array-binding.js +184 -166
  99. package/dist/form/choice-ids.d.ts +7 -0
  100. package/dist/form/choice-ids.js +11 -0
  101. package/dist/form/choices-controller.d.ts +3 -2
  102. package/dist/form/choices-controller.js +302 -275
  103. package/dist/form/date-format.d.ts +38 -0
  104. package/dist/form/date-format.js +89 -0
  105. package/dist/form/dirty-values.d.ts +2 -2
  106. package/dist/form/dirty-values.js +22 -11
  107. package/dist/form/duration.d.ts +22 -0
  108. package/dist/form/duration.js +49 -0
  109. package/dist/form/edit-create-form.d.ts +12 -5
  110. package/dist/form/edit-create-form.js +243 -188
  111. package/dist/form/event-value.d.ts +6 -0
  112. package/dist/form/event-value.js +17 -0
  113. package/dist/form/field-error.d.ts +14 -0
  114. package/dist/form/field-error.js +28 -0
  115. package/dist/form/field-name.d.ts +20 -0
  116. package/dist/form/field-name.js +6 -0
  117. package/dist/form/filter-form-values.js +63 -49
  118. package/dist/form/form-controller.d.ts +9 -1
  119. package/dist/form/form-controller.js +165 -160
  120. package/dist/form/form-groups.d.ts +4 -3
  121. package/dist/form/form-groups.js +79 -79
  122. package/dist/form/form-handle.d.ts +175 -0
  123. package/dist/form/form-handle.js +68 -0
  124. package/dist/form/input-binding.d.ts +56 -31
  125. package/dist/form/input-binding.js +169 -118
  126. package/dist/form/input-values.d.ts +130 -0
  127. package/dist/form/input-values.js +177 -0
  128. package/dist/form/json-text.js +51 -37
  129. package/dist/form/save-pipeline.d.ts +6 -8
  130. package/dist/form/save-pipeline.js +91 -82
  131. package/dist/form/set-form-values.d.ts +6 -0
  132. package/dist/form/set-form-values.js +10 -0
  133. package/dist/form/source.js +97 -65
  134. package/dist/form/text-of.d.ts +2 -0
  135. package/dist/form/text-of.js +7 -0
  136. package/dist/form/validators.d.ts +58 -19
  137. package/dist/form/validators.js +97 -71
  138. package/dist/geo/bbox.d.ts +5 -4
  139. package/dist/geo/bbox.js +69 -48
  140. package/dist/geo/bounds.d.ts +14 -3
  141. package/dist/geo/bounds.js +98 -68
  142. package/dist/geo/constraints.js +88 -93
  143. package/dist/geo/coordinates.js +31 -23
  144. package/dist/geo/editor.d.ts +13 -13
  145. package/dist/geo/editor.js +176 -153
  146. package/dist/geo/geocoding.d.ts +4 -4
  147. package/dist/geo/geocoding.js +38 -41
  148. package/dist/geo/geojson.d.ts +12 -74
  149. package/dist/geo/geojson.js +52 -40
  150. package/dist/geo/geometry-math.d.ts +4 -4
  151. package/dist/geo/geometry-math.js +100 -93
  152. package/dist/geo/index.d.ts +7 -6
  153. package/dist/geo/map-layers.d.ts +42 -7
  154. package/dist/geo/map-layers.js +88 -62
  155. package/dist/geo/map-style.js +31 -32
  156. package/dist/geo/messages.js +48 -45
  157. package/dist/geo/nominatim.js +88 -80
  158. package/dist/geo/osm-presets.d.ts +4 -3
  159. package/dist/geo/osm-presets.js +108 -86
  160. package/dist/geo/osm-tags.js +14 -12
  161. package/dist/geo/overpass.d.ts +14 -2
  162. package/dist/geo/overpass.js +83 -90
  163. package/dist/geo/shape-value.d.ts +9 -5
  164. package/dist/geo/shape-value.js +169 -146
  165. package/dist/geo/snap-to-roads.d.ts +3 -3
  166. package/dist/geo/snap-to-roads.js +55 -50
  167. package/dist/geo/throttle.js +36 -39
  168. package/dist/guards.d.ts +37 -0
  169. package/dist/guards.js +62 -0
  170. package/dist/i18n/default-messages.js +34 -29
  171. package/dist/i18n/english-messages.js +187 -189
  172. package/dist/i18n/i18n.d.ts +8 -2
  173. package/dist/i18n/i18n.js +47 -48
  174. package/dist/i18n/inflection.d.ts +34 -0
  175. package/dist/i18n/inflection.js +82 -0
  176. package/dist/i18n/messages.d.ts +10 -2
  177. package/dist/i18n/messages.js +17 -4
  178. package/dist/i18n/missing-keys.d.ts +19 -0
  179. package/dist/i18n/missing-keys.js +68 -0
  180. package/dist/i18n/translatable.d.ts +16 -1
  181. package/dist/i18n/translatable.js +40 -47
  182. package/dist/index.d.ts +96 -22
  183. package/dist/index.js +52 -257
  184. package/dist/json/deep-equal.d.ts +8 -0
  185. package/dist/json/deep-equal.js +24 -0
  186. package/dist/json/strip-json-comments.js +38 -42
  187. package/dist/noop.d.ts +2 -0
  188. package/dist/noop.js +4 -0
  189. package/dist/notification/error-message.d.ts +2 -0
  190. package/dist/notification/error-message.js +10 -0
  191. package/dist/notification/notification-store.d.ts +3 -2
  192. package/dist/notification/notification-store.js +41 -45
  193. package/dist/onboarding-tour/placement.d.ts +34 -0
  194. package/dist/onboarding-tour/placement.js +67 -0
  195. package/dist/onboarding-tour/tour-controller.d.ts +25 -0
  196. package/dist/onboarding-tour/tour-controller.js +50 -0
  197. package/dist/realtime/add-events-for-mutations.js +75 -81
  198. package/dist/realtime/announce-lock.d.ts +7 -0
  199. package/dist/realtime/announce-lock.js +18 -0
  200. package/dist/realtime/broadcast-channel-transport.d.ts +14 -0
  201. package/dist/realtime/broadcast-channel-transport.js +69 -0
  202. package/dist/realtime/copy-members.js +22 -14
  203. package/dist/realtime/in-memory-lock-provider.js +41 -60
  204. package/dist/realtime/live.js +95 -101
  205. package/dist/realtime/lock-options.js +16 -16
  206. package/dist/realtime/lock-session.js +91 -78
  207. package/dist/realtime/memory-transport.js +26 -67
  208. package/dist/realtime/presence.js +120 -122
  209. package/dist/realtime/realtime-data-provider.d.ts +10 -0
  210. package/dist/realtime/realtime-data-provider.js +45 -42
  211. package/dist/realtime/reconnect-backoff.d.ts +15 -0
  212. package/dist/realtime/reconnect-backoff.js +17 -0
  213. package/dist/realtime/sse-transport.d.ts +31 -0
  214. package/dist/realtime/sse-transport.js +235 -0
  215. package/dist/realtime/status-store.js +23 -28
  216. package/dist/realtime/topic-hub.d.ts +24 -0
  217. package/dist/realtime/topic-hub.js +66 -0
  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 +232 -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 +16 -1
  236. package/dist/rich-text/rich-text-extras.d.ts +132 -0
  237. package/dist/rich-text/rich-text-extras.js +179 -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 +62 -0
  241. package/dist/rich-text/rich-text.js +142 -0
  242. package/dist/router/location.d.ts +22 -4
  243. package/dist/router/location.js +41 -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/package.json +13 -11
@@ -2,174 +2,190 @@ 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
+ var asError = (error) => error instanceof Error ? error : new Error(String(error));
7
13
  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
- };
14
+ const fromSchema = csvSchemaFields(options.schema);
15
+ const explicitFields = options.fields ?? fromSchema.fields;
16
+ const requiredFields = options.requiredFields ?? (options.fields ? [] : fromSchema.required);
17
+ const initialMapping = options.mapping ?? {};
18
+ const initial = () => ({
19
+ step: "upload",
20
+ fileName: null,
21
+ headers: [],
22
+ rows: [],
23
+ parseError: null,
24
+ fields: explicitFields,
25
+ requiredFields,
26
+ mapping: initialMapping,
27
+ validations: [],
28
+ progress: {
29
+ current: 0,
30
+ total: 0
31
+ },
32
+ status: "idle",
33
+ report: null,
34
+ error: null
35
+ });
36
+ const store = createMicroStore(initial());
37
+ const state = () => store.getSnapshot();
38
+ let mappingSettled = Object.keys(initialMapping).length > 0;
39
+ let generation = 0;
40
+ let busy = false;
41
+ let created = false;
42
+ let abort;
43
+ const startImport = () => {
44
+ const run = ++generation;
45
+ const controller = new AbortController();
46
+ abort = controller;
47
+ const validations = state().validations;
48
+ const total = validations.filter((v) => v.ok).length;
49
+ store.setState({
50
+ status: "running",
51
+ progress: {
52
+ current: 0,
53
+ total
54
+ },
55
+ report: null,
56
+ error: null
57
+ });
58
+ (async () => {
59
+ let report;
60
+ try {
61
+ report = await runCsvImport({
62
+ dataProvider: options.dataProvider,
63
+ resource: options.resource,
64
+ validations,
65
+ ...options.batchSize !== void 0 && { batchSize: options.batchSize },
66
+ signal: controller.signal,
67
+ onProgress: (progress) => {
68
+ if (run === generation) store.setState({ progress });
69
+ }
70
+ });
71
+ } catch (thrown) {
72
+ if (run !== generation) return;
73
+ const error = asError(thrown);
74
+ store.setState({
75
+ status: "failed",
76
+ error
77
+ });
78
+ options.onError?.(error);
79
+ return;
80
+ }
81
+ if (run !== generation) return;
82
+ if (report.created > 0) created = true;
83
+ store.setState({
84
+ status: "done",
85
+ report
86
+ });
87
+ options.onComplete?.(report);
88
+ })();
89
+ };
90
+ const gate = (step) => {
91
+ const s = state();
92
+ switch (step) {
93
+ case "upload": return s.rows.length > 0 && s.parseError === null;
94
+ case "map": return s.requiredFields.every((field) => !!s.mapping[field]) && Object.values(s.mapping).some(Boolean);
95
+ case "preview": return !created && s.validations.some((v) => v.ok);
96
+ case "commit": return false;
97
+ }
98
+ };
99
+ return {
100
+ store,
101
+ loadParsed(parsed, fileName) {
102
+ if (state().status === "running" || busy) return;
103
+ const first = parsed.errors[0];
104
+ const parseError = first ? first.row === void 0 ? first.message : `Row ${first.row}: ${first.message}` : null;
105
+ const fields = explicitFields.length > 0 ? explicitFields : parsed.headers;
106
+ mappingSettled = Object.keys(initialMapping).length > 0;
107
+ created = false;
108
+ store.setState({
109
+ ...initial(),
110
+ fileName: fileName ?? null,
111
+ headers: parsed.headers,
112
+ rows: parseError === null ? parsed.rows : [],
113
+ parseError,
114
+ fields
115
+ });
116
+ },
117
+ setMapping(field, header) {
118
+ if (busy) return;
119
+ mappingSettled = true;
120
+ store.setState((prev) => ({ mapping: {
121
+ ...prev.mapping,
122
+ [field]: header
123
+ } }));
124
+ },
125
+ async next() {
126
+ if (busy) return false;
127
+ const s = state();
128
+ if (s.status === "running") return false;
129
+ const target = STEPS[STEPS.indexOf(s.step) + 1];
130
+ if (!target || !gate(s.step)) return false;
131
+ if (target === "map") {
132
+ if (!mappingSettled) {
133
+ mappingSettled = true;
134
+ const mapping = explicitFields.length > 0 ? matchCsvHeaders(s.fields, s.headers) : Object.fromEntries(s.headers.map((h) => [h, h]));
135
+ store.setState({ mapping });
136
+ }
137
+ store.setState({ step: "map" });
138
+ } else if (target === "preview") {
139
+ busy = true;
140
+ const run = generation;
141
+ try {
142
+ const validations = await validateCsvRows(s.rows, {
143
+ mapping: s.mapping,
144
+ ...options.schema && { schema: options.schema },
145
+ ...options.transform && { transform: options.transform }
146
+ });
147
+ if (run !== generation) return false;
148
+ store.setState({
149
+ validations,
150
+ step: "preview"
151
+ });
152
+ } finally {
153
+ if (run === generation) busy = false;
154
+ }
155
+ } else {
156
+ store.setState({ step: "commit" });
157
+ startImport();
158
+ }
159
+ return true;
160
+ },
161
+ back() {
162
+ const s = state();
163
+ if (s.status === "running" || busy) return;
164
+ const previous = STEPS[STEPS.indexOf(s.step) - 1];
165
+ if (!previous) return;
166
+ store.setState({
167
+ step: previous,
168
+ status: "idle",
169
+ report: null,
170
+ error: null,
171
+ progress: {
172
+ current: 0,
173
+ total: 0
174
+ }
175
+ });
176
+ },
177
+ cancel() {
178
+ abort?.abort();
179
+ },
180
+ reset() {
181
+ generation += 1;
182
+ abort?.abort();
183
+ abort = void 0;
184
+ busy = false;
185
+ created = false;
186
+ mappingSettled = Object.keys(initialMapping).length > 0;
187
+ store.setState(initial());
188
+ }
189
+ };
172
190
  }
173
- export {
174
- createCsvImportController
175
- };
191
+ export { 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 };