@dataverse-kit/export-engine 1.5.0 → 1.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -14359,7 +14359,8 @@ function buildGridCommandHandlerBlock(args) {
14359
14359
  itemsExpr,
14360
14360
  selectionExpr,
14361
14361
  exportColumnsLiteral,
14362
- createColumnsLiteral
14362
+ createColumnsLiteral,
14363
+ addExisting
14363
14364
  } = args;
14364
14365
  const exportCase = exportColumnsLiteral ? `{
14365
14366
  const exportColumns = [${exportColumnsLiteral}];
@@ -14431,6 +14432,36 @@ function buildGridCommandHandlerBlock(args) {
14431
14432
  }
14432
14433
  return;
14433
14434
  }`;
14435
+ const addExistingStateBlock = addExisting ? `
14436
+ const gridAddExistingMutation = useUpdateRecord<Record<string, unknown>>('${addExisting.childEntitySet}');` : "";
14437
+ const addExistingCase = addExisting ? `{
14438
+ const parentId = selectedIds[0];
14439
+ if (!parentId) {
14440
+ console.warn('[grid] Select or open a parent record before adding an existing ${addExisting.childEntityLogical}.');
14441
+ return;
14442
+ }
14443
+ const lookup = (xrm as { Utility?: { lookupObjects?: (opts: unknown) => Promise<Array<{ id: string }>> } } | undefined)?.Utility;
14444
+ if (lookup?.lookupObjects) {
14445
+ const picked = await lookup.lookupObjects({ entityTypes: ['${addExisting.childEntityLogical}'], allowMultiSelect: true });
14446
+ if (!picked || picked.length === 0) return;
14447
+ for (const rec of picked) {
14448
+ const childId = String(rec.id).replace(/[{}]/g, '');
14449
+ await gridAddExistingMutation.mutateAsync({ id: childId, data: { '${addExisting.childField}@odata.bind': '/${addExisting.parentEntitySet}(' + parentId + ')' } as Record<string, unknown> });
14450
+ }
14451
+ await refreshGrid();
14452
+ } else {
14453
+ console.warn('[grid] Add Existing requires Xrm.Utility.lookupObjects; not available in this host.');
14454
+ }
14455
+ return;
14456
+ }` : `{
14457
+ if (xrm?.Navigation?.openForm) {
14458
+ await xrm.Navigation.openForm({ entityName: '${entityName}' });
14459
+ await refreshGrid();
14460
+ } else {
14461
+ console.warn('[grid] Add Existing requires Xrm.Navigation; not available in this host.');
14462
+ }
14463
+ return;
14464
+ }`;
14434
14465
  return `
14435
14466
  const queryClient = useQueryClient();
14436
14467
  const gridUpdateMutation = useUpdateRecord<Record<string, unknown>>('${entitySetName}');
@@ -14454,7 +14485,7 @@ function buildGridCommandHandlerBlock(args) {
14454
14485
  } catch (err) {
14455
14486
  setDeleteError((err as Error)?.message ?? 'Delete failed.');
14456
14487
  }
14457
- }, [pendingDelete, gridDeleteMutation]);${createStateBlock}
14488
+ }, [pendingDelete, gridDeleteMutation]);${createStateBlock}${addExistingStateBlock}
14458
14489
  const handleGridCommand = React.useCallback(async (actionType: string, overrideRowIndex?: number) => {
14459
14490
  const xrm = (typeof window !== 'undefined' ? (window as unknown as { Xrm?: any }).Xrm : undefined);
14460
14491
  const items = ${itemsExpr} as ReadonlyArray<Record<string, unknown>>;
@@ -14480,15 +14511,7 @@ function buildGridCommandHandlerBlock(args) {
14480
14511
  };
14481
14512
  switch (actionType) {
14482
14513
  case 'new': ${newCase}
14483
- case 'addExisting': {
14484
- if (xrm?.Navigation?.openForm) {
14485
- await xrm.Navigation.openForm({ entityName: '${entityName}' });
14486
- await refreshGrid();
14487
- } else {
14488
- console.warn('[grid] Add Existing requires Xrm.Navigation; not available in this host.');
14489
- }
14490
- return;
14491
- }
14514
+ case 'addExisting': ${addExistingCase}
14492
14515
  case 'edit': {
14493
14516
  if (!requireSel('edit')) return;
14494
14517
  if (selectedIds.length > 1 && xrm?.Navigation?.openBulkEditForm) {
@@ -14538,7 +14561,7 @@ function buildGridCommandHandlerBlock(args) {
14538
14561
  default:
14539
14562
  return;
14540
14563
  }
14541
- }, [${itemsExpr}, ${selectionExpr}, gridUpdateMutation, refreshGrid]);`;
14564
+ }, [${itemsExpr}, ${selectionExpr}, gridUpdateMutation, refreshGrid${addExisting ? ", gridAddExistingMutation" : ""}]);`;
14542
14565
  }
14543
14566
  function buildRowCommandsLiteral(contextMenuItems) {
14544
14567
  return contextMenuItems.filter((ci) => (ci.actionType ?? "custom") !== "custom").filter((ci) => ci.actionType !== "new").map(
@@ -15001,12 +15024,18 @@ function generateLinkedSubgrid(gridDef, entityName, imports, library = "fluent-v
15001
15024
  const showRefresh = gridDef.toolbar?.showRefresh ?? false;
15002
15025
  const showColumnChooser = gridDef.toolbar?.showColumnChooser ?? false;
15003
15026
  const hasToolbarIcons = showFilters || showViewToggle || showExport || showRefresh || showColumnChooser;
15027
+ const childGridDef = gridDef.nestedGridId ? _currentGridCustomizers.find((g) => g.id === gridDef.nestedGridId) : void 0;
15028
+ const _aeRel = gridDef.nestedRelationship;
15029
+ const addExistingFeasible = Boolean(
15030
+ childGridDef && _includeDataAccessLayer && _aeRel?.relationshipType === "OneToMany" && _aeRel?.parentField && _aeRel?.childField && gridDef.dataSource?.entitySetName && gridDef.dataSource?.fetchXml && childGridDef.dataSource?.entitySetName && childGridDef.dataSource?.entityName && childGridDef.dataSource?.fetchXml
15031
+ );
15004
15032
  const barItems = (gridDef.commandBarItems ?? []).filter(
15005
15033
  (ci) => ci.visibility === "commandBar" || ci.visibility === "both" || !ci.visibility
15006
- );
15034
+ ).filter((ci) => ci.actionType !== "addExisting" || addExistingFeasible);
15007
15035
  const contextMenuItems = (gridDef.commandBarItems ?? []).filter(
15008
15036
  (ci) => ci.visibility === "contextMenu" || ci.visibility === "both" || !ci.visibility
15009
- );
15037
+ ).filter((ci) => ci.actionType !== "addExisting" || addExistingFeasible);
15038
+ const enableAddExisting = addExistingFeasible && (barItems.some((ci) => ci.actionType === "addExisting") || contextMenuItems.some((ci) => ci.actionType === "addExisting"));
15010
15039
  const _handlerAvailable = (
15011
15040
  // The dispatcher calls useUpdateRecord/useDeleteRecord/useQueryClient — which only
15012
15041
  // exist (module + provider + dep) when the data-access layer is included. Without it,
@@ -15095,7 +15124,6 @@ function generateLinkedSubgrid(gridDef, entityName, imports, library = "fluent-v
15095
15124
  </div>
15096
15125
  </div>`;
