lula2 0.6.4 → 0.6.5

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 (35) hide show
  1. package/README.md +3 -3
  2. package/dist/_app/immutable/assets/0.gNk4bE5Z.css +1 -0
  3. package/dist/_app/immutable/chunks/{DBdrJbLi.js → 6cSSDZaX.js} +1 -1
  4. package/dist/_app/immutable/chunks/{BaV6jU6m.js → BDFhLgJd.js} +1 -1
  5. package/dist/_app/immutable/chunks/{_8PUdHCK.js → BZU_Nz1O.js} +1 -1
  6. package/dist/_app/immutable/chunks/BnySH2DD.js +2 -0
  7. package/dist/_app/immutable/chunks/{sF1amBpw.js → CfxzrOg_.js} +1 -1
  8. package/dist/_app/immutable/chunks/{DG4ZcLIc.js → D2GS6lt_.js} +1 -1
  9. package/dist/_app/immutable/chunks/MY0vM1lA.js +3 -0
  10. package/dist/_app/immutable/chunks/{WNo48c2U.js → Vl8FMUTS.js} +1 -1
  11. package/dist/_app/immutable/chunks/{CynYS-Ma.js → ipJF3Ffx.js} +1 -1
  12. package/dist/_app/immutable/entry/{app.VdrAeFMF.js → app.XAEr8i-M.js} +2 -2
  13. package/dist/_app/immutable/entry/start.DCxCYu1M.js +1 -0
  14. package/dist/_app/immutable/nodes/0.DHn4BGVS.js +2 -0
  15. package/dist/_app/immutable/nodes/{1.Dt4-pegp.js → 1.BRVNZ7Zr.js} +1 -1
  16. package/dist/_app/immutable/nodes/{2.CgJgF2F1.js → 2.DjZVN6-v.js} +1 -1
  17. package/dist/_app/immutable/nodes/{3.DsDKmoyP.js → 3.BwkBTWlm.js} +1 -1
  18. package/dist/_app/immutable/nodes/{4.E9uJ4Np6.js → 4.CrrKXZL6.js} +1 -1
  19. package/dist/_app/version.json +1 -1
  20. package/dist/cli/commands/ui.js +49 -7
  21. package/dist/cli/server/index.js +49 -7
  22. package/dist/cli/server/server.js +49 -7
  23. package/dist/cli/server/serverState.js +37 -4
  24. package/dist/cli/server/spreadsheetRoutes.js +12 -3
  25. package/dist/cli/server/websocketServer.js +49 -7
  26. package/dist/index.html +10 -10
  27. package/dist/index.js +49 -7
  28. package/package.json +126 -126
  29. package/src/lib/components/dialogs/ExportColumnDialog.svelte +7 -5
  30. package/src/routes/+layout.svelte +1 -1
  31. package/dist/_app/immutable/assets/0.CJjXKESY.css +0 -1
  32. package/dist/_app/immutable/chunks/DmBJsPtc.js +0 -2
  33. package/dist/_app/immutable/chunks/DztCq-9O.js +0 -3
  34. package/dist/_app/immutable/entry/start.BD6MZ_XC.js +0 -1
  35. package/dist/_app/immutable/nodes/0.D3GkfY8V.js +0 -2