15097
15126
  }
15098
- const childGridDef = gridDef.nestedGridId ? _currentGridCustomizers.find((g) => g.id === gridDef.nestedGridId) : void 0;
15099
15127
  const isGridKitNested = !!childGridDef;
15100
15128
  const visibleCols = [...gridDef.columns].filter((c) => c.isVisible).sort((a, b) => a.order - b.order);
15101
15129
  const exportColumnsLiteral = enableExport ? buildExportColumnsLiteral(visibleCols) : "";
@@ -15168,7 +15196,18 @@ ${childEntries.join(",\n")},
15168
15196
  itemsExpr: "keyedItems",
15169
15197
  selectionExpr: "selectedIndices",
15170
15198
  exportColumnsLiteral,
15171
- createColumnsLiteral
15199
+ createColumnsLiteral,
15200
+ // Associate an existing child to the clicked/active parent (the ONLY call site
15201
+ // that wires it). Shared by the nested AND focused-view emitters below — both
15202
+ // reuse this ngHandlerBlock. Gated on enableAddExisting (feasible AND an
15203
+ // addExisting item present); the && chain narrows the optional entity-set strings
15204
+ // to `string` (enableAddExisting ⟹ addExistingFeasible guarantees they're present).
15205
+ addExisting: enableAddExisting && childEntitySet && childEntityLogical && parentEntitySet && nestedRel?.childField ? {
15206
+ childEntitySet,
15207
+ childEntityLogical,
15208
+ childField: nestedRel.childField,
15209
+ parentEntitySet
15210
+ } : null
15172
15211
  }) : "";
15173
15212
  const ngHasDelete = (gridDef.commandBarItems ?? []).some(
15174
15213
  (ci) => ci.actionType === "delete"
@@ -15399,7 +15438,9 @@ ${childEntries.join(",\n")},
15399
15438
  itemsExpr: "rows",
15400
15439
  selectionExpr: "selectedIndices",
15401
15440
  exportColumnsLiteral,
15402
- createColumnsLiteral
15441
+ createColumnsLiteral,
15442
+ addExisting: null
15443
+ // flat (no parent relationship) → addExisting filtered out above
15403
15444
  }) : "";
15404
15445
  const cardSelectedIndicesState = cardEmitHandler ? "\n const [selectedIndices, setSelectedIndices] = React.useState<Set<number>>(new Set());" : "";
15405
15446
  const cardRowCommandsLiteral = cardEmitRowCommands ? buildRowCommandsLiteral(contextMenuItems) : "";
@@ -15493,7 +15534,9 @@ ${childEntries.join(",\n")},
15493
15534
  itemsExpr: "rows",
15494
15535
  selectionExpr: "selectedIndices",
15495
15536
  exportColumnsLiteral,
15496
- createColumnsLiteral
15537
+ createColumnsLiteral,
15538
+ addExisting: null
15539
+ // flat (no parent relationship) → addExisting filtered out above
15497
15540
  }) : "";
15498
15541
  const roSelectedIndicesState = roEmitHandler ? "\n const [selectedIndices, setSelectedIndices] = React.useState<Set<number>>(new Set());" : "";
15499
15542
  const roRowCommandsLiteral = roEmitRowCommands ? buildRowCommandsLiteral(contextMenuItems) : "";
@@ -15605,7 +15648,9 @@ const ${liveWrapperName}: React.FC = () => {
15605
15648
  itemsExpr: "keyedItems",
15606
15649
  selectionExpr: "selectedIndices",
15607
15650
  exportColumnsLiteral,
15608
- createColumnsLiteral
15651
+ createColumnsLiteral,
15652
+ addExisting: null
15653
+ // flat (no parent relationship) → addExisting filtered out above
15609
15654
  }) : "";
15610
15655
  const edSelectedIndicesState = edEmitHandler ? "\n const [selectedIndices, setSelectedIndices] = React.useState<Set<number>>(new Set());" : "";
15611
15656
  const edRowCommandsLiteral = edEmitRowCommands ? buildRowCommandsLiteral(contextMenuItems) : "";
@@ -18465,6 +18510,19 @@ ${code}
18465
18510
  };