@@ -1,4 +1,4 @@
1
- import"../chunks/DsnmJJEf.js";import{i as We}from"../chunks/_8PUdHCK.js";import{p as Xe,am as Ve,d as a,T as k,G as pe,h as e,an as $r,ao as Ne,c as o,n as ke,r as t,b as d,e as Ke,J as P,K as I,ap as Nr,f as x,s as i,aq as c,a as we,ar as xr,aj as Ae,a3 as ze,ak as hr,al as tr,as as yr,k as de,o as ot,W as lt}from"../chunks/DmBJsPtc.js";import{l as ar,p as Ye,i as M,a as st,s as it}from"../chunks/BaV6jU6m.js";import{a as Lr,s as le,r as jr,e as ge,b as Je,c as Vr,d as _r,i as Cr,f as Sr,w as wr}from"../chunks/sF1amBpw.js";import{g as nt}from"../chunks/DztCq-9O.js";function dt(ue){return function(...U){var F=U[0];return F.stopPropagation(),ue?.apply(this,U)}}var vt=Ne("<title> </title>"),ct=Ne('<svg><!><path d="M11 18L12.41 19.41 15 16.83 15 29 17 29 17 16.83 19.59 19.41 21 18 16 13 11 18z"></path><path d="M23.5,22H23V20h.5a4.5,4.5,0,0,0,.36-9L23,11l-.1-.82a7,7,0,0,0-13.88,0L9,11,8.14,11a4.5,4.5,0,0,0,.36,9H9v2H8.5A6.5,6.5,0,0,1,7.2,9.14a9,9,0,0,1,17.6,0A6.5,6.5,0,0,1,23.5,22Z"></path></svg>');function gt(ue,U){const F=ar(U,["children","$$slots","$$events","$$legacy"]),J=ar(F,["size","title"]);Xe(U,!1);const E=k(),j=k();let Z=Ye(U,"size",8,16),b=Ye(U,"title",8,void 0);Ve(()=>(pe(F),pe(b())),()=>{a(E,F["aria-label"]||F["aria-labelledby"]||b())}),Ve(()=>(e(E),pe(F)),()=>{a(j,{"aria-hidden":e(E)?void 0:!0,role:e(E)?"img":void 0,focusable:Number(F.tabindex)===0?!0:void 0})}),$r(),We();var $=ct();Lr($,()=>({xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 32 32",fill:"currentColor",preserveAspectRatio:"xMidYMid meet",width:Z(),height:Z(),...e(j),...J}));var K=o($);{var G=H=>{var g=vt(),N=o(g,!0);t(g),P(()=>I(N,b())),d(H,g)};M(K,H=>{b()&&H(G)})}ke(2),t($),d(ue,$),Ke()}var pt=Ne("<title> </title>"),ut=Ne('<svg><!><path d="M10 6H14V10H10zM18 6H22V10H18zM10 14H14V18H10zM18 14H22V18H18zM10 22H14V26H10zM18 22H22V26H18z"></path></svg>');function kr(ue,U){const F=ar(U,["children","$$slots","$$events","$$legacy"]),J=ar(F,["size","title"]);Xe(U,!1);const E=k(),j=k();let Z=Ye(U,"size",8,16),b=Ye(U,"title",8,void 0);Ve(()=>(pe(F),pe(b())),()=>{a(E,F["aria-label"]||F["aria-labelledby"]||b())}),Ve(()=>(e(E),pe(F)),()=>{a(j,{"aria-hidden":e(E)?void 0:!0,role:e(E)?"img":void 0,focusable:Number(F.tabindex)===0?!0:void 0})}),$r(),We();var $=ut();Lr($,()=>({xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 32 32",fill:"currentColor",preserveAspectRatio:"xMidYMid meet",width:Z(),height:Z(),...e(j),...J}));var K=o($);{var G=H=>{var g=pt(),N=o(g,!0);t(g),P(()=>I(N,b())),d(H,g)};M(K,H=>{b()&&H(G)})}ke(),t($),d(ue,$),Ke()}var bt=x('<div class="p-4 text-sm text-blue-800 rounded-lg bg-blue-50 dark:bg-gray-800 dark:text-blue-400"><div class="flex items-center"><svg class="flex-shrink-0 inline w-4 h-4 mr-3" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 20 20"><path d="M10 .5a9.5 9.5 0 1 0 9.5 9.5A9.51 9.51 0 0 0 10 .5ZM9.5 4a1.5 1.5 0 1 1 0 3 1.5 1.5 0 0 1 0-3ZM12 15H8a1 1 0 0 1 0-2h1v-3H8a1 1 0 0 1 0-2h2a1 1 0 0 1 1 1v4h1a1 1 0 0 1 0 2Z"></path></svg> <div><span class="font-medium">File loaded:</span> <div class="mt-1"><span class="font-medium">Sheets:</span> <span class="font-medium">Fields:</span> <span class="font-medium">Controls found:</span> </div></div></div></div>'),ft=x('<div class="p-4 text-sm text-red-800 rounded-lg bg-red-50 dark:bg-gray-800 dark:text-red-400"><div class="flex items-center"><svg class="flex-shrink-0 inline w-4 h-4 mr-3" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 20 20"><path d="M10 .5a9.5 9.5 0 1 0 9.5 9.5A9.51 9.51 0 0 0 10 .5ZM9.5 4a1.5 1.5 0 1 1 0 3 1.5 1.5 0 0 1 0-3ZM12 15H8a1 1 0 0 1 0-2h1v-3H8a1 1 0 0 1 0-2h2a1 1 0 0 1 1 1v4h1a1 1 0 0 1 0 2Z"></path></svg> <span> </span></div></div>'),mt=x('<div class="p-4 text-sm text-green-800 rounded-lg bg-green-50 dark:bg-gray-800 dark:text-green-400"><div class="flex items-center"><svg class="flex-shrink-0 inline w-4 h-4 mr-3" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 20 20"><path d="M10 .5a9.5 9.5 0 1 0 9.5 9.5A9.51 9.51 0 0 0 10 .5ZM9.5 4a1.5 1.5 0 1 1 0 3 1.5 1.5 0 0 1 0-3ZM12 15H8a1 1 0 0 1 0-2h1v-3H8a1 1 0 0 1 0-2h2a1 1 0 0 1 1 1v4h1a1 1 0 0 1 0 2Z"></path></svg> <span> </span></div></div>'),xt=x("<option> </option>"),ht=x("<option> </option>"),yt=x("<option> </option>"),_t=x('<span class="ml-auto text-xs text-blue-600 dark:text-blue-400">ID</span>'),wt=x('<div draggable="true" role="button" tabindex="0" class="flex items-center px-3 py-2 bg-gray-100 dark:bg-gray-700 text-gray-500 dark:text-gray-400 rounded text-sm cursor-move hover:bg-gray-200 dark:hover:bg-gray-600 transition-colors opacity-75"><svg class="w-3 h-3 mr-2 flex-shrink-0" fill="currentColor" viewBox="0 0 20 20"><path d="M10 6a2 2 0 110-4 2 2 0 010 4zM10 12a2 2 0 110-4 2 2 0 010 4zM10 18a2 2 0 110-4 2 2 0 010 4z"></path></svg> <span class="truncate line-through"> </span> <!></div>'),kt=x('<p class="text-xs text-gray-400 dark:text-gray-500 text-center py-4">No excluded fields</p>'),Ct=x('<div draggable="true" role="button" tabindex="0"><!> <span class="truncate"> </span></div>'),St=x('<p class="text-xs text-gray-400 dark:text-gray-500 text-center py-4">Drop fields here</p>'),$t=x('<div draggable="true" role="button" tabindex="0"><!> <span class="truncate"> </span></div>'),Dt=x('<p class="text-xs text-gray-400 dark:text-gray-500 text-center py-4">Drop fields here</p>'),Mt=x('<div draggable="true" role="button" tabindex="0"><!> <span class="truncate"> </span></div>'),zt=x('<p class="text-xs text-gray-400 dark:text-gray-500 text-center py-4">Drop fields here</p>'),At=x('<div draggable="false" role="button" tabindex="0" class="flex items-center px-3 py-2 bg-orange-100 dark:bg-orange-900/30 text-orange-800 dark:text-orange-300 rounded text-sm hover:bg-orange-200 dark:hover:bg-orange-800/30 transition-colors"><span class="truncate"> </span> <button class="ml-auto text-gray-400 hover:text-red-500 dark:text-gray-500 dark:hover:text-red-400" title="Remove from mappings">×</button></div>'),Ft=x('<div role="region" aria-label="Justification field drop zone"><p class="text-xs text-gray-400 dark:text-gray-500 text-center py-4">Drop fields here</p></div>'),Ot=x('<th class="px-4 py-2"> </th>'),Pt=x('<td class="px-4 py-2"> </td>'),Ht=x('<tr class="bg-white border-b dark:bg-gray-800 dark:border-gray-700"></tr>'),Et=x('<div class="bg-gradient-to-br from-gray-50 to-gray-100 dark:from-gray-800 dark:to-gray-900 rounded-lg p-4 border border-gray-200 dark:border-gray-700"><h3 class="text-lg font-semibold text-gray-900 dark:text-white mb-4">Sample Data Preview</h3> <div class="overflow-x-auto"><table class="w-full text-sm text-left text-gray-500 dark:text-gray-400"><thead class="text-xs text-gray-700 uppercase bg-gray-100 dark:bg-gray-600 dark:text-gray-400"><tr></tr></thead><tbody></tbody></table></div></div>'),It=x('<span class="flex items-center"><svg class="animate-spin -ml-1 mr-3 h-5 w-5 text-white" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"><circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle><path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path></svg> Importing...</span>'),Tt=x(`<div class="bg-gradient-to-br from-gray-50 to-gray-100 dark:from-gray-800 dark:to-gray-900 rounded-lg p-4 border border-gray-200 dark:border-gray-700"><h3 class="text-lg font-semibold text-gray-900 dark:text-white mb-4">Import Options</h3> <div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-4"><div><label for="controlSetName" class="block mb-2 text-sm font-medium text-gray-900 dark:text-white">Control Set Name <span class="text-red-500">*</span></label> <input type="text" id="controlSetName" placeholder="e.g., NIST 800-53 Rev 4" class="bg-white border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-600 dark:border-gray-500 dark:text-white" required/> <p class="mt-1 text-xs text-gray-500 dark:text-gray-400">This will be used as the display name and folder name</p></div> <div><label for="controlSetDescription" class="block mb-2 text-sm font-medium text-gray-900 dark:text-white">Description</label> <input type="text" id="controlSetDescription" placeholder="Optional description" class="bg-white border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-600 dark:border-gray-500 dark:text-white"/> <p class="mt-1 text-xs text-gray-500 dark:text-gray-400">Brief description of this control set</p></div></div> <div class="grid grid-cols-1 md:grid-cols-2 gap-4"><div><label for="sheet" class="block mb-2 text-sm font-medium text-gray-900 dark:text-white">Sheet</label> <select id="sheet" class="bg-white border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-600 dark:border-gray-500 dark:text-white"></select> <p class="mt-1 text-xs text-gray-500 dark:text-gray-400">Select which worksheet contains your control data</p></div> <div><label for="headerRow" class="block mb-2 text-sm font-medium text-gray-900 dark:text-white">Select Header Row</label> <select id="headerRow" class="bg-white border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-600 dark:border-gray-500 dark:text-white"></select> <p class="mt-1 text-xs text-gray-500 dark:text-gray-400">Select the row containing column headers</p></div> <div><label for="controlIdField" class="block mb-2 text-sm font-medium text-gray-900 dark:text-white">Control ID Field <span class="text-red-500">*</span></label> <select id="controlIdField" required><option disabled>Select Control ID field</option><!></select> <p class="mt-1 text-xs text-gray-500 dark:text-gray-400">Column containing unique control identifiers (e.g., AC-1, SC-7)</p></div></div></div> <div class="bg-gradient-to-br from-gray-50 to-gray-100 dark:from-gray-800 dark:to-gray-900 rounded-lg p-4 border border-gray-200 dark:border-gray-700"><h3 class="text-lg font-semibold text-gray-900 dark:text-white mb-2">Organize Fields</h3> <p class="text-sm text-gray-600 dark:text-gray-400 mb-4">Drag fields to organize them. <strong>Overview fields</strong> will appear as table columns in
1
+ import"../chunks/DsnmJJEf.js";import{i as We}from"../chunks/BZU_Nz1O.js";import{p as Xe,am as Ve,d as a,T as k,G as pe,h as e,an as $r,ao as Ne,c as o,n as ke,r as t,b as d,e as Ke,J as P,K as I,ap as Nr,f as x,s as i,aq as c,a as we,ar as xr,aj as Ae,a3 as ze,ak as hr,al as tr,as as yr,k as de,o as ot,W as lt}from"../chunks/BnySH2DD.js";import{l as ar,p as Ye,i as M,a as st,s as it}from"../chunks/BDFhLgJd.js";import{a as Lr,s as le,r as jr,e as ge,b as Je,c as Vr,d as _r,i as Cr,f as Sr,w as wr}from"../chunks/CfxzrOg_.js";import{g as nt}from"../chunks/MY0vM1lA.js";function dt(ue){return function(...U){var F=U[0];return F.stopPropagation(),ue?.apply(this,U)}}var vt=Ne("<title> </title>"),ct=Ne('<svg><!><path d="M11 18L12.41 19.41 15 16.83 15 29 17 29 17 16.83 19.59 19.41 21 18 16 13 11 18z"></path><path d="M23.5,22H23V20h.5a4.5,4.5,0,0,0,.36-9L23,11l-.1-.82a7,7,0,0,0-13.88,0L9,11,8.14,11a4.5,4.5,0,0,0,.36,9H9v2H8.5A6.5,6.5,0,0,1,7.2,9.14a9,9,0,0,1,17.6,0A6.5,6.5,0,0,1,23.5,22Z"></path></svg>');function gt(ue,U){const F=ar(U,["children","$$slots","$$events","$$legacy"]),J=ar(F,["size","title"]);Xe(U,!1);const E=k(),j=k();let Z=Ye(U,"size",8,16),b=Ye(U,"title",8,void 0);Ve(()=>(pe(F),pe(b())),()=>{a(E,F["aria-label"]||F["aria-labelledby"]||b())}),Ve(()=>(e(E),pe(F)),()=>{a(j,{"aria-hidden":e(E)?void 0:!0,role:e(E)?"img":void 0,focusable:Number(F.tabindex)===0?!0:void 0})}),$r(),We();var $=ct();Lr($,()=>({xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 32 32",fill:"currentColor",preserveAspectRatio:"xMidYMid meet",width:Z(),height:Z(),...e(j),...J}));var K=o($);{var G=H=>{var g=vt(),N=o(g,!0);t(g),P(()=>I(N,b())),d(H,g)};M(K,H=>{b()&&H(G)})}ke(2),t($),d(ue,$),Ke()}var pt=Ne("<title> </title>"),ut=Ne('<svg><!><path d="M10 6H14V10H10zM18 6H22V10H18zM10 14H14V18H10zM18 14H22V18H18zM10 22H14V26H10zM18 22H22V26H18z"></path></svg>');function kr(ue,U){const F=ar(U,["children","$$slots","$$events","$$legacy"]),J=ar(F,["size","title"]);Xe(U,!1);const E=k(),j=k();let Z=Ye(U,"size",8,16),b=Ye(U,"title",8,void 0);Ve(()=>(pe(F),pe(b())),()=>{a(E,F["aria-label"]||F["aria-labelledby"]||b())}),Ve(()=>(e(E),pe(F)),()=>{a(j,{"aria-hidden":e(E)?void 0:!0,role:e(E)?"img":void 0,focusable:Number(F.tabindex)===0?!0:void 0})}),$r(),We();var $=ut();Lr($,()=>({xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 32 32",fill:"currentColor",preserveAspectRatio:"xMidYMid meet",width:Z(),height:Z(),...e(j),...J}));var K=o($);{var G=H=>{var g=pt(),N=o(g,!0);t(g),P(()=>I(N,b())),d(H,g)};M(K,H=>{b()&&H(G)})}ke(),t($),d(ue,$),Ke()}var bt=x('<div class="p-4 text-sm text-blue-800 rounded-lg bg-blue-50 dark:bg-gray-800 dark:text-blue-400"><div class="flex items-center"><svg class="flex-shrink-0 inline w-4 h-4 mr-3" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 20 20"><path d="M10 .5a9.5 9.5 0 1 0 9.5 9.5A9.51 9.51 0 0 0 10 .5ZM9.5 4a1.5 1.5 0 1 1 0 3 1.5 1.5 0 0 1 0-3ZM12 15H8a1 1 0 0 1 0-2h1v-3H8a1 1 0 0 1 0-2h2a1 1 0 0 1 1 1v4h1a1 1 0 0 1 0 2Z"></path></svg> <div><span class="font-medium">File loaded:</span> <div class="mt-1"><span class="font-medium">Sheets:</span> <span class="font-medium">Fields:</span> <span class="font-medium">Controls found:</span> </div></div></div></div>'),ft=x('<div class="p-4 text-sm text-red-800 rounded-lg bg-red-50 dark:bg-gray-800 dark:text-red-400"><div class="flex items-center"><svg class="flex-shrink-0 inline w-4 h-4 mr-3" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 20 20"><path d="M10 .5a9.5 9.5 0 1 0 9.5 9.5A9.51 9.51 0 0 0 10 .5ZM9.5 4a1.5 1.5 0 1 1 0 3 1.5 1.5 0 0 1 0-3ZM12 15H8a1 1 0 0 1 0-2h1v-3H8a1 1 0 0 1 0-2h2a1 1 0 0 1 1 1v4h1a1 1 0 0 1 0 2Z"></path></svg> <span> </span></div></div>'),mt=x('<div class="p-4 text-sm text-green-800 rounded-lg bg-green-50 dark:bg-gray-800 dark:text-green-400"><div class="flex items-center"><svg class="flex-shrink-0 inline w-4 h-4 mr-3" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 20 20"><path d="M10 .5a9.5 9.5 0 1 0 9.5 9.5A9.51 9.51 0 0 0 10 .5ZM9.5 4a1.5 1.5 0 1 1 0 3 1.5 1.5 0 0 1 0-3ZM12 15H8a1 1 0 0 1 0-2h1v-3H8a1 1 0 0 1 0-2h2a1 1 0 0 1 1 1v4h1a1 1 0 0 1 0 2Z"></path></svg> <span> </span></div></div>'),xt=x("<option> </option>"),ht=x("<option> </option>"),yt=x("<option> </option>"),_t=x('<span class="ml-auto text-xs text-blue-600 dark:text-blue-400">ID</span>'),wt=x('<div draggable="true" role="button" tabindex="0" class="flex items-center px-3 py-2 bg-gray-100 dark:bg-gray-700 text-gray-500 dark:text-gray-400 rounded text-sm cursor-move hover:bg-gray-200 dark:hover:bg-gray-600 transition-colors opacity-75"><svg class="w-3 h-3 mr-2 flex-shrink-0" fill="currentColor" viewBox="0 0 20 20"><path d="M10 6a2 2 0 110-4 2 2 0 010 4zM10 12a2 2 0 110-4 2 2 0 010 4zM10 18a2 2 0 110-4 2 2 0 010 4z"></path></svg> <span class="truncate line-through"> </span> <!></div>'),kt=x('<p class="text-xs text-gray-400 dark:text-gray-500 text-center py-4">No excluded fields</p>'),Ct=x('<div draggable="true" role="button" tabindex="0"><!> <span class="truncate"> </span></div>'),St=x('<p class="text-xs text-gray-400 dark:text-gray-500 text-center py-4">Drop fields here</p>'),$t=x('<div draggable="true" role="button" tabindex="0"><!> <span class="truncate"> </span></div>'),Dt=x('<p class="text-xs text-gray-400 dark:text-gray-500 text-center py-4">Drop fields here</p>'),Mt=x('<div draggable="true" role="button" tabindex="0"><!> <span class="truncate"> </span></div>'),zt=x('<p class="text-xs text-gray-400 dark:text-gray-500 text-center py-4">Drop fields here</p>'),At=x('<div draggable="false" role="button" tabindex="0" class="flex items-center px-3 py-2 bg-orange-100 dark:bg-orange-900/30 text-orange-800 dark:text-orange-300 rounded text-sm hover:bg-orange-200 dark:hover:bg-orange-800/30 transition-colors"><span class="truncate"> </span> <button class="ml-auto text-gray-400 hover:text-red-500 dark:text-gray-500 dark:hover:text-red-400" title="Remove from mappings">×</button></div>'),Ft=x('<div role="region" aria-label="Justification field drop zone"><p class="text-xs text-gray-400 dark:text-gray-500 text-center py-4">Drop fields here</p></div>'),Ot=x('<th class="px-4 py-2"> </th>'),Pt=x('<td class="px-4 py-2"> </td>'),Ht=x('<tr class="bg-white border-b dark:bg-gray-800 dark:border-gray-700"></tr>'),Et=x('<div class="bg-gradient-to-br from-gray-50 to-gray-100 dark:from-gray-800 dark:to-gray-900 rounded-lg p-4 border border-gray-200 dark:border-gray-700"><h3 class="text-lg font-semibold text-gray-900 dark:text-white mb-4">Sample Data Preview</h3> <div class="overflow-x-auto"><table class="w-full text-sm text-left text-gray-500 dark:text-gray-400"><thead class="text-xs text-gray-700 uppercase bg-gray-100 dark:bg-gray-600 dark:text-gray-400"><tr></tr></thead><tbody></tbody></table></div></div>'),It=x('<span class="flex items-center"><svg class="animate-spin -ml-1 mr-3 h-5 w-5 text-white" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"><circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle><path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path></svg> Importing...</span>'),Tt=x(`<div class="bg-gradient-to-br from-gray-50 to-gray-100 dark:from-gray-800 dark:to-gray-900 rounded-lg p-4 border border-gray-200 dark:border-gray-700"><h3 class="text-lg font-semibold text-gray-900 dark:text-white mb-4">Import Options</h3> <div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-4"><div><label for="controlSetName" class="block mb-2 text-sm font-medium text-gray-900 dark:text-white">Control Set Name <span class="text-red-500">*</span></label> <input type="text" id="controlSetName" placeholder="e.g., NIST 800-53 Rev 4" class="bg-white border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-600 dark:border-gray-500 dark:text-white" required/> <p class="mt-1 text-xs text-gray-500 dark:text-gray-400">This will be used as the display name and folder name</p></div> <div><label for="controlSetDescription" class="block mb-2 text-sm font-medium text-gray-900 dark:text-white">Description</label> <input type="text" id="controlSetDescription" placeholder="Optional description" class="bg-white border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-600 dark:border-gray-500 dark:text-white"/> <p class="mt-1 text-xs text-gray-500 dark:text-gray-400">Brief description of this control set</p></div></div> <div class="grid grid-cols-1 md:grid-cols-2 gap-4"><div><label for="sheet" class="block mb-2 text-sm font-medium text-gray-900 dark:text-white">Sheet</label> <select id="sheet" class="bg-white border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-600 dark:border-gray-500 dark:text-white"></select> <p class="mt-1 text-xs text-gray-500 dark:text-gray-400">Select which worksheet contains your control data</p></div> <div><label for="headerRow" class="block mb-2 text-sm font-medium text-gray-900 dark:text-white">Select Header Row</label> <select id="headerRow" class="bg-white border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-600 dark:border-gray-500 dark:text-white"></select> <p class="mt-1 text-xs text-gray-500 dark:text-gray-400">Select the row containing column headers</p></div> <div><label for="controlIdField" class="block mb-2 text-sm font-medium text-gray-900 dark:text-white">Control ID Field <span class="text-red-500">*</span></label> <select id="controlIdField" required><option disabled>Select Control ID field</option><!></select> <p class="mt-1 text-xs text-gray-500 dark:text-gray-400">Column containing unique control identifiers (e.g., AC-1, SC-7)</p></div></div></div> <div class="bg-gradient-to-br from-gray-50 to-gray-100 dark:from-gray-800 dark:to-gray-900 rounded-lg p-4 border border-gray-200 dark:border-gray-700"><h3 class="text-lg font-semibold text-gray-900 dark:text-white mb-2">Organize Fields</h3> <p class="text-sm text-gray-600 dark:text-gray-400 mb-4">Drag fields to organize them. <strong>Overview fields</strong> will appear as table columns in
2
2
  the controls list.</p> <div class="grid grid-cols-1 lg:grid-cols-5 gap-4"><div class="border border-gray-300 dark:border-gray-600 rounded-lg bg-white dark:bg-gray-800"><div class="p-3 border-b border-gray-200 dark:border-gray-700 bg-gray-50 dark:bg-gray-700 rounded-t-lg"><h4 class="text-sm font-semibold text-gray-700 dark:text-gray-300">Excluded Fields</h4> <p class="text-xs text-gray-500 dark:text-gray-400 mt-1">Not imported</p></div> <div role="region" aria-label="Excluded fields drop zone"><!> <!></div></div> <div class="border border-blue-300 dark:border-blue-700 rounded-lg bg-white dark:bg-gray-800"><div class="p-3 border-b border-blue-200 dark:border-blue-800 bg-blue-50 dark:bg-blue-900/20 rounded-t-lg"><h4 class="text-sm font-semibold text-blue-700 dark:text-blue-300">Overview Tab</h4> <p class="text-xs text-blue-600 dark:text-blue-400 mt-1">Shows in details & table columns</p></div> <div role="region" aria-label="Overview tab drop zone"><!> <!></div></div> <div class="border border-green-300 dark:border-green-700 rounded-lg bg-white dark:bg-gray-800"><div class="p-3 border-b border-green-200 dark:border-green-800 bg-green-50 dark:bg-green-900/20 rounded-t-lg"><h4 class="text-sm font-semibold text-green-700 dark:text-green-300">Implementation Tab</h4> <p class="text-xs text-green-600 dark:text-green-400 mt-1">Status & compliance</p></div> <div role="region" aria-label="Implementation tab drop zone"><!> <!></div></div> <div class="border border-purple-300 dark:border-purple-700 rounded-lg bg-white dark:bg-gray-800"><div class="p-3 border-b border-purple-200 dark:border-purple-800 bg-purple-50 dark:bg-purple-900/20 rounded-t-lg"><h4 class="text-sm font-semibold text-purple-700 dark:text-purple-300">Custom Tab</h4> <p class="text-xs text-purple-600 dark:text-purple-400 mt-1">Additional fields</p></div> <div role="region" aria-label="Custom fields drop zone"><!> <!></div></div> <div class="border border-orange-300 dark:border-orange-700 rounded-lg bg-white dark:bg-gray-800"><div class="p-3 border-b border-orange-200 dark:border-orange-800 bg-orange-50 dark:bg-orange-900/20 rounded-t-lg"><h4 class="text-sm font-semibold text-orange-700 dark:text-orange-300">Mappings Tab</h4> <p class="text-xs text-orange-600 dark:text-orange-400 mt-1">Pre-populate justification for a control mapping</p></div> <div role="region" aria-label="Justifications tab drop zone"><div class="space-y-2"><!></div></div></div></div></div> <!> <div class="flex justify-center"><button class="px-5 py-2.5 text-white bg-blue-600 hover:bg-blue-700 focus:ring-4 focus:ring-blue-300 font-medium rounded-lg text-sm disabled:opacity-50 disabled:cursor-not-allowed"><!></button></div>`,1),jt=x('<div class="space-y-6"><div role="button" tabindex="0" class="relative"><label><div class="flex flex-col items-center justify-center pt-5 pb-6"><!> <p class="mb-2 text-sm text-gray-500 dark:text-gray-400"><span class="font-semibold">Click to upload</span> or drag and drop</p> <p class="text-xs text-gray-500 dark:text-gray-400">XLSX, XLS or CSV files</p></div> <input type="file" class="hidden" accept=".xlsx,.xls,.csv"/></label></div> <!> <!> <!> <!></div>');function Vt(ue,U){Xe(U,!1);const F=Nr();let J=k(null),E=k(""),j=k(""),Z=k([]),b=k([]),$=k([]),K=k(0),G=k([]),H=k([]),g=k(new Map),N=k(1),L=k(""),xe=k(""),Y=k(""),Q=k(!1),ee=k(""),be=k(""),Ce=k(!1),te=k(!1),C=k(null),B=k(null),re=k(null);function Se(){a(b,[]),a($,[]),a(K,0),e(g).clear(),a(g,new Map),a(H,[]),a(L,""),a(ee,""),a(be,""),a(C,null),a(B,null),a(re,null)}function p(l){l.preventDefault(),a(te,!0)}function u(){a(te,!1)}function D(l){l.preventDefault(),a(te,!1);const n=l.dataTransfer?.files;n&&n.length>0&&T(n[0])}function V(l){const n=l.target;n.files&&n.files.length>0&&T(n.files[0])}async function T(l){Se(),a(E,l.name),a(J,l),a(ee,""),a(Q,!0),a(xe,e(E).replace(/\.[^.]+$/,"").replace(/[-_]/g," ")),a(Y,`Imported from ${e(E)}`);try{const n=new FormData;n.append("file",l);const y=await fetch("/api/parse-excel",{method:"POST",body:n});if(!y.ok){const z=await y.json();throw new Error(z.error||"Failed to parse file")}const h=await y.json();a(Z,h.sheets||[]),a(j,h.selectedSheet||e(Z)[0]),a(G,h.rowPreviews||[]),e(G).length>0&&e(N)===1&&a(N,e(G)[0].row),await q(),a(Ce,!0)}catch(n){a(ee,"Error reading file: "+n.message)}finally{a(Q,!1)}}async function q(){if(!(!e(J)||!e(j))){a(Q,!0),e(g).clear(),a(g,new Map),a(L,""),a(H,[]),a(C,null),a(B,null),a(re,null);try{const l=new FormData;l.append("file",e(J)),l.append("sheetName",e(j));const n=await fetch("/api/parse-excel-sheet-previews",{method:"POST",body:l});if(n.ok){const w=await n.json();a(G,w.rowPreviews||[]),e(G).length>0&&!e(G).some(A=>A.row===e(N))&&a(N,e(G)[0].row)}else{const w=await n.json();throw new Error(w.error||"Failed to load sheet previews")}const y=new FormData;y.append("file",e(J)),y.append("sheetName",e(j)),y.append("headerRow",e(N).toString());const h=await fetch("/api/parse-excel-sheet",{method:"POST",body:y});if(!h.ok){const w=await h.json();throw new Error(w.error||"Failed to parse sheet")}const z=await h.json();if(a(b,z.fields||[]),a($,z.sampleData||[]),a(K,z.controlCount||0),e(b).forEach((w,A)=>{const _=w.toLowerCase();let ce="custom",fe="text";_.includes("implementation")||_.includes("status")||_.includes("narrative")||_.includes("guidance")?ce="implementation":(_.includes("id")||_.includes("title")||_.includes("family")||_.includes("cci")||_.includes("control")||_.includes("acronym"))&&(ce="overview"),_.includes("description")||_.includes("narrative")||_.includes("guidance")||_.includes("statement")?fe="textarea":_.includes("status")||_.includes("type")||_.includes("designation")?fe="select":_.includes("date")?fe="date":(_.includes("count")||_.includes("number"))&&(fe="number"),e(g).set(w,{originalName:w,tab:ce,displayOrder:A,fieldType:fe,required:_.includes("id")||_.includes("title")})}),a(g,e(g)),e(L)&&!e(b).includes(e(L))&&a(L,""),!e(L)&&e(b).includes("AP Acronym")){const w=!e($).length||e($).every(ne=>!ne["AP Acronym"]||String(ne["AP Acronym"]).length<25),A=e($).map(ne=>ne["AP Acronym"]).filter(ne=>ne!=null&&ne!==""&&String(ne).trim()!==""),_=new Set(A),ce=!A.length||_.size===A.length,fe=A.length>0;w&&ce&&fe&&a(L,"AP Acronym")}}catch(l){a(ee,"Error loading sheet data: "+l.message)}finally{a(Q,!1)}}}function ve(l){if(!l)return l;let n=l.trim().replace(/\r?\n/g," ").replace(/\s+/g," ").trim();return Le(n)}function Le(l){return l.replace(/\W+/g," ").split(/ |\s/).map(n=>n.toLowerCase()).join("-")}function he(l,n){a(C,n),l.dataTransfer&&(l.dataTransfer.effectAllowed="move",l.dataTransfer.setData("text/plain",n))}function ae(){a(C,null),a(B,null),a(re,null)}function S(l,n){l.preventDefault(),a(B,n),l.dataTransfer&&(l.dataTransfer.dropEffect="move")}function se(){a(B,null)}function ie(l,n,y){if(l.preventDefault(),e(C)&&e(g).has(e(C))){const h=e(g).get(e(C));if(n==="mappings")e(H).includes(e(C))||a(H,[...e(H),e(C)]);else{if(h.tab=n,y!==void 0&&n!==null){const w=Array.from(e(g).entries()).filter(([A,_])=>_.tab===n).sort((A,_)=>A[1].displayOrder-_[1].displayOrder).filter(([A])=>A!==e(C));w.splice(y,0,[e(C),h]),w.forEach(([A,_],ce)=>{_.displayOrder=ce,e(g).set(A,_)})}else if(n!==null){const z=Math.max(0,...Array.from(e(g).values()).filter(w=>w.tab===n).map(w=>w.displayOrder));h.displayOrder=z+1}e(g).set(e(C),h),a(g,e(g))}}a(C,null),a(B,null)}function Fe(l,n){l.preventDefault(),l.stopPropagation(),a(re,n)}function $e(){a(re,null)}function De(l,n,y){if(l.preventDefault(),l.stopPropagation(),e(C)&&e(C)!==n){const z=Array.from(e(g).entries()).filter(([w,A])=>A.tab===y).sort((w,A)=>w[1].displayOrder-A[1].displayOrder).findIndex(([w])=>w===n);z!==-1&&ie(l,y,z)}a(re,null)}async function Be(){if(!(!e(J)||!e(E))){if(!e(L)){a(ee,"Please select a Control ID field before importing"),a(be,"");return}if(!e(xe)||e(xe).trim()===""){a(ee,"Please enter a Control Set Name before importing"),a(be,"");return}a(Q,!0),a(ee,""),a(be,"");try{const l=new FormData;l.append("file",e(J),e(E)),l.append("controlIdField",e(L)),l.append("startRow",e(N).toString()),l.append("sheetName",e(j)),l.append("namingConvention","kebab-case"),l.append("skipEmpty","true"),l.append("skipEmptyRows","true"),l.append("controlSetName",e(xe)||e(E).replace(/\.[^.]+$/,"")),l.append("controlSetDescription",e(Y)||`Imported from ${e(E)}`);const n=Array.from(e(g).entries()).filter(([h,z])=>z.tab!==null).map(([h,z])=>({fieldName:ve(h),...z}));l.append("fieldSchema",JSON.stringify(n)),l.append("justificationFields",JSON.stringify(e(H).map(h=>ve(h))));let y;try{if(y=await fetch("/api/import-spreadsheet",{method:"POST",body:l}),!y.ok){const z=await y.json();throw new Error(z.error||"Import failed")}const h=await y.json();a(be,`Successfully imported ${h.controlCount} controls into ${h.families.length} families`),F("created",{path:h.outputDir})}catch(h){console.error("Error importing spreadsheet:",h)}}catch(l){a(ee,"Error importing spreadsheet: "+l.message)}finally{a(Q,!1)}}}We();var Re=jt(),ye=o(Re),Ze=o(ye),Oe=o(Ze),or=o(Oe);gt(or,{class:"w-8 h-8 mb-4 text-gray-500 dark:text-gray-400"}),ke(4),t(Oe);var Ge=i(Oe,2);t(Ze),t(ye);var Pe=i(ye,2);{var lr=l=>{var n=bt(),y=o(n),h=i(o(y),2),z=i(o(h)),w=i(z),A=i(o(w)),_=i(A,2),ce=i(_,2);t(w),t(h),t(y),t(n),P(()=>{I(z,` ${e(E)??""} `),I(A,` ${e(Z).length??""} | `),I(_,` ${e(b).length??""} | `),I(ce,` ${e(K)??""}`)}),d(l,n)};M(Pe,l=>{e(E)&&l(lr)})}var Qe=i(Pe,2);{var sr=l=>{var n=ft(),y=o(n),h=i(o(y),2),z=o(h,!0);t(h),t(y),t(n),P(()=>I(z,e(ee))),d(l,n)};M(Qe,l=>{e(ee)&&l(sr)})}var qe=i(Qe,2);{var ir=l=>{var n=mt(),y=o(n),h=i(o(y),2),z=o(h,!0);t(h),t(y),t(n),P(()=>I(z,e(be))),d(l,n)};M(qe,l=>{e(be)&&l(ir)})}var nr=i(qe,2);{var dr=l=>{var n=Tt(),y=we(n),h=i(o(y),2),z=o(h),w=i(o(z),2);jr(w),ke(2),t(z);var A=i(z,2),_=i(o(A),2);jr(_),ke(2),t(A),t(h);var ce=i(h,2),fe=o(ce),ne=i(o(fe),2);P(()=>{e(j),xr(()=>{e(Z)})}),ge(ne,5,()=>e(Z),r=>r,(r,s)=>{var f=xt(),m=o(f,!0);t(f);var v={};P(()=>{I(m,e(s)),v!==(v=e(s))&&(f.value=(f.__value=e(s))??"")}),d(r,f)}),t(ne),ke(2),t(fe);var vr=i(fe,2),er=i(o(vr),2);P(()=>{e(N),xr(()=>{e(G)})}),ge(er,5,()=>e(G),r=>r.row,(r,s)=>{var f=ht(),m=o(f);t(f);var v={};P(()=>{I(m,`Row ${e(s).row??""}: ${e(s).preview??""}`),v!==(v=e(s).row)&&(f.value=(f.__value=e(s).row)??"")}),d(r,f)}),t(er),ke(2),t(vr);var Dr=i(vr,2),rr=i(o(Dr),2);P(()=>{e(L),xr(()=>{e(b),e($)})});var cr=o(rr);cr.value=cr.__value="";var Br=i(cr);ge(Br,1,()=>e(b),r=>r,(r,s)=>{const f=ze(()=>e($).length>0&&e($)[0][e(s)]?String(e($)[0][e(s)]).slice(0,30):""),m=ze(()=>!e($).length||e($).every(oe=>!oe[e(s)]||String(oe[e(s)]).length<25)),v=ze(()=>e($).map(oe=>oe[e(s)]).filter(oe=>oe!=null&&oe!==""&&String(oe).trim()!=="")),W=ze(()=>new Set(e(v))),X=ze(()=>!e(v).length||e(W).size===e(v).length),R=ze(()=>e(v).length>0);var O=Ae(),me=we(O);{var Me=oe=>{var _e=yt(),mr=o(_e);t(_e);var Tr={};P(()=>{I(mr,`${e(s)??""}${e(f)?` (e.g., ${e(f)})`:""}`),Tr!==(Tr=e(s))&&(_e.value=(_e.__value=e(s))??"")}),d(oe,_e)};M(me,oe=>{e(m)&&e(X)&&e(R)&&oe(Me)})}d(r,O)}),t(rr),ke(2),t(Dr),t(ce),t(y);var gr=i(y,2),Mr=i(o(gr),4),pr=o(Mr),He=i(o(pr),2),zr=o(He);ge(zr,1,()=>e(b).filter(r=>!e(g).get(r)||e(g).get(r)?.tab===null),r=>r,(r,s)=>{var f=wt(),m=i(o(f),2),v=o(m,!0);t(m);var W=i(m,2);{var X=R=>{var O=_t();d(R,O)};M(W,R=>{e(s)===e(L)&&R(X)})}t(f),P(()=>{Je(f,"aria-label",`Drag ${e(s)??""} field`),I(v,e(s))}),c("dragstart",f,R=>he(R,e(s))),c("dragend",f,ae),d(r,f)});var Rr=i(zr,2);{var Zr=r=>{var s=kt();d(r,s)};M(Rr,r=>{e(b).filter(s=>!e(g).get(s)||e(g).get(s)?.tab===null).length===0&&r(Zr)})}t(He),t(pr);var ur=i(pr,2),Ee=i(o(ur),2),Ar=o(Ee);ge(Ar,3,()=>Array.from(e(g).entries()).filter(([r,s])=>s.tab==="overview").sort((r,s)=>r[1].displayOrder-s[1].displayOrder),([r,s])=>r,(r,s)=>{var f=hr(()=>yr(e(s),2));let m=()=>e(f)[0];var v=Ct(),W=o(v);kr(W,{class:"w-3 h-3 mr-2 flex-shrink-0"});var X=i(W,2),R=o(X,!0);t(X),t(v),P(()=>{Je(v,"aria-label",`${m()??""} field in Overview tab`),le(v,1,`flex items-center px-3 py-2 bg-blue-100 dark:bg-blue-900/30 text-blue-800 dark:text-blue-300 rounded text-sm cursor-move hover:bg-blue-200 dark:hover:bg-blue-800/30 transition-colors
3
3
  ${e(re)===m()&&e(C)!==m()?"border-t-2 border-blue-500":""}`),I(R,m())}),c("dragstart",v,O=>he(O,m())),c("dragend",v,ae),c("dragover",v,O=>Fe(O,m())),c("dragleave",v,$e),c("drop",v,O=>De(O,m(),"overview")),d(r,v)});var qr=i(Ar,2);{var Ur=r=>{var s=St();d(r,s)};M(qr,r=>{Array.from(e(g).entries()).filter(([s,f])=>f.tab==="overview").length===0&&r(Ur)})}t(Ee),t(ur);var br=i(ur,2),Ie=i(o(br),2),Fr=o(Ie);ge(Fr,3,()=>Array.from(e(g).entries()).filter(([r,s])=>s.tab==="implementation").sort((r,s)=>r[1].displayOrder-s[1].displayOrder),([r,s])=>r,(r,s)=>{var f=hr(()=>yr(e(s),2));let m=()=>e(f)[0];var v=$t(),W=o(v);kr(W,{class:"w-3 h-3 mr-2 flex-shrink-0"});var X=i(W,2),R=o(X,!0);t(X),t(v),P(()=>{Je(v,"aria-label",`${m()??""} field in Implementation tab`),le(v,1,`flex items-center px-3 py-2 bg-green-100 dark:bg-green-900/30 text-green-800 dark:text-green-300 rounded text-sm cursor-move hover:bg-green-200 dark:hover:bg-green-800/30 transition-colors
4
4
  ${e(re)===m()&&e(C)!==m()?"border-t-2 border-green-500":""}`),I(R,m())}),c("dragstart",v,O=>he(O,m())),c("dragend",v,ae),c("dragover",v,O=>Fe(O,m())),c("dragleave",v,$e),c("drop",v,O=>De(O,m(),"implementation")),d(r,v)});var Jr=i(Fr,2);{var Yr=r=>{var s=Dt();d(r,s)};M(Jr,r=>{Array.from(e(g).entries()).filter(([s,f])=>f.tab==="implementation").length===0&&r(Yr)})}t(Ie),t(br);var fr=i(br,2),Te=i(o(fr),2),Or=o(Te);ge(Or,3,()=>Array.from(e(g).entries()).filter(([r,s])=>s.tab==="custom").sort((r,s)=>r[1].displayOrder-s[1].displayOrder),([r,s])=>r,(r,s)=>{var f=hr(()=>yr(e(s),2));let m=()=>e(f)[0];var v=Mt(),W=o(v);kr(W,{class:"w-3 h-3 mr-2 flex-shrink-0"});var X=i(W,2),R=o(X,!0);t(X),t(v),P(()=>{Je(v,"aria-label",`${m()??""} field in Custom tab`),le(v,1,`flex items-center px-3 py-2 bg-purple-100 dark:bg-purple-900/30 text-purple-800 dark:text-purple-300 rounded text-sm cursor-move hover:bg-purple-200 dark:hover:bg-purple-800/30 transition-colors
@@ -1 +1 @@
1
- {"version":"1760478281579"}
1
+ {"version":"1760625230679"}
@@ -1721,8 +1721,8 @@ var init_fileStore = __esm({
1721
1721
  if (!this.baseDir || this.baseDir === "." || this.baseDir === process.cwd()) {
1722
1722
  return;
1723
1723
  }
1724
- const lulaConfigPath = join2(this.baseDir, "lula.yaml");
1725
- if (!existsSync2(lulaConfigPath)) {
1724
+ const lulaConfigPath2 = join2(this.baseDir, "lula.yaml");
1725
+ if (!existsSync2(lulaConfigPath2)) {
1726
1726
  return;
1727
1727
  }
1728
1728
  if (!existsSync2(this.controlsDir)) {
@@ -1880,6 +1880,17 @@ var init_fileStore = __esm({
1880
1880
  if (!existsSync2(this.controlsDir)) {
1881
1881
  return [];
1882
1882
  }
1883
+ let controlOrder = null;
1884
+ try {
1885
+ const lulaConfigPath2 = join2(this.baseDir, "lula.yaml");
1886
+ if (existsSync2(lulaConfigPath2)) {
1887
+ const content = readFileSync2(lulaConfigPath2, "utf8");
1888
+ const metadata = yaml2.load(content);
1889
+ controlOrder = metadata?.controlOrder || null;
1890
+ }
1891
+ } catch (error) {
1892
+ console.error(`Failed to load lula.yaml for controlOrder (path: ${lulaConfigPath}):`, error);
1893
+ }
1883
1894
  const entries = readdirSync(this.controlsDir);
1884
1895
  const yamlFiles = entries.filter((file) => file.endsWith(".yaml"));
1885
1896
  if (yamlFiles.length > 0) {
@@ -1898,7 +1909,11 @@ var init_fileStore = __esm({
1898
1909
  }
1899
1910
  });
1900
1911
  const results2 = await Promise.all(promises);
1901
- return results2.filter((c) => c !== null);
1912
+ const controls2 = results2.filter((c) => c !== null);
1913
+ if (controlOrder && controlOrder.length > 0) {
1914
+ return this.sortControlsByOrder(controls2, controlOrder);
1915
+ }
1916
+ return controls2;
1902
1917
  }
1903
1918
  const families = entries.filter((name) => {
1904
1919
  const familyPath = join2(this.controlsDir, name);
@@ -1921,7 +1936,25 @@ var init_fileStore = __esm({
1921
1936
  allPromises.push(...familyPromises);
1922
1937
  }
1923
1938
  const results = await Promise.all(allPromises);
1924
- return results.filter((c) => c !== null);
1939
+ const controls = results.filter((c) => c !== null);
1940
+ if (controlOrder && controlOrder.length > 0) {
1941
+ return this.sortControlsByOrder(controls, controlOrder);
1942
+ }
1943
+ return controls;
1944
+ }
1945
+ /**
1946
+ * Sort controls based on the provided order array
1947
+ */
1948
+ sortControlsByOrder(controls, controlOrder) {
1949
+ const orderMap = /* @__PURE__ */ new Map();
1950
+ controlOrder.forEach((controlId, index) => {
1951
+ orderMap.set(controlId, index);
1952
+ });
1953
+ return controls.sort((a, b) => {
1954
+ const aIndex = orderMap.get(a.id) ?? Number.MAX_SAFE_INTEGER;
1955
+ const bIndex = orderMap.get(b.id) ?? Number.MAX_SAFE_INTEGER;
1956
+ return aIndex - bIndex;
1957
+ });
1925
1958
  }
1926
1959
  /**
1927
1960
  * Load mappings from mappings directory
@@ -3041,6 +3074,7 @@ function processSpreadsheetData(rawData, headers, startRowIndex, params) {
3041
3074
  continue;
3042
3075
  }
3043
3076
  const family = extractFamilyFromControlId(controlId);
3077
+ control._originalRowIndex = i;
3044
3078
  control.family = family;
3045
3079
  controls.push(control);
3046
3080
  if (!families.has(family)) {
@@ -3163,6 +3197,7 @@ async function createOutputStructure(processedData, fieldSchema, params) {
3163
3197
  params.controlIdField,
3164
3198
  params.namingConvention
3165
3199
  );
3200
+ const controlOrder = controls.sort((a, b) => (a._originalRowIndex || 0) - (b._originalRowIndex || 0)).map((control) => control[controlIdFieldNameClean]);
3166
3201
  const controlSetData = {
3167
3202
  name: params.controlSetName,
3168
3203
  description: params.controlSetDescription,
@@ -3170,12 +3205,16 @@ async function createOutputStructure(processedData, fieldSchema, params) {
3170
3205
  control_id_field: controlIdFieldNameClean,
3171
3206
  controlCount: controls.length,
3172
3207
  families: uniqueFamilies,
3208
+ controlOrder,
3173
3209
  fieldSchema
3174
3210
  };
3175
3211
  writeFileSync2(join4(baseDir, "lula.yaml"), yaml4.dump(controlSetData));
3176
3212
  const controlsDir = join4(baseDir, "controls");
3177
3213
  const mappingsDir = join4(baseDir, "mappings");
3178
- families.forEach((familyControls, family) => {
3214
+ const sortedFamilies = Array.from(families.entries()).sort(
3215
+ (a, b) => a[0].localeCompare(b[0])
3216
+ );
3217
+ sortedFamilies.forEach(([family, familyControls]) => {
3179
3218
  const familyDir = join4(controlsDir, family);
3180
3219
  const familyMappingsDir = join4(mappingsDir, family);
3181
3220
  if (!existsSync3(familyDir)) {
@@ -3184,7 +3223,10 @@ async function createOutputStructure(processedData, fieldSchema, params) {
3184
3223
  if (!existsSync3(familyMappingsDir)) {
3185
3224
  mkdirSync2(familyMappingsDir, { recursive: true });
3186
3225
  }
3187
- familyControls.forEach((control) => {
3226
+ const sortedFamilyControls = familyControls.sort(
3227
+ (a, b) => (a._originalRowIndex || 0) - (b._originalRowIndex || 0)
3228
+ );
3229
+ sortedFamilyControls.forEach((control) => {
3188
3230
  const controlId = control[controlIdFieldNameClean];
3189
3231
  if (!controlId) {
3190
3232
  console.error("Missing control ID for control:", control);
@@ -3206,7 +3248,7 @@ async function createOutputStructure(processedData, fieldSchema, params) {
3206
3248
  filteredControl.family = control.family;
3207
3249
  }
3208
3250
  Object.keys(control).forEach((fieldName) => {
3209
- if (fieldName === "family") return;
3251
+ if (fieldName === "family" || fieldName === "_originalRowIndex") return;
3210
3252
  if (params.justificationFields.includes(fieldName) && control[fieldName] !== void 0 && control[fieldName] !== null) {
3211
3253
  justificationContents.push(control[fieldName]);
3212
3254
  }
@@ -1703,8 +1703,8 @@ var init_fileStore = __esm({
1703
1703
  if (!this.baseDir || this.baseDir === "." || this.baseDir === process.cwd()) {
1704
1704
  return;
1705
1705
  }
1706
- const lulaConfigPath = join2(this.baseDir, "lula.yaml");
1707
- if (!existsSync2(lulaConfigPath)) {
1706
+ const lulaConfigPath2 = join2(this.baseDir, "lula.yaml");
1707
+ if (!existsSync2(lulaConfigPath2)) {
1708
1708
  return;
1709
1709
  }
1710
1710
  if (!existsSync2(this.controlsDir)) {
@@ -1862,6 +1862,17 @@ var init_fileStore = __esm({
1862
1862
  if (!existsSync2(this.controlsDir)) {
1863
1863
  return [];
1864
1864
  }
1865
+ let controlOrder = null;
1866
+ try {
1867
+ const lulaConfigPath2 = join2(this.baseDir, "lula.yaml");
1868
+ if (existsSync2(lulaConfigPath2)) {
1869
+ const content = readFileSync2(lulaConfigPath2, "utf8");
1870
+ const metadata = yaml2.load(content);
1871
+ controlOrder = metadata?.controlOrder || null;
1872
+ }
1873
+ } catch (error) {
1874
+ console.error(`Failed to load lula.yaml for controlOrder (path: ${lulaConfigPath}):`, error);
1875
+ }
1865
1876
  const entries = readdirSync(this.controlsDir);
1866
1877
  const yamlFiles = entries.filter((file) => file.endsWith(".yaml"));
1867
1878
  if (yamlFiles.length > 0) {
@@ -1880,7 +1891,11 @@ var init_fileStore = __esm({
1880
1891
  }
1881
1892
  });
1882
1893
  const results2 = await Promise.all(promises);
1883
- return results2.filter((c) => c !== null);
1894
+ const controls2 = results2.filter((c) => c !== null);
1895
+ if (controlOrder && controlOrder.length > 0) {
1896
+ return this.sortControlsByOrder(controls2, controlOrder);
1897
+ }
1898
+ return controls2;
1884
1899
  }
1885
1900
  const families = entries.filter((name) => {
1886
1901
  const familyPath = join2(this.controlsDir, name);
@@ -1903,7 +1918,25 @@ var init_fileStore = __esm({
1903
1918
  allPromises.push(...familyPromises);
1904
1919
  }
1905
1920
  const results = await Promise.all(allPromises);
1906
- return results.filter((c) => c !== null);
1921
+ const controls = results.filter((c) => c !== null);
1922
+ if (controlOrder && controlOrder.length > 0) {
1923
+ return this.sortControlsByOrder(controls, controlOrder);
1924
+ }
1925
+ return controls;
1926
+ }
1927
+ /**
1928
+ * Sort controls based on the provided order array
1929
+ */
1930
+ sortControlsByOrder(controls, controlOrder) {
1931
+ const orderMap = /* @__PURE__ */ new Map();
1932
+ controlOrder.forEach((controlId, index) => {
1933
+ orderMap.set(controlId, index);
1934
+ });
1935
+ return controls.sort((a, b) => {
1936
+ const aIndex = orderMap.get(a.id) ?? Number.MAX_SAFE_INTEGER;
1937
+ const bIndex = orderMap.get(b.id) ?? Number.MAX_SAFE_INTEGER;
1938
+ return aIndex - bIndex;
1939
+ });
1907
1940
  }
1908
1941
  /**
1909
1942
  * Load mappings from mappings directory
@@ -3023,6 +3056,7 @@ function processSpreadsheetData(rawData, headers, startRowIndex, params) {
3023
3056
  continue;
3024
3057
  }
3025
3058
  const family = extractFamilyFromControlId(controlId);
3059
+ control._originalRowIndex = i;
3026
3060
  control.family = family;
3027
3061
  controls.push(control);
3028
3062
  if (!families.has(family)) {
@@ -3145,6 +3179,7 @@ async function createOutputStructure(processedData, fieldSchema, params) {
3145
3179
  params.controlIdField,
3146
3180
  params.namingConvention
3147
3181
  );
3182
+ const controlOrder = controls.sort((a, b) => (a._originalRowIndex || 0) - (b._originalRowIndex || 0)).map((control) => control[controlIdFieldNameClean]);
3148
3183
  const controlSetData = {
3149
3184
  name: params.controlSetName,
3150
3185
  description: params.controlSetDescription,
@@ -3152,12 +3187,16 @@ async function createOutputStructure(processedData, fieldSchema, params) {
3152
3187
  control_id_field: controlIdFieldNameClean,
3153
3188
  controlCount: controls.length,
3154
3189
  families: uniqueFamilies,
3190
+ controlOrder,
3155
3191
  fieldSchema
3156
3192
  };
3157
3193
  writeFileSync2(join4(baseDir, "lula.yaml"), yaml4.dump(controlSetData));
3158
3194
  const controlsDir = join4(baseDir, "controls");
3159
3195
  const mappingsDir = join4(baseDir, "mappings");
3160
- families.forEach((familyControls, family) => {
3196
+ const sortedFamilies = Array.from(families.entries()).sort(
3197
+ (a, b) => a[0].localeCompare(b[0])
3198
+ );
3199
+ sortedFamilies.forEach(([family, familyControls]) => {
3161
3200
  const familyDir = join4(controlsDir, family);
3162
3201
  const familyMappingsDir = join4(mappingsDir, family);
3163
3202
  if (!existsSync3(familyDir)) {
@@ -3166,7 +3205,10 @@ async function createOutputStructure(processedData, fieldSchema, params) {
3166
3205
  if (!existsSync3(familyMappingsDir)) {
3167
3206
  mkdirSync2(familyMappingsDir, { recursive: true });
3168
3207
  }
3169
- familyControls.forEach((control) => {
3208
+ const sortedFamilyControls = familyControls.sort(
3209
+ (a, b) => (a._originalRowIndex || 0) - (b._originalRowIndex || 0)
3210
+ );
3211
+ sortedFamilyControls.forEach((control) => {
3170
3212
  const controlId = control[controlIdFieldNameClean];
3171
3213
  if (!controlId) {
3172
3214
  console.error("Missing control ID for control:", control);
@@ -3188,7 +3230,7 @@ async function createOutputStructure(processedData, fieldSchema, params) {
3188
3230
  filteredControl.family = control.family;
3189
3231
  }
3190
3232
  Object.keys(control).forEach((fieldName) => {
3191
- if (fieldName === "family") return;
3233
+ if (fieldName === "family" || fieldName === "_originalRowIndex") return;
3192
3234
  if (params.justificationFields.includes(fieldName) && control[fieldName] !== void 0 && control[fieldName] !== null) {
3193
3235
  justificationContents.push(control[fieldName]);
3194
3236
  }
@@ -1703,8 +1703,8 @@ var init_fileStore = __esm({
1703
1703
  if (!this.baseDir || this.baseDir === "." || this.baseDir === process.cwd()) {
1704
1704
  return;
1705
1705
  }
1706
- const lulaConfigPath = join2(this.baseDir, "lula.yaml");
1707
- if (!existsSync2(lulaConfigPath)) {
1706
+ const lulaConfigPath2 = join2(this.baseDir, "lula.yaml");
1707
+ if (!existsSync2(lulaConfigPath2)) {
1708
1708
  return;
1709
1709
  }
1710
1710
  if (!existsSync2(this.controlsDir)) {
@@ -1862,6 +1862,17 @@ var init_fileStore = __esm({
1862
1862
  if (!existsSync2(this.controlsDir)) {
1863
1863
  return [];
1864
1864
  }
1865
+ let controlOrder = null;
1866
+ try {
1867
+ const lulaConfigPath2 = join2(this.baseDir, "lula.yaml");
1868
+ if (existsSync2(lulaConfigPath2)) {
1869
+ const content = readFileSync2(lulaConfigPath2, "utf8");
1870
+ const metadata = yaml2.load(content);
1871
+ controlOrder = metadata?.controlOrder || null;
1872
+ }
1873
+ } catch (error) {
1874
+ console.error(`Failed to load lula.yaml for controlOrder (path: ${lulaConfigPath}):`, error);
1875
+ }
1865
1876
  const entries = readdirSync(this.controlsDir);
1866
1877
  const yamlFiles = entries.filter((file) => file.endsWith(".yaml"));
1867
1878
  if (yamlFiles.length > 0) {
@@ -1880,7 +1891,11 @@ var init_fileStore = __esm({
1880
1891
  }
1881
1892
  });
1882
1893
  const results2 = await Promise.all(promises);
1883
- return results2.filter((c) => c !== null);
1894
+ const controls2 = results2.filter((c) => c !== null);
1895
+ if (controlOrder && controlOrder.length > 0) {
1896
+ return this.sortControlsByOrder(controls2, controlOrder);
1897
+ }
1898
+ return controls2;
1884
1899
  }
1885
1900
  const families = entries.filter((name) => {
1886
1901
  const familyPath = join2(this.controlsDir, name);
@@ -1903,7 +1918,25 @@ var init_fileStore = __esm({
1903
1918
  allPromises.push(...familyPromises);
1904
1919
  }
1905
1920
  const results = await Promise.all(allPromises);
1906
- return results.filter((c) => c !== null);
1921
+ const controls = results.filter((c) => c !== null);
1922
+ if (controlOrder && controlOrder.length > 0) {
1923
+ return this.sortControlsByOrder(controls, controlOrder);
1924
+ }
1925
+ return controls;
1926
+ }
1927
+ /**
1928
+ * Sort controls based on the provided order array
1929
+ */
1930
+ sortControlsByOrder(controls, controlOrder) {
1931
+ const orderMap = /* @__PURE__ */ new Map();
1932
+ controlOrder.forEach((controlId, index) => {
1933
+ orderMap.set(controlId, index);
1934
+ });
1935
+ return controls.sort((a, b) => {
1936
+ const aIndex = orderMap.get(a.id) ?? Number.MAX_SAFE_INTEGER;
1937
+ const bIndex = orderMap.get(b.id) ?? Number.MAX_SAFE_INTEGER;
1938
+ return aIndex - bIndex;
1939
+ });
1907
1940
  }
1908
1941
  /**
1909
1942
  * Load mappings from mappings directory
@@ -3023,6 +3056,7 @@ function processSpreadsheetData(rawData, headers, startRowIndex, params) {
3023
3056
  continue;
3024
3057
  }
3025
3058
  const family = extractFamilyFromControlId(controlId);
3059
+ control._originalRowIndex = i;
3026
3060
  control.family = family;
3027
3061
  controls.push(control);
3028
3062
  if (!families.has(family)) {
@@ -3145,6 +3179,7 @@ async function createOutputStructure(processedData, fieldSchema, params) {
3145
3179
  params.controlIdField,
3146
3180
  params.namingConvention
3147
3181
  );
3182
+ const controlOrder = controls.sort((a, b) => (a._originalRowIndex || 0) - (b._originalRowIndex || 0)).map((control) => control[controlIdFieldNameClean]);
3148
3183
  const controlSetData = {
3149
3184
  name: params.controlSetName,
3150
3185
  description: params.controlSetDescription,
@@ -3152,12 +3187,16 @@ async function createOutputStructure(processedData, fieldSchema, params) {
3152
3187
  control_id_field: controlIdFieldNameClean,
3153
3188
  controlCount: controls.length,
3154
3189
  families: uniqueFamilies,
3190
+ controlOrder,
3155
3191
  fieldSchema
3156
3192
  };
3157
3193
  writeFileSync2(join4(baseDir, "lula.yaml"), yaml4.dump(controlSetData));
3158
3194
  const controlsDir = join4(baseDir, "controls");
3159
3195
  const mappingsDir = join4(baseDir, "mappings");
3160
- families.forEach((familyControls, family) => {
3196
+ const sortedFamilies = Array.from(families.entries()).sort(
3197
+ (a, b) => a[0].localeCompare(b[0])
3198
+ );
3199
+ sortedFamilies.forEach(([family, familyControls]) => {
3161
3200
  const familyDir = join4(controlsDir, family);
3162
3201
  const familyMappingsDir = join4(mappingsDir, family);
3163
3202
  if (!existsSync3(familyDir)) {
@@ -3166,7 +3205,10 @@ async function createOutputStructure(processedData, fieldSchema, params) {
3166
3205
  if (!existsSync3(familyMappingsDir)) {
3167
3206
  mkdirSync2(familyMappingsDir, { recursive: true });
3168
3207
  }
3169
- familyControls.forEach((control) => {
3208
+ const sortedFamilyControls = familyControls.sort(
3209
+ (a, b) => (a._originalRowIndex || 0) - (b._originalRowIndex || 0)
3210
+ );
3211
+ sortedFamilyControls.forEach((control) => {
3170
3212
  const controlId = control[controlIdFieldNameClean];
3171
3213
  if (!controlId) {
3172
3214
  console.error("Missing control ID for control:", control);
@@ -3188,7 +3230,7 @@ async function createOutputStructure(processedData, fieldSchema, params) {
3188
3230
  filteredControl.family = control.family;
3189
3231
  }
3190
3232
  Object.keys(control).forEach((fieldName) => {
3191
- if (fieldName === "family") return;
3233
+ if (fieldName === "family" || fieldName === "_originalRowIndex") return;
3192
3234
  if (params.justificationFields.includes(fieldName) && control[fieldName] !== void 0 && control[fieldName] !== null) {
3193
3235
  justificationContents.push(control[fieldName]);
3194
3236
  }
@@ -124,8 +124,8 @@ var FileStore = class {
124
124
  if (!this.baseDir || this.baseDir === "." || this.baseDir === process.cwd()) {
125
125
  return;
126
126
  }
127
- const lulaConfigPath = join2(this.baseDir, "lula.yaml");
128
- if (!existsSync2(lulaConfigPath)) {
127
+ const lulaConfigPath2 = join2(this.baseDir, "lula.yaml");
128
+ if (!existsSync2(lulaConfigPath2)) {
129
129
  return;
130
130
  }
131
131
  if (!existsSync2(this.controlsDir)) {
@@ -283,6 +283,17 @@ var FileStore = class {
283
283
  if (!existsSync2(this.controlsDir)) {
284
284
  return [];
285
285
  }
286
+ let controlOrder = null;
287
+ try {
288
+ const lulaConfigPath2 = join2(this.baseDir, "lula.yaml");
289
+ if (existsSync2(lulaConfigPath2)) {
290
+ const content = readFileSync2(lulaConfigPath2, "utf8");
291
+ const metadata = yaml2.load(content);
292
+ controlOrder = metadata?.controlOrder || null;
293
+ }
294
+ } catch (error) {
295
+ console.error(`Failed to load lula.yaml for controlOrder (path: ${lulaConfigPath}):`, error);
296
+ }
286
297
  const entries = readdirSync(this.controlsDir);
287
298
  const yamlFiles = entries.filter((file) => file.endsWith(".yaml"));
288
299
  if (yamlFiles.length > 0) {
@@ -301,7 +312,11 @@ var FileStore = class {
301
312
  }
302
313
  });
303
314
  const results2 = await Promise.all(promises);
304
- return results2.filter((c) => c !== null);
315
+ const controls2 = results2.filter((c) => c !== null);
316
+ if (controlOrder && controlOrder.length > 0) {
317
+ return this.sortControlsByOrder(controls2, controlOrder);
318
+ }
319
+ return controls2;
305
320
  }
306
321
  const families = entries.filter((name) => {
307
322
  const familyPath = join2(this.controlsDir, name);
@@ -324,7 +339,25 @@ var FileStore = class {
324
339
  allPromises.push(...familyPromises);
325
340
  }
326
341
  const results = await Promise.all(allPromises);
327
- return results.filter((c) => c !== null);
342
+ const controls = results.filter((c) => c !== null);
343
+ if (controlOrder && controlOrder.length > 0) {
344
+ return this.sortControlsByOrder(controls, controlOrder);
345
+ }
346
+ return controls;
347
+ }
348
+ /**
349
+ * Sort controls based on the provided order array
350
+ */
351
+ sortControlsByOrder(controls, controlOrder) {
352
+ const orderMap = /* @__PURE__ */ new Map();
353
+ controlOrder.forEach((controlId, index) => {
354
+ orderMap.set(controlId, index);
355
+ });
356
+ return controls.sort((a, b) => {
357
+ const aIndex = orderMap.get(a.id) ?? Number.MAX_SAFE_INTEGER;
358
+ const bIndex = orderMap.get(b.id) ?? Number.MAX_SAFE_INTEGER;
359
+ return aIndex - bIndex;
360
+ });
328
361
  }
329
362
  /**
330
363
  * Load mappings from mappings directory
@@ -267,6 +267,7 @@ function processSpreadsheetData(rawData, headers, startRowIndex, params) {
267
267
  continue;
268
268
  }
269
269
  const family = extractFamilyFromControlId(controlId);
270
+ control._originalRowIndex = i;
270
271
  control.family = family;
271
272
  controls.push(control);
272
273
  if (!families.has(family)) {
@@ -389,6 +390,7 @@ async function createOutputStructure(processedData, fieldSchema, params) {
389
390
  params.controlIdField,
390
391
  params.namingConvention
391
392
  );
393
+ const controlOrder = controls.sort((a, b) => (a._originalRowIndex || 0) - (b._originalRowIndex || 0)).map((control) => control[controlIdFieldNameClean]);
392
394
  const controlSetData = {
393
395
  name: params.controlSetName,
394
396
  description: params.controlSetDescription,
@@ -396,12 +398,16 @@ async function createOutputStructure(processedData, fieldSchema, params) {
396
398
  control_id_field: controlIdFieldNameClean,
397
399
  controlCount: controls.length,
398
400
  families: uniqueFamilies,
401
+ controlOrder,
399
402
  fieldSchema
400
403
  };
401
404
  writeFileSync(join2(baseDir, "lula.yaml"), yaml4.dump(controlSetData));
402
405
  const controlsDir = join2(baseDir, "controls");
403
406
  const mappingsDir = join2(baseDir, "mappings");
404
- families.forEach((familyControls, family) => {
407
+ const sortedFamilies = Array.from(families.entries()).sort(
408
+ (a, b) => a[0].localeCompare(b[0])
409
+ );
410
+ sortedFamilies.forEach(([family, familyControls]) => {
405
411
  const familyDir = join2(controlsDir, family);
406
412
  const familyMappingsDir = join2(mappingsDir, family);
407
413
  if (!existsSync(familyDir)) {
@@ -410,7 +416,10 @@ async function createOutputStructure(processedData, fieldSchema, params) {
410
416
  if (!existsSync(familyMappingsDir)) {
411
417
  mkdirSync(familyMappingsDir, { recursive: true });
412
418
  }
413
- familyControls.forEach((control) => {
419
+ const sortedFamilyControls = familyControls.sort(
420
+ (a, b) => (a._originalRowIndex || 0) - (b._originalRowIndex || 0)
421
+ );
422
+ sortedFamilyControls.forEach((control) => {
414
423
  const controlId = control[controlIdFieldNameClean];
415
424
  if (!controlId) {
416
425
  console.error("Missing control ID for control:", control);
@@ -432,7 +441,7 @@ async function createOutputStructure(processedData, fieldSchema, params) {
432
441
  filteredControl.family = control.family;
433
442
  }
434
443
  Object.keys(control).forEach((fieldName) => {
435
- if (fieldName === "family") return;
444
+ if (fieldName === "family" || fieldName === "_originalRowIndex") return;
436
445
  if (params.justificationFields.includes(fieldName) && control[fieldName] !== void 0 && control[fieldName] !== null) {
437
446
  justificationContents.push(control[fieldName]);
438
447
  }