18466
18511
  `;
18467
18512
  }
18513
+ function dedupeImportStatements(content) {
18514
+ const isImportLine = (l) => /^import\b[^\n]*\bfrom\b[^\n]*;[ \t]*$/.test(l) || /^import\s+['"][^'"]+['"];[ \t]*$/.test(l);
18515
+ const seen = /* @__PURE__ */ new Set();
18516
+ const out = [];
18517
+ for (const line of content.split("\n")) {
18518
+ if (isImportLine(line)) {
18519
+ if (seen.has(line)) continue;
18520
+ seen.add(line);
18521
+ }
18522
+ out.push(line);
18523
+ }
18524
+ return out.join("\n");
18525
+ }
18468
18526
  function generateFormCode(form, options) {
18469
18527
  _currentGridCustomizers = options?.gridCustomizers ?? [];
18470
18528
  _includeSampleData = options?.includeSampleData ?? false;
@@ -18495,6 +18553,7 @@ function generateFormCode(form, options) {
18495
18553
  default:
18496
18554
  content = generateMainForm(form, hasRules, library);
18497
18555
  }
18556
+ content = dedupeImportStatements(content);
18498
18557
  const files = [
18499
18558
  { path: `src/components/${fileName}`, content }
18500
18559
  ];
package/dist/index.d.cts CHANGED
@@ -148,7 +148,6 @@ interface GenerateFormCodeOptions {
148
148
  */
149
149
  componentLibrary?: 'fluent-v8' | 'fluent-v9';
150
150
  }
151
- /** Generate React component source files from a FormDefinition. */
152
151
  declare function generateFormCode(form: FormDefinition, options?: GenerateFormCodeOptions): GeneratedFile[];
153
152
  /** Options for `generateAllFormCode`. */
154
153
  interface GenerateAllFormCodeOptions {
package/dist/index.d.ts CHANGED
@@ -148,7 +148,6 @@ interface GenerateFormCodeOptions {
148
148
  */
149
149
  componentLibrary?: 'fluent-v8' | 'fluent-v9';
150
150
  }
151
- /** Generate React component source files from a FormDefinition. */
152
151
  declare function generateFormCode(form: FormDefinition, options?: GenerateFormCodeOptions): GeneratedFile[];
153
152
  /** Options for `generateAllFormCode`. */
154
153
  interface GenerateAllFormCodeOptions {
package/dist/index.mjs CHANGED
@@ -14339,7 +14339,8 @@ function buildGridCommandHandlerBlock(args) {
14339
14339
  itemsExpr,
14340
14340
  selectionExpr,
14341
14341
  exportColumnsLiteral,
14342
- createColumnsLiteral
14342
+ createColumnsLiteral,
14343
+ addExisting
14343
14344
  } = args;
14344
14345
  const exportCase = exportColumnsLiteral ? `{
14345
14346
  const exportColumns = [${exportColumnsLiteral}];
@@ -14411,6 +14412,36 @@ function buildGridCommandHandlerBlock(args) {
14411
14412
  }
14412
14413
  return;
14413
14414
  }`;
14415
+ const addExistingStateBlock = addExisting ? `
14416
+ const gridAddExistingMutation = useUpdateRecord<Record<string, unknown>>('${addExisting.childEntitySet}');` : "";
14417
+ const addExistingCase = addExisting ? `{
14418
+ const parentId = selectedIds[0];
14419
+ if (!parentId) {
14420
+ console.warn('[grid] Select or open a parent record before adding an existing ${addExisting.childEntityLogical}.');
14421
+ return;
14422
+ }
14423
+ const lookup = (xrm as { Utility?: { lookupObjects?: (opts: unknown) => Promise<Array<{ id: string }>> } } | undefined)?.Utility;
14424
+ if (lookup?.lookupObjects) {
14425
+ const picked = await lookup.lookupObjects({ entityTypes: ['${addExisting.childEntityLogical}'], allowMultiSelect: true });
14426
+ if (!picked || picked.length === 0) return;
14427
+ for (const rec of picked) {
14428
+ const childId = String(rec.id).replace(/[{}]/g, '');
14429
+ await gridAddExistingMutation.mutateAsync({ id: childId, data: { '${addExisting.childField}@odata.bind': '/${addExisting.parentEntitySet}(' + parentId + ')' } as Record<string, unknown> });
14430
+ }
14431
+ await refreshGrid();
14432
+ } else {
14433
+ console.warn('[grid] Add Existing requires Xrm.Utility.lookupObjects; not available in this host.');
14434
+ }
14435
+ return;
14436
+ }` : `{
14437
+ if (xrm?.Navigation?.openForm) {
14438
+ await xrm.Navigation.openForm({ entityName: '${entityName}' });
14439
+ await refreshGrid();
14440
+ } else {
14441
+ console.warn('[grid] Add Existing requires Xrm.Navigation; not available in this host.');
14442
+ }
14443
+ return;
14444
+ }`;
14414
14445
  return `
14415
14446
  const queryClient = useQueryClient();
14416
14447
  const gridUpdateMutation = useUpdateRecord<Record<string, unknown>>('${entitySetName}');
@@ -14434,7 +14465,7 @@ function buildGridCommandHandlerBlock(args) {
14434
14465
  } catch (err) {
14435
14466
  setDeleteError((err as Error)?.message ?? 'Delete failed.');
14436
14467
  }
14437
- }, [pendingDelete, gridDeleteMutation]);${createStateBlock}
14468
+ }, [pendingDelete, gridDeleteMutation]);${createStateBlock}${addExistingStateBlock}
14438
14469
  const handleGridCommand = React.useCallback(async (actionType: string, overrideRowIndex?: number) => {
14439
14470
  const xrm = (typeof window !== 'undefined' ? (window as unknown as { Xrm?: any }).Xrm : undefined);
14440
14471
  const items = ${itemsExpr} as ReadonlyArray<Record<string, unknown>>;
@@ -14460,15 +14491,7 @@ function buildGridCommandHandlerBlock(args) {
14460
14491
  };
14461
14492
  switch (actionType) {
14462
14493
  case 'new': ${newCase}
14463
- case 'addExisting': {
14464
- if (xrm?.Navigation?.openForm) {
14465
- await xrm.Navigation.openForm({ entityName: '${entityName}' });
14466
- await refreshGrid();
14467
- } else {
14468
- console.warn('[grid] Add Existing requires Xrm.Navigation; not available in this host.');
14469
- }
14470
- return;
14471
- }
14494
+ case 'addExisting': ${addExistingCase}
14472
14495
  case 'edit': {
14473
14496
  if (!requireSel('edit')) return;
14474
14497
  if (selectedIds.length > 1 && xrm?.Navigation?.openBulkEditForm) {
@@ -14518,7 +14541,7 @@ function buildGridCommandHandlerBlock(args) {
14518
14541
  default:
14519
14542
  return;
14520
14543
  }
14521
- }, [${itemsExpr}, ${selectionExpr}, gridUpdateMutation, refreshGrid]);`;
14544
+ }, [${itemsExpr}, ${selectionExpr}, gridUpdateMutation, refreshGrid${addExisting ? ", gridAddExistingMutation" : ""}]);`;
14522
14545
  }
14523
14546
  function buildRowCommandsLiteral(contextMenuItems) {
14524
14547
  return contextMenuItems.filter((ci) => (ci.actionType ?? "custom") !== "custom").filter((ci) => ci.actionType !== "new").map(
@@ -14981,12 +15004,18 @@ function generateLinkedSubgrid(gridDef, entityName, imports, library = "fluent-v
14981
15004
  const showRefresh = gridDef.toolbar?.showRefresh ?? false;
14982
15005
  const showColumnChooser = gridDef.toolbar?.showColumnChooser ?? false;
14983
15006
  const hasToolbarIcons = showFilters || showViewToggle || showExport || showRefresh || showColumnChooser;
15007
+ const childGridDef = gridDef.nestedGridId ? _currentGridCustomizers.find((g) => g.id === gridDef.nestedGridId) : void 0;
15008
+ const _aeRel = gridDef.nestedRelationship;
15009
+ const addExistingFeasible = Boolean(
15010
+ childGridDef && _includeDataAccessLayer && _aeRel?.relationshipType === "OneToMany" && _aeRel?.parentField && _aeRel?.childField && gridDef.dataSource?.entitySetName && gridDef.dataSource?.fetchXml && childGridDef.dataSource?.entitySetName && childGridDef.dataSource?.entityName && childGridDef.dataSource?.fetchXml
15011
+ );
14984
15012
  const barItems = (gridDef.commandBarItems ?? []).filter(
14985
15013
  (ci) => ci.visibility === "commandBar" || ci.visibility === "both" || !ci.visibility
14986
- );
15014
+ ).filter((ci) => ci.actionType !== "addExisting" || addExistingFeasible);
14987
15015
  const contextMenuItems = (gridDef.commandBarItems ?? []).filter(
14988
15016
  (ci) => ci.visibility === "contextMenu" || ci.visibility === "both" || !ci.visibility
14989
- );
15017
+ ).filter((ci) => ci.actionType !== "addExisting" || addExistingFeasible);
15018
+ const enableAddExisting = addExistingFeasible && (barItems.some((ci) => ci.actionType === "addExisting") || contextMenuItems.some((ci) => ci.actionType === "addExisting"));
14990
15019
  const _handlerAvailable = (
14991
15020
  // The dispatcher calls useUpdateRecord/useDeleteRecord/useQueryClient — which only
14992
15021
  // exist (module + provider + dep) when the data-access layer is included. Without it,
@@ -15075,7 +15104,6 @@ function generateLinkedSubgrid(gridDef, entityName, imports, library = "fluent-v
15075
15104
  </div>
15076
15105
  </div>`;
15077
15106
  }
15078
- const childGridDef = gridDef.nestedGridId ? _currentGridCustomizers.find((g) => g.id === gridDef.nestedGridId) : void 0;
15079
15107
  const isGridKitNested = !!childGridDef;
15080
15108
  const visibleCols = [...gridDef.columns].filter((c) => c.isVisible).sort((a, b) => a.order - b.order);
15081
15109
  const exportColumnsLiteral = enableExport ? buildExportColumnsLiteral(visibleCols) : "";
@@ -15148,7 +15176,18 @@ ${childEntries.join(",\n")},
15148
15176
  itemsExpr: "keyedItems",
15149
15177
  selectionExpr: "selectedIndices",
15150
15178
  exportColumnsLiteral,
15151
- createColumnsLiteral
15179
+ createColumnsLiteral,
15180
+ // Associate an existing child to the clicked/active parent (the ONLY call site
15181
+ // that wires it). Shared by the nested AND focused-view emitters below — both
15182
+ // reuse this ngHandlerBlock. Gated on enableAddExisting (feasible AND an
15183
+ // addExisting item present); the && chain narrows the optional entity-set strings
15184
+ // to `string` (enableAddExisting ⟹ addExistingFeasible guarantees they're present).
15185
+ addExisting: enableAddExisting && childEntitySet && childEntityLogical && parentEntitySet && nestedRel?.childField ? {
15186
+ childEntitySet,
15187
+ childEntityLogical,
15188
+ childField: nestedRel.childField,
15189
+ parentEntitySet
15190
+ } : null
15152
15191
  }) : "";
15153
15192
  const ngHasDelete = (gridDef.commandBarItems ?? []).some(
15154
15193
  (ci) => ci.actionType === "delete"
@@ -15379,7 +15418,9 @@ ${childEntries.join(",\n")},
15379
15418
  itemsExpr: "rows",
15380
15419
  selectionExpr: "selectedIndices",
15381
15420
  exportColumnsLiteral,
15382
- createColumnsLiteral
15421
+ createColumnsLiteral,
15422
+ addExisting: null
15423
+ // flat (no parent relationship) → addExisting filtered out above
15383
15424
  }) : "";
15384
15425
  const cardSelectedIndicesState = cardEmitHandler ? "\n const [selectedIndices, setSelectedIndices] = React.useState<Set<number>>(new Set());" : "";
15385
15426
  const cardRowCommandsLiteral = cardEmitRowCommands ? buildRowCommandsLiteral(contextMenuItems) : "";
@@ -15473,7 +15514,9 @@ ${childEntries.join(",\n")},
15473
15514
  itemsExpr: "rows",
15474
15515
  selectionExpr: "selectedIndices",
15475
15516
  exportColumnsLiteral,
15476
- createColumnsLiteral
15517
+ createColumnsLiteral,
15518
+ addExisting: null
15519
+ // flat (no parent relationship) → addExisting filtered out above
15477
15520
  }) : "";
15478
15521
  const roSelectedIndicesState = roEmitHandler ? "\n const [selectedIndices, setSelectedIndices] = React.useState<Set<number>>(new Set());" : "";
15479
15522
  const roRowCommandsLiteral = roEmitRowCommands ? buildRowCommandsLiteral(contextMenuItems) : "";
@@ -15585,7 +15628,9 @@ const ${liveWrapperName}: React.FC = () => {
15585
15628
  itemsExpr: "keyedItems",
15586
15629
  selectionExpr: "selectedIndices",
15587
15630
  exportColumnsLiteral,
15588
- createColumnsLiteral
15631
+ createColumnsLiteral,
15632
+ addExisting: null
15633
+ // flat (no parent relationship) → addExisting filtered out above
15589
15634
  }) : "";
15590
15635
  const edSelectedIndicesState = edEmitHandler ? "\n const [selectedIndices, setSelectedIndices] = React.useState<Set<number>>(new Set());" : "";
15591
15636
  const edRowCommandsLiteral = edEmitRowCommands ? buildRowCommandsLiteral(contextMenuItems) : "";
@@ -18445,6 +18490,19 @@ ${code}
18445
18490
  };
18446
18491
  `;
18447
18492
  }
18493
+ function dedupeImportStatements(content) {
18494
+ const isImportLine = (l) => /^import\b[^\n]*\bfrom\b[^\n]*;[ \t]*$/.test(l) || /^import\s+['"][^'"]+['"];[ \t]*$/.test(l);
18495
+ const seen = /* @__PURE__ */ new Set();
18496
+ const out = [];
18497
+ for (const line of content.split("\n")) {
18498
+ if (isImportLine(line)) {
18499
+ if (seen.has(line)) continue;
18500
+ seen.add(line);
18501
+ }
18502
+ out.push(line);
18503
+ }
18504
+ return out.join("\n");
18505
+ }
18448
18506
  function generateFormCode(form, options) {
18449
18507
  _currentGridCustomizers = options?.gridCustomizers ?? [];
18450
18508
  _includeSampleData = options?.includeSampleData ?? false;
@@ -18475,6 +18533,7 @@ function generateFormCode(form, options) {
18475
18533
  default:
18476
18534
  content = generateMainForm(form, hasRules, library);
18477
18535
  }
18536
+ content = dedupeImportStatements(content);
18478
18537
  const files = [
18479
18538
  { path: `src/components/${fileName}`, content }
18480
18539
  ];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dataverse-kit/export-engine",
3
- "version": "1.5.0",
3
+ "version": "1.6.0",
4
4
  "type": "module",
5
5
  "main": "./dist/index.cjs",
6
6
  "module": "./dist/index.mjs",