@nice2dev/ui-forms 1.4.4 → 1.4.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.
package/dist/studio.cjs CHANGED
@@ -1,10 +1,13 @@
1
- "use strict";var Se=Object.defineProperty;var je=(e,t,n)=>t in e?Se(e,t,{enumerable:!0,configurable:!0,writable:!0,value:n}):e[t]=n;var H=(e,t,n)=>je(e,typeof t!="symbol"?t+"":t,n);Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const Z="\uFEFF",Q={bom:!1,eol:`
2
- `,indent:" ",finalNewline:!0,colonSpace:!0};function P(e){const t=e.charCodeAt(0)===65279,n=e.includes(`\r
1
+ "use strict";var Fe=Object.defineProperty;var xe=(e,t,n)=>t in e?Fe(e,t,{enumerable:!0,configurable:!0,writable:!0,value:n}):e[t]=n;var ee=(e,t,n)=>xe(e,typeof t!="symbol"?t+"":t,n);Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const T=()=>({version:1,sections:[],folders:[],placement:{}}),Ie=(e,t)=>`${e}:${t}`,_=".studio.json",Me=/^([^/]+?)\.(manifest|entities|views|workflows|permissions|rbac|seeds|datasources|scripts)\.json$/i,se=e=>!e.includes("/")&&e.toLowerCase().endsWith(_);function Te(e){const t=e.find(n=>se(n.path));if(t)return t.path;for(const n of e){const s=Me.exec(n.path);if(s)return`${s[1]}${_}`}return`module${_}`}const N=e=>typeof e=="object"&&e!==null&&!Array.isArray(e),b=e=>typeof e=="string"&&e?e:void 0;function Le(e){if(!e)return T();let t;try{t=JSON.parse(e.replace(/^\uFEFF/,""))}catch{return T()}if(!N(t))return T();const n=(Array.isArray(t.sections)?t.sections:[]).filter(N).map(o=>({id:b(o.id),label:b(o.label)??b(o.id)})).filter(o=>!!o.id&&!!o.label),s=(Array.isArray(t.folders)?t.folders:[]).filter(N).map(o=>({id:b(o.id),label:b(o.label)??b(o.id),group:b(o.group),...b(o.parent)?{parent:b(o.parent)}:{},...b(o.section)?{section:b(o.section)}:{}})).filter(o=>!!o.id&&!!o.label&&!!o.group),i={};if(N(t.placement))for(const[o,c]of Object.entries(t.placement)){if(!N(c))continue;const l={};b(c.section)&&(l.section=b(c.section)),b(c.folder)&&(l.folder=b(c.folder)),typeof c.order=="number"&&Number.isFinite(c.order)&&(l.order=c.order),(l.section||l.folder||l.order!==void 0)&&(i[o]=l)}return{version:1,sections:n,folders:s,placement:i}}const Je=e=>e.sections.length===0&&e.folders.length===0&&Object.keys(e.placement).length===0;function Pe(e,t){const n=JSON.stringify(e,null,2)+`
2
+ `;return t!=null&&t.includes(`\r
3
+ `)?n.replace(/\n/g,`\r
4
+ `):n}const De=e=>e.toLowerCase().normalize("NFKD").replace(/[̀-ͯ]/g,"").replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"")||"item";function ie(e,t){const n=De(e);let s=n;for(let i=2;t.has(s);i++)s=`${n}-${i}`;return s}function Re(e,t){const n=ie(t,new Set(e.sections.map(s=>s.id)));return{layout:{...e,sections:[...e.sections,{id:n,label:t}]},id:n}}function Ce(e,t){const n=ie(t.label,new Set(e.folders.map(i=>i.id))),s={id:n,label:t.label,group:t.group};return t.parent&&(s.parent=t.parent),t.section&&(s.section=t.section),{layout:{...e,folders:[...e.folders,s]},id:n}}function Ve(e,t,n){return t.kind==="section"?{...e,sections:e.sections.map(s=>s.id===t.id?{...s,label:n}:s)}:{...e,folders:e.folders.map(s=>s.id===t.id?{...s,label:n}:s)}}function Ue(e,t){const n={};if(t.kind==="folder"){const s=e.folders.find(i=>i.id===t.id);for(const[i,o]of Object.entries(e.placement))n[i]=o.folder===t.id?{...o,folder:s==null?void 0:s.parent}:o,n[i].folder||delete n[i].folder;return{...e,folders:e.folders.filter(i=>i.id!==t.id).map(i=>i.parent===t.id?{...i,parent:s==null?void 0:s.parent}:i).map(i=>{if(!i.parent){const{parent:o,...c}=i;return c}return i}),placement:z(n)}}for(const[s,i]of Object.entries(e.placement))if(i.section===t.id){const{section:o,...c}=i;n[s]=c}else n[s]=i;return{...e,sections:e.sections.filter(s=>s.id!==t.id),folders:e.folders.map(s=>{if(s.section===t.id){const{section:i,...o}=s;return o}return s}),placement:z(n)}}function z(e){const t={};for(const[n,s]of Object.entries(e))(s.section||s.folder||s.order!==void 0)&&(t[n]=s);return t}function _e(e,t,n){var o;const s=(o=e.placement[t])==null?void 0:o.order,i={};if(n.folder){i.folder=n.folder;const c=e.folders.find(l=>l.id===n.folder);c!=null&&c.section&&(i.section=c.section)}else n.section&&(i.section=n.section);return s!==void 0&&(i.order=s),{...e,placement:z({...e.placement,[t]:i})}}function ze(e,t,n){if(t===n||!e.placement[t])return e;const s={...e.placement,[n]:e.placement[t]};return delete s[t],{...e,placement:s}}const re="\uFEFF",oe={bom:!1,eol:`
5
+ `,indent:" ",finalNewline:!0,colonSpace:!0};function C(e){const t=e.charCodeAt(0)===65279,n=e.includes(`\r
3
6
  `)?`\r
4
7
  `:`
5
- `;let i=Q.indent;const r=e.split(/\r?\n/);for(let c=1;c<r.length;c++){const d=/^([ \t]+)\S/.exec(r[c]);if(d){i=d[1];break}}const a=/"\s*:(\s?)/.exec(e);return{bom:t,eol:n,indent:i,finalNewline:/\n$/.test(e),colonSpace:a?a[1]!=="":!0}}function K(e){const t=P(e);return{value:JSON.parse(t.bom?e.slice(1):e),format:t}}function w(e,t){const n={...Q,...t},i=O(e,n,"");return(n.bom?Z:"")+i+(n.finalNewline?n.eol:"")}function ee(e,t){if(t===void 0)return e;let n=t.includes(`\r
8
+ `;let s=oe.indent;const i=e.split(/\r?\n/);for(let c=1;c<i.length;c++){const l=/^([ \t]+)\S/.exec(i[c]);if(l){s=l[1];break}}const o=/"\s*:(\s?)/.exec(e);return{bom:t,eol:n,indent:s,finalNewline:/\n$/.test(e),colonSpace:o?o[1]!=="":!0}}function O(e){const t=C(e);return{value:JSON.parse(t.bom?e.slice(1):e),format:t}}function k(e,t){const n={...oe,...t},s=E(e,n,"");return(n.bom?re:"")+s+(n.finalNewline?n.eol:"")}function ae(e,t){if(t===void 0)return e;let n=t.includes(`\r
6
9
  `)?e.replace(/\r?\n/g,`\r
7
- `):e;return t.charCodeAt(0)===65279&&n.charCodeAt(0)!==65279&&(n=Z+n),n}function x(e,t){if(e===t)return!0;if(typeof e!=typeof t||e===null||t===null||typeof e!="object"||Array.isArray(e)!==Array.isArray(t))return!1;if(Array.isArray(e)){const a=t;return e.length===a.length&&e.every((c,d)=>x(c,a[d]))}const n=e,i=t,r=Object.keys(n);return r.length!==Object.keys(i).length?!1:r.every(a=>Object.prototype.hasOwnProperty.call(i,a)&&x(n[a],i[a]))}function q(e,t,n){return te(e,t,n).text}function te(e,t,n){const i=P(e),r=s=>({text:w(t,i),exact:!1,reason:s});let a;try{a=new Ke(e).parseDocument()}catch(s){return r(s instanceof Error?s.message:String(s))}if(C(a))return r("duplicate keys");const c=[],d={text:e,format:i,edits:c,options:n,compact:!e.trimEnd().includes(`
8
- `)};z(d,a,t,"",!1);const u=Oe(e,c);try{const s=JSON.parse(i.bom?u.slice(1):u);if(!x(s,t))return r("patch did not read back")}catch{return r("patch was not valid JSON")}return{text:u,exact:!0}}class Ke{constructor(t){H(this,"pos",0);this.text=t}parseDocument(){this.text.charCodeAt(0)===65279&&(this.pos=1);const t=this.value();if(this.ws(),this.pos<this.text.length)throw new Error(`Unexpected text at ${this.pos}`);return t}ws(){for(;this.pos<this.text.length&&/\s/.test(this.text[this.pos]);)this.pos++}value(){this.ws();const t=this.text[this.pos];if(t==="{")return this.object();if(t==="[")return this.array();const n=this.pos;if(t==='"')return{kind:"scalar",start:n,end:this.stringEnd(),value:JSON.parse(this.slice(n))};const i=/^(?:-?\d+(?:\.\d+)?(?:[eE][+-]?\d+)?|true|false|null)/.exec(this.text.slice(n,n+64));if(!i)throw new Error(`Unexpected token at ${n}`);return this.pos=n+i[0].length,{kind:"scalar",start:n,end:this.pos,value:JSON.parse(i[0])}}slice(t){return this.text.slice(t,this.pos)}stringEnd(){for(this.pos++;this.pos<this.text.length;){const t=this.text[this.pos];if(t==="\\"){this.pos+=2;continue}if(this.pos++,t==='"')return this.pos}throw new Error("Unterminated string")}object(){const t=this.pos++,n=[];if(this.ws(),this.text[this.pos]==="}")return{kind:"object",start:t,end:++this.pos,members:n};for(;;){this.ws();const i=this.pos;if(this.text[this.pos]!=='"')throw new Error(`Expected a key at ${this.pos}`);const r=JSON.parse(this.text.slice(i,this.stringEnd()));if(this.ws(),this.text[this.pos]!==":")throw new Error(`Expected ':' at ${this.pos}`);this.pos++,n.push({key:r,start:i,value:this.value()}),this.ws();const a=this.text[this.pos++];if(a==="}")return{kind:"object",start:t,end:this.pos,members:n};if(a!==",")throw new Error(`Expected ',' or '}' at ${this.pos-1}`)}}array(){const t=this.pos++,n=[];if(this.ws(),this.text[this.pos]==="]")return{kind:"array",start:t,end:++this.pos,items:n};for(;;){n.push(this.value()),this.ws();const i=this.text[this.pos++];if(i==="]")return{kind:"array",start:t,end:this.pos,items:n};if(i!==",")throw new Error(`Expected ',' or ']' at ${this.pos-1}`)}}}function C(e){if(e.kind==="object"){const t=new Set;for(const n of e.members){if(t.has(n.key)||C(n.value))return!0;t.add(n.key)}}else if(e.kind==="array")return e.items.some(C);return!1}function M(e){if(e.kind==="scalar")return e.value;if(e.kind==="array")return e.items.map(M);const t={};for(const n of e.members)t[n.key]=M(n.value);return t}function O(e,t,n){if(e===null||typeof e!="object")return e===void 0?"null":JSON.stringify(e);const i=n+t.indent,r=t.colonSpace?": ":":";if(Array.isArray(e))return e.length===0?"[]":`[${t.eol}${e.map(c=>i+O(c,t,i)).join(`,${t.eol}`)}${t.eol}${n}]`;const a=Object.entries(e).filter(([,c])=>c!==void 0);return a.length===0?"{}":`{${t.eol}${a.map(([c,d])=>`${i}${JSON.stringify(c)}${r}${O(d,t,i)}`).join(`,${t.eol}`)}${t.eol}${n}}`}function A(e,t,n=!1){if(e===null||typeof e!="object")return e===void 0?"null":JSON.stringify(e);const i=t.colonSpace?": ":":",r=n?",":", ";if(Array.isArray(e))return`[${e.map(d=>A(d,t,n)).join(r)}]`;const a=Object.entries(e).filter(([,d])=>d!==void 0),c=n?"":" ";return a.length===0?"{}":`{${c}${a.map(([d,u])=>`${JSON.stringify(d)}${i}${A(u,t,n)}`).join(r)}${c}}`}const ne=e=>e.compact?",":", ";function Oe(e,t){let n=e;for(const i of[...t].sort((r,a)=>a.start-r.start))n=n.slice(0,i.start)+i.text+n.slice(i.end);return n}function F(e,t){var i;const n=e.lastIndexOf(`
9
- `,t-1)+1;return((i=/^[ \t]*/.exec(e.slice(n,t)))==null?void 0:i[0])??""}function se(e,t){return!e.slice(t.start,t.end).includes(`
10
- `)}function _(e,t,n){return e.compact?!0:t.kind==="scalar"||(t.kind==="object"?t.members.length===0:t.items.length===0)?n:se(e.text,t)}function N(e,t,n,i){const r=_(e,t,i);e.edits.push({start:t.start,end:t.end,text:r?A(n,e.format,e.compact):O(n,e.format,F(e.text,t.start))})}const ie=e=>typeof e=="object"&&e!==null&&!Array.isArray(e);function z(e,t,n,i,r){if(t.kind==="scalar"){if(t.value===n)return;N(e,t,n,r);return}x(M(t),n)||(t.kind==="object"&&ie(n)?Ae(e,t,n,i,r):t.kind==="array"&&Array.isArray(n)?Ne(e,t,n,i,r):N(e,t,n,r))}function re(e,t,n){return n!==void 0?F(e.text,n):F(e.text,t.start)+e.format.indent}function Ae(e,t,n,i,r){var l;const a=_(e,t,r),c=t.members.filter(f=>Object.prototype.hasOwnProperty.call(n,f.key)&&n[f.key]!==void 0),d=Object.keys(n).filter(f=>n[f]!==void 0&&!t.members.some(h=>h.key===f));if(c.length===0&&t.members.length>0){N(e,t,n,r);return}for(const f of c)z(e,f.value,n[f.key],`${i}/${Fe(f.key)}`,a);if(oe(e,t.members.map(f=>({start:f.start,end:f.value.end})),t.members.map(f=>c.includes(f))),d.length===0)return;const u=e.format.colonSpace?": ":":";if(a){const f=d.map(h=>`${JSON.stringify(h)}${u}${A(n[h],e.format,e.compact)}`);ce(e,t,c.length>0?c[c.length-1].value.end:void 0,f);return}const s=re(e,t,(l=t.members[0])==null?void 0:l.start),o=d.map(f=>`${s}${JSON.stringify(f)}${u}${O(n[f],e.format,s)}`);ae(e,t,c.length>0?c[c.length-1].value.end:void 0,o)}const Ee=["name","id","code","key","slug","state","Id"];function xe(e,t,n,i){var u,s;const r=[...n,...i];if(r.length===0||!r.every(ie))return;const a=(o,l)=>{const f=o.map(h=>h[l]);return f.every(h=>typeof h=="string"||typeof h=="number")&&new Set(f).size===f.length},c=(s=(u=e.options)==null?void 0:u.arrayKey)==null?void 0:s.call(u,t);return(c?[c]:Ee).find(o=>a(n,o)&&a(i,o))}function Ne(e,t,n,i,r){var g;const a=_(e,t,r),c=t.items.map(M),d=xe(e,i,c,n),u=p=>p[d],s=d!==void 0?c.map(p=>{const m=u(p);return n.findIndex(b=>u(b)===m)}):Me(c,n);{const p=new Set(s.filter(m=>m>=0));for(let m=0;m<s.length;m++){if(s[m]>=0)continue;let b=-1;for(let y=m-1;y>=0;y--)if(s[y]>=0){b=s[y];break}let $=n.length;for(let y=m+1;y<s.length;y++)if(s[y]>=0){$=s[y];break}for(let y=b+1;y<$;y++)if(!p.has(y)){s[m]=y,p.add(y);break}}}const o=s.filter(p=>p>=0);if(o.some((p,m)=>m>0&&p<o[m-1])){N(e,t,n,r);return}if(o.length===0&&t.items.length>0){N(e,t,n,r);return}t.items.forEach((p,m)=>{s[m]>=0&&z(e,p,n[s[m]],`${i}/${s[m]}`,a)}),oe(e,t.items.map(p=>({start:p.start,end:p.end})),s.map(p=>p>=0));const l=t.items.length>0&&t.items.every(p=>p.kind!=="scalar"&&se(e.text,p)),f=re(e,t,(g=t.items[0])==null?void 0:g.start),h=new Map;n.forEach((p,m)=>{if(s.includes(m))return;let b;for(let S=t.items.length-1;S>=0;S--)if(s[S]>=0&&s[S]<m){b=S;break}const $=a?A(p,e.format,e.compact):l?`${f}${A(p,e.format)}`:`${f}${O(p,e.format,f)}`,y=h.get(b)??[];y.push($),h.set(b,y)});for(const[p,m]of h){const b=p===void 0?void 0:t.items[p].end;if(p===void 0&&o.length>0){const $=t.items[s.findIndex(S=>S>=0)],y=a?ne(e):`,${e.format.eol}`;e.edits.push({start:$.start,end:$.start,text:a?m.join(y)+y:m.join(y).trimStart()+y+f});continue}a?ce(e,t,b,m):ae(e,t,b,m)}}const Ie=4e6;function Me(e,t){const n=e.length,i=t.length;if(n*i>Ie)return e.map((o,l)=>l<i?l:-1);const r=e.map(o=>JSON.stringify(o)),a=t.map(o=>JSON.stringify(o)),c=Array.from({length:n+1},()=>new Uint32Array(i+1));for(let o=n-1;o>=0;o--)for(let l=i-1;l>=0;l--)c[o][l]=r[o]===a[l]?c[o+1][l+1]+1:Math.max(c[o+1][l],c[o][l+1]);const d=new Array(n).fill(-1);let u=0,s=0;for(;u<n&&s<i;)r[u]===a[s]?d[u++]=s++:c[u+1][s]>=c[u][s+1]?u++:s++;return d}function oe(e,t,n){for(let i=0;i<t.length;i++){if(n[i])continue;let r=i;for(;r+1<t.length&&!n[r+1];)r++;r+1<t.length?e.edits.push({start:t[i].start,end:t[r+1].start,text:""}):i>0?e.edits.push({start:t[i-1].end,end:t[r].end,text:""}):e.edits.push({start:t[i].start,end:t[r].end,text:""}),i=r}}function ae(e,t,n,i){const r=e.format.eol;if(n!==void 0){e.edits.push({start:n,end:n,text:`,${r}${i.join(`,${r}`)}`});return}const a=t.end-1;if((t.kind==="object"?t.members.length:t.items.length)===0)e.edits.push({start:t.start+1,end:a,text:`${r}${i.join(`,${r}`)}${r}${F(e.text,t.start)}`});else{const d=t.kind==="object"?t.members[0].start:t.items[0].start;e.edits.push({start:d,end:d,text:`${i.join(`,${r}`).trimStart()}`})}}function ce(e,t,n,i){const r=ne(e);if(n!==void 0){e.edits.push({start:n,end:n,text:`${r}${i.join(r)}`});return}const a=t.kind==="object"&&!e.compact?" ":"";e.edits.push({start:t.start+1,end:t.end-1,text:`${a}${i.join(r)}${a}`})}function Fe(e){return e.replace(/~/g,"~0").replace(/\//g,"~1")}const j=e=>e.slice(e.lastIndexOf("/")+1),Te=e=>e.charCodeAt(0)===65279?e.slice(1):e;function V(e){return{id:e.id,label:e.label,labelKey:e.labelKey,icon:e.icon,match:e.match,editor:e.editor,decode(t,n){return e.select(K(t[0].text).value,n)},encode(t,n,i){const r=n[0].text,a=K(r).value,c=e.assign(a,t,i);return{files:[{path:n[0].path,text:q(r,c,{arrayKey:e.arrayKey})}]}}}}const T=V({id:"json",label:"JSON",labelKey:"devStudio.kind.json",icon:"code",match:e=>e.toLowerCase().endsWith(".json"),editor:"json",select:e=>e,assign:(e,t)=>t}),J={id:"text",label:"Text",labelKey:"devStudio.kind.text",icon:"file",match:()=>!0,editor:"text",decode:e=>e[0].text,encode:(e,t)=>({files:[{path:t[0].path,text:ee(e,t[0].text)}]})};function le(e,t){return e.find(n=>n.match(t))??(T.match(t)?T:J)}function Je(e,t,n){for(const i of[T,J])if(i.match(e.path))try{const r=i.decode([e],n);return{key:`${i.id}:${e.path}`,kind:i,paths:[e.path],label:j(e.path),model:r,error:t}}catch{}return{key:`text:${e.path}`,kind:J,paths:[e.path],label:j(e.path),model:e.text,error:t}}function De(e,t,n,i){var d,u;const r=e.encode(t,n,i),a=new Map(n.map(s=>[s.path,s.text])),c=((d=r.files.find(s=>a.get(s.path)!==s.text))==null?void 0:d.path)??((u=r.deleted)==null?void 0:u.find(s=>a.has(s)));if(c!==void 0)throw new Error(`${j(c)} would not be stored as it is`)}function Pe(e,t,n){const i=new Map;for(const a of t){const c=le(e,a.path),d=c.group?c.group(a.path):a.path,u=`${c.id}:${d}`,s=i.get(u)??{kind:c,group:d,files:[]};s.files.push(a),i.set(u,s)}const r=[];for(const[a,{kind:c,group:d,files:u}]of i){const s=u.map(l=>l.path).sort(),o=j(c.group?d:s[0]);try{const l=c.decode(u,n);De(c,l,u,n),r.push({key:a,kind:c,paths:s,label:o,model:l})}catch(l){const f=l instanceof Error?l.message:String(l);for(const h of u)r.push(Je(h,f,n))}}return r.sort((a,c)=>a.label.localeCompare(c.label))}function Ve(e,t,n,i){const r=n.filter(u=>e.paths.includes(u.path)),a=e.kind.encode(t,r,i),c=new Map(n.map(u=>[u.path,u])),d=[];for(const u of a.files){const s=c.get(u.path);s&&s.text===u.text||d.push({type:"write",path:u.path,text:u.text,baseVersion:s==null?void 0:s.version})}for(const u of a.deleted??[]){const s=c.get(u);s&&d.push({type:"delete",path:u,baseVersion:s.version})}return d}function de(e,t){try{return JSON.parse(Te(e))}catch{return t}}const k=e=>typeof e=="object"&&e!==null&&!Array.isArray(e),v=(...e)=>t=>{const n=t.toLowerCase();return e.some(i=>n.endsWith(i.toLowerCase()))};function I(e){return V({id:e.id,label:e.label,labelKey:e.labelKey,icon:e.icon,editor:e.editor,match:e.match,select:t=>{if(Array.isArray(t))return t;const n=k(t)?t[e.property]:void 0;return Array.isArray(n)?n:[]},assign:(t,n)=>Array.isArray(t)?n:k(t)&&!(e.property in t)&&n.length===0?t:{...k(t)?t:{},[e.property]:n},arrayKey:e.itemKey?()=>e.itemKey:void 0})}function B(e){const t=I(e);return{...t,decode:(n,i)=>t.decode(n,i).map((r,a)=>e.toItem(r,a)),encode:(n,i,r)=>t.encode(n.map(a=>e.fromItem(a)),i,r)}}function G(e){return V({...e,select:t=>k(t)?t:{},assign:(t,n)=>n})}const Le=/^(.*)\.([a-z]{2,3}(?:-[A-Za-z]{2,4})?)\.i18n\.json$/i,Ce=e=>{const t=Le.exec(e);return t?{group:t[1],locale:t[2]}:null},R=e=>k(e)&&Object.values(e).every(t=>typeof t=="string");function fe(e){if(k(e)){for(const t of["translations","keys"])if(t in e){if(R(e[t]))return e[t];throw new Error(`"${t}" is not a flat map of texts`)}if(R(e))return e}throw new Error("no translations in this file")}function U(e,t){return k(e)?k(e.translations)?{...e,translations:t}:k(e.keys)?{...e,keys:t}:R(e)?t:{...e,translations:t}:{translations:t}}function ue(e={}){const t=e.parse??Ce,n=e.pathFor??((i,r)=>`${i}.${r}.i18n.json`);return{id:e.id??"i18n",label:e.label??"Translations",labelKey:e.labelKey??"devStudio.kind.i18n",icon:"globe",editor:"i18n",match:i=>t(i)!==null,group:i=>{var r;return((r=t(i))==null?void 0:r.group)??i},decode(i){const r={};for(const a of i){const c=t(a.path);c&&(r[c.locale]={...fe(K(a.text).value)})}return r},encode(i,r){const a=new Map;let c="";for(const o of r){const l=t(o.path);l&&(a.set(l.locale,o),c=l.group)}const d=a.get("en")??r[0],u=[];for(const[o,l]of Object.entries(i)){const f=a.get(o);if(f){const g=K(f.text).value;u.push({path:f.path,text:q(f.text,U(g,l))});continue}const h=n(c||j((d==null?void 0:d.path)??"module"),o);if(d){const g=K(d.text).value,p=k(g)&&"locale"in g?{...g,locale:o}:g;u.push({path:h,text:w(U(p,l),P(d.text))})}else u.push({path:h,text:w({locale:o,translations:l})})}const s=[...a.entries()].filter(([o])=>!(o in i)).map(([,o])=>o.path);return{files:u,deleted:s}}}}const E=e=>JSON.parse(JSON.stringify(e));function Re(e){const t=e.revisions!==!1;let n=0;const i=e.workspaces.map(s=>({meta:{id:s.id,label:s.label,description:s.description,icon:s.icon,readOnly:s.readOnly},packages:new Map((s.packages??[]).map(o=>[o.id,{...o,workspaceId:s.id}])),modules:new Map(s.modules.map(o=>[o.id,{...o,files:new Map(Object.entries(o.files).map(([l,f])=>[l,{text:f,version:++n}])),revisions:[]}]))}));let r=(e.templates??[]).map(s=>E(s));const a=s=>{const o=i.find(l=>l.meta.id===s);if(!o)throw new Error(`Unknown workspace "${s}"`);return o},c=s=>{const o=a(s.workspaceId).modules.get(s.id);if(!o)throw new Error(`Unknown module "${s.id}"`);return o},d=(s,o)=>({workspaceId:s,id:o.id,packageId:o.packageId,label:o.label??o.id,description:o.description,icon:o.icon,version:o.version,readOnly:o.readOnly||a(s).meta.readOnly,files:[...o.files.keys()].sort()}),u=(s,o)=>({path:s,text:o.text,version:String(o.version)});return{async listWorkspaces(){return i.map(s=>({...s.meta}))},async listModules(s){return[...a(s).modules.values()].map(l=>d(s,l))},async listPackages(s){const o=a(s),l=[...o.packages.values()],f=[...new Set([...o.modules.values()].map(h=>h.packageId).filter(Boolean))].filter(h=>!o.packages.has(h)).map(h=>({id:h,workspaceId:s,label:h,derived:!0}));return[...l,...f]},async readModule(s){return[...c(s).files.entries()].map(([l,f])=>u(l,f))},async writeModule(s,o){const l=c(s);if(l.readOnly||a(s.workspaceId).meta.readOnly)throw new Error(`Module "${s.id}" is read-only`);const f=o.filter(p=>p.baseVersion!==void 0).filter(p=>{const m=l.files.get(p.path);return m?String(m.version)!==p.baseVersion:!1}).map(p=>{var m;return{path:p.path,currentVersion:String((m=l.files.get(p.path))==null?void 0:m.version)}});if(f.length>0)return{ok:!1,conflicts:f};let h;if(t){const p={};for(const[m,b]of l.files)p[m]=b.text;h=`r${++n}`,l.revisions.unshift({id:h,timestamp:Date.now(),label:h,summary:o.map(m=>`${m.type} ${m.path}`).join(", "),files:p})}const g={};for(const p of o)if(p.type==="delete")l.files.delete(p.path);else{const m=++n;l.files.set(p.path,{text:p.text,version:m}),g[p.path]=String(m)}return{ok:!0,versions:g,revision:h}},async createModule(s){const o=a(s.workspaceId);if(o.meta.readOnly)throw new Error(`Workspace "${s.workspaceId}" is read-only`);if(o.modules.has(s.id))throw new Error(`Module "${s.id}" already exists`);const l={id:s.id,packageId:s.packageId,files:new Map(s.files.map(f=>[f.path,{text:f.text,version:++n}])),revisions:[]};return o.modules.set(s.id,l),d(s.workspaceId,l)},async deleteModule(s){const o=a(s.workspaceId);if(o.meta.readOnly)throw new Error(`Workspace "${s.workspaceId}" is read-only`);o.modules.delete(s.id)},async savePackage(s){return a(s.workspaceId).packages.set(s.id,{...s,derived:!1}),{...s,derived:!1}},async deletePackage(s){a(s.workspaceId).packages.delete(s.id)},async listTemplates(){return r.map(s=>E(s))},async saveTemplate(s,o){const l=(o==null?void 0:o.previousId)??s.id,f=E(s),h=r.findIndex(g=>g.id===l);return r=h>=0?r.map((g,p)=>p===h?f:g):[...r,f],E(f)},async deleteTemplate(s){r=r.filter(o=>o.id!==s)},async listRevisions(s,o){return c(s).revisions.filter(l=>!o||o in l.files).map(({files:l,...f})=>({...f,...o?{path:o}:{}}))},async readRevision(s,o,l){const f=c(s).revisions.find(h=>h.id===o);if(!f)throw new Error(`Unknown revision "${o}"`);return l?f.files[l]??"":JSON.stringify(f.files,null,2)},async rollback(s,o,l){const f=c(s),h=f.revisions.find(p=>p.id===o);if(!h)throw new Error(`Unknown revision "${o}"`);const g=l?{[l]:h.files[l]}:h.files;if(!l)for(const p of[...f.files.keys()])p in g||f.files.delete(p);for(const[p,m]of Object.entries(g))m!==void 0&&f.files.set(p,{text:m,version:++n})},snapshot(){return{workspaces:i.map(s=>({...s.meta,packages:[...s.packages.values()].map(({workspaceId:o,...l})=>l),modules:[...s.modules.values()].map(o=>({id:o.id,packageId:o.packageId,label:o.label,description:o.description,icon:o.icon,version:o.version,readOnly:o.readOnly,files:Object.fromEntries([...o.files.entries()].map(([l,f])=>[l,f.text]))}))})),templates:r.map(s=>E(s)),revisions:t}}}}function Ue(e){return e}function D(e,t){if(!t||e===void 0||e===null)return!0;if(t.enum&&!t.enum.includes(e))return!1;switch(t.type){case"string":return typeof e=="string";case"number":return typeof e=="number";case"integer":return Number.isInteger(e);case"boolean":return typeof e=="boolean";case"array":return Array.isArray(e)&&(!t.items||e.every(n=>D(n,t.items)));case"object":{if(typeof e!="object"||Array.isArray(e))return!1;const n=t.properties;return!n||Object.entries(e).every(([i,r])=>i in n&&D(r,n[i]))}default:return!0}}function We(e,t){var c;const n=(e.fields??[]).map(d=>d.name),i=(c=e.schema)==null?void 0:c.properties;if(!e.schema||!i)return{section:e,keys:n};const r=Object.entries(i).filter(([d,u])=>!(d in t)||D(t[d],u)),a=r.map(([d])=>d);return{section:{...e,schema:{...e.schema,properties:Object.fromEntries(r),...e.schema.required?{required:e.schema.required.filter(d=>a.includes(d))}:{}}},keys:[...a,...n]}}function qe(e){var n;const t=new Set;for(const i of e){for(const r of Object.keys(((n=i.schema)==null?void 0:n.properties)??{}))t.add(r);for(const r of i.fields??[])t.add(r.name)}return t}function _e(e){return e.map(t=>{const n=t;return{name:String(n.tableName||n.name||"Entity"),columns:(Array.isArray(n.fields)?n.fields:[]).map(i=>({name:String(i.name??""),dataType:String(i.dataType??i.type??"string"),isPrimaryKey:!!i.isPrimaryKey,isForeignKey:!!(i.isForeignKey??i.foreignKey)}))}})}function ze(e){const t=e.manifest??{},n=String(t.displayName||t.packageName||"Module"),i=(e.views??[]).map(a=>({id:`view:${a.id}`,label:a.name,type:"view"})),r=(e.entities??[]).map(a=>{const c=String(a.name??"Entity");return{id:`entity:${c}`,label:c,type:"entity"}});return{roles:[{id:"admin",label:"Admin"},{id:"user",label:"User"}],actions:[{id:"view",label:"View"},{id:"create",label:"Create"},{id:"edit",label:"Edit"},{id:"delete",label:"Delete"}],resources:[{id:"module",label:n,type:"module",children:[...i.length?[{id:"views",label:"Views",type:"group",children:i}]:[],...r.length?[{id:"entities",label:"Entities",type:"group",children:r}]:[]]}],grants:{}}}const L=G({id:"manifest",label:"Manifest",labelKey:"devStudio.kind.manifest",icon:"file",editor:"manifest",match:v(".manifest.json")}),pe=I({id:"entities",label:"Entities",labelKey:"devStudio.kind.entities",icon:"database",editor:"entities",match:v(".entities.json"),property:"entities",itemKey:"name"}),me=ue();function he(e,t){const n=e,i=typeof e=="object"&&e!==null&&typeof n.id=="string";return{key:i?n.id:`#${t}`,label:i&&n.name||(i?n.id:`#${t+1}`),...i?{definition:n}:{rawReason:"no id"},source:e}}const ye=B({id:"views",label:"Views",labelKey:"devStudio.kind.views",icon:"grid",editor:"views",match:v(".views.json"),property:"views",itemKey:"id",toItem:(e,t)=>he(e,t),fromItem:e=>e.definition??e.source}),ge=B({id:"workflows",label:"Workflows",labelKey:"devStudio.kind.workflows",icon:"git-branch",editor:"workflows",match:v(".workflows.json"),property:"workflows",itemKey:"id",toItem:(e,t)=>he(e,t),fromItem:e=>e.definition??e.source}),be=I({id:"dataSources",label:"Data sources",labelKey:"devStudio.kind.dataSources",icon:"database",editor:"dataSources",match:v(".datasources.json"),property:"dataSources",itemKey:"key"}),we=G({id:"rbac",label:"Access",labelKey:"devStudio.kind.rbac",icon:"shield",editor:"rbac",match:v(".rbac.json")}),ke=I({id:"hooks",label:"Lifecycle hooks",labelKey:"devStudio.kind.hooks",icon:"zap",editor:"hooks",match:v(".hooks.json"),property:"bindings",itemKey:"id"}),ve=[L,pe,me,ye,ge,be,we,ke];function W(e){return e.normalize("NFKD").replace(/[̀-ͯ]/g,"").replace(/ł/g,"l").replace(/Ł/g,"L").toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"")||"module"}const X=e=>{const t=e.find(n=>L.match(n.path));return t?de(t.text,void 0):void 0};function $e(e){const t=e.find(n=>L.match(n.path));return t?j(t.path).replace(/\.manifest\.json$/i,""):"module"}const Y=e=>Array.isArray(e.fields)?e.fields:[],Be={id:"native",kinds:ve,locales:["en","pl","de","fr","es","uk"],requiredLocales:["en"],moduleId:e=>{const t=X(e),n=(t==null?void 0:t.id)??(t==null?void 0:t.packageName);return typeof n=="string"?n:void 0},validateModule:({files:e})=>{const t=X(e);return t?["id","name","version"].filter(n=>typeof t[n]!="string"||!t[n]).map(n=>({severity:"error",code:"manifest.required",message:`The manifest needs "${n}".`,messageKey:"devStudio.issue.manifestRequired",params:{field:n},pointer:`/${n}`})):[{severity:"error",code:"manifest.missing",message:"The module has no manifest.",messageKey:"devStudio.issue.manifestMissing"}]},newFile:(e,{files:t})=>{const n=$e(t),r={entities:["entities.json",{entities:[]}],views:["views.json",{views:[]}],workflows:["workflows.json",{workflows:[]}],dataSources:["datasources.json",{dataSources:[]}],rbac:["rbac.json",{roles:[],actions:[],resources:[],grants:{}}],hooks:["hooks.json",{bindings:[]}]}[e];return r?{path:`${n}.${r[0]}`,text:w(r[1])}:void 0},generateModule:async(e,{existingIds:t})=>{let n=W(e.name);for(let r=2;t.has(n);r++)n=`${W(e.name)}-${r}`;const i=[{path:`${n}.manifest.json`,text:w({id:n,name:e.name,version:"1.0.0",...e.description?{description:e.description}:{},...e.icon?{icon:e.icon}:{},...e.packageId?{category:e.packageId}:{}})},{path:`${n}.entities.json`,text:w({entities:e.entities})}];for(const r of e.locales){const a={"module.displayName":e.name};for(const c of e.entities){const d=String(c.name??"");a[`entity.${d}.displayName`]=d;for(const u of Y(c))a[`field.${d}.${String(u.name)}.label`]=String(u.name)}i.push({path:`${n}.${r}.i18n.json`,text:w({locale:r,translations:a})})}if(e.views){const r=e.entities.map(a=>{const c=String(a.name??"Item");return{id:`${c}List`,name:`${c} list`,kind:"grid",version:2,columns:12,dataSources:[{key:"rows",type:"entity",entity:c,autoLoad:!0}],rows:[{id:"r1",cells:[{id:"grid",controlType:"dataGrid",colSpan:12,props:{columns:Y(a).map(d=>({field:String(d.name),header:String(d.name)}))},bindings:{data:{source:"rows",field:""}}}]}]}});i.push({path:`${n}.views.json`,text:w({views:r})})}if(e.permissions){const r={roles:[{id:"viewer",label:"Viewer"},{id:"editor",label:"Editor"},{id:"admin",label:"Admin"}],actions:[{id:"view",label:"View"},{id:"edit",label:"Edit"},{id:"delete",label:"Delete"}],resources:e.entities.map(a=>({id:`entity:${String(a.name)}`,label:String(a.name),type:"entity"})),grants:{}};i.push({path:`${n}.rbac.json`,text:w(r)})}return{id:n,packageId:e.packageId,files:i}}};exports.arrayFileKind=I;exports.buildDocuments=Pe;exports.createMemoryStudioProvider=Re;exports.defineManifestSection=Ue;exports.deriveDefaultRbac=ze;exports.detectJsonTextFormat=P;exports.encodeDocument=Ve;exports.endsWithAny=v;exports.entitiesToSchemas=_e;exports.fileName=j;exports.fitManifestSection=We;exports.i18nFileKind=ue;exports.itemsFileKind=B;exports.jsonFallbackKind=T;exports.jsonFileKind=V;exports.jsonValueFitsSchema=D;exports.jsonValuesEqual=x;exports.keepTextFormat=ee;exports.manifestSectionKeys=qe;exports.modulePrefix=$e;exports.nativeDataSourcesKind=be;exports.nativeEntitiesKind=pe;exports.nativeFileKinds=ve;exports.nativeHooksKind=ke;exports.nativeI18nKind=me;exports.nativeManifestKind=L;exports.nativeRbacKind=we;exports.nativeStudioPreset=Be;exports.nativeViewsKind=ye;exports.nativeWorkflowsKind=ge;exports.objectFileKind=G;exports.parseJsonText=K;exports.patchJsonText=q;exports.patchJsonTextDetailed=te;exports.readTranslations=fe;exports.resolveFileKind=le;exports.safeJson=de;exports.slugifyModuleId=W;exports.stringifyJsonText=w;exports.textFallbackKind=J;exports.writeTranslations=U;
10
+ `):e;return t.charCodeAt(0)===65279&&n.charCodeAt(0)!==65279&&(n=re+n),n}function x(e,t){if(e===t)return!0;if(typeof e!=typeof t||e===null||t===null||typeof e!="object"||Array.isArray(e)!==Array.isArray(t))return!1;if(Array.isArray(e)){const o=t;return e.length===o.length&&e.every((c,l)=>x(c,o[l]))}const n=e,s=t,i=Object.keys(n);return i.length!==Object.keys(s).length?!1:i.every(o=>Object.prototype.hasOwnProperty.call(s,o)&&x(n[o],s[o]))}function G(e,t,n){return ce(e,t,n).text}function ce(e,t,n){const s=C(e),i=r=>({text:k(t,s),exact:!1,reason:r});let o;try{o=new We(e).parseDocument()}catch(r){return i(r instanceof Error?r.message:String(r))}if(W(o))return i("duplicate keys");const c=[],l={text:e,format:s,edits:c,options:n,compact:!e.trimEnd().includes(`
11
+ `)};Y(l,o,t,"",!1);const u=qe(e,c);try{const r=JSON.parse(s.bom?u.slice(1):u);if(!x(r,t))return i("patch did not read back")}catch{return i("patch was not valid JSON")}return{text:u,exact:!0}}class We{constructor(t){ee(this,"pos",0);this.text=t}parseDocument(){this.text.charCodeAt(0)===65279&&(this.pos=1);const t=this.value();if(this.ws(),this.pos<this.text.length)throw new Error(`Unexpected text at ${this.pos}`);return t}ws(){for(;this.pos<this.text.length&&/\s/.test(this.text[this.pos]);)this.pos++}value(){this.ws();const t=this.text[this.pos];if(t==="{")return this.object();if(t==="[")return this.array();const n=this.pos;if(t==='"')return{kind:"scalar",start:n,end:this.stringEnd(),value:JSON.parse(this.slice(n))};const s=/^(?:-?\d+(?:\.\d+)?(?:[eE][+-]?\d+)?|true|false|null)/.exec(this.text.slice(n,n+64));if(!s)throw new Error(`Unexpected token at ${n}`);return this.pos=n+s[0].length,{kind:"scalar",start:n,end:this.pos,value:JSON.parse(s[0])}}slice(t){return this.text.slice(t,this.pos)}stringEnd(){for(this.pos++;this.pos<this.text.length;){const t=this.text[this.pos];if(t==="\\"){this.pos+=2;continue}if(this.pos++,t==='"')return this.pos}throw new Error("Unterminated string")}object(){const t=this.pos++,n=[];if(this.ws(),this.text[this.pos]==="}")return{kind:"object",start:t,end:++this.pos,members:n};for(;;){this.ws();const s=this.pos;if(this.text[this.pos]!=='"')throw new Error(`Expected a key at ${this.pos}`);const i=JSON.parse(this.text.slice(s,this.stringEnd()));if(this.ws(),this.text[this.pos]!==":")throw new Error(`Expected ':' at ${this.pos}`);this.pos++,n.push({key:i,start:s,value:this.value()}),this.ws();const o=this.text[this.pos++];if(o==="}")return{kind:"object",start:t,end:this.pos,members:n};if(o!==",")throw new Error(`Expected ',' or '}' at ${this.pos-1}`)}}array(){const t=this.pos++,n=[];if(this.ws(),this.text[this.pos]==="]")return{kind:"array",start:t,end:++this.pos,items:n};for(;;){n.push(this.value()),this.ws();const s=this.text[this.pos++];if(s==="]")return{kind:"array",start:t,end:this.pos,items:n};if(s!==",")throw new Error(`Expected ',' or ']' at ${this.pos-1}`)}}}function W(e){if(e.kind==="object"){const t=new Set;for(const n of e.members){if(t.has(n.key)||W(n.value))return!0;t.add(n.key)}}else if(e.kind==="array")return e.items.some(W);return!1}function L(e){if(e.kind==="scalar")return e.value;if(e.kind==="array")return e.items.map(L);const t={};for(const n of e.members)t[n.key]=L(n.value);return t}function E(e,t,n){if(e===null||typeof e!="object")return e===void 0?"null":JSON.stringify(e);const s=n+t.indent,i=t.colonSpace?": ":":";if(Array.isArray(e))return e.length===0?"[]":`[${t.eol}${e.map(c=>s+E(c,t,s)).join(`,${t.eol}`)}${t.eol}${n}]`;const o=Object.entries(e).filter(([,c])=>c!==void 0);return o.length===0?"{}":`{${t.eol}${o.map(([c,l])=>`${s}${JSON.stringify(c)}${i}${E(l,t,s)}`).join(`,${t.eol}`)}${t.eol}${n}}`}function A(e,t,n=!1){if(e===null||typeof e!="object")return e===void 0?"null":JSON.stringify(e);const s=t.colonSpace?": ":":",i=n?",":", ";if(Array.isArray(e))return`[${e.map(l=>A(l,t,n)).join(i)}]`;const o=Object.entries(e).filter(([,l])=>l!==void 0),c=n?"":" ";return o.length===0?"{}":`{${c}${o.map(([l,u])=>`${JSON.stringify(l)}${s}${A(u,t,n)}`).join(i)}${c}}`}const le=e=>e.compact?",":", ";function qe(e,t){let n=e;for(const s of[...t].sort((i,o)=>o.start-i.start))n=n.slice(0,s.start)+s.text+n.slice(s.end);return n}function J(e,t){var s;const n=e.lastIndexOf(`
12
+ `,t-1)+1;return((s=/^[ \t]*/.exec(e.slice(n,t)))==null?void 0:s[0])??""}function de(e,t){return!e.slice(t.start,t.end).includes(`
13
+ `)}function H(e,t,n){return e.compact?!0:t.kind==="scalar"||(t.kind==="object"?t.members.length===0:t.items.length===0)?n:de(e.text,t)}function I(e,t,n,s){const i=H(e,t,s);e.edits.push({start:t.start,end:t.end,text:i?A(n,e.format,e.compact):E(n,e.format,J(e.text,t.start))})}const fe=e=>typeof e=="object"&&e!==null&&!Array.isArray(e);function Y(e,t,n,s,i){if(t.kind==="scalar"){if(t.value===n)return;I(e,t,n,i);return}x(L(t),n)||(t.kind==="object"&&fe(n)?Be(e,t,n,s,i):t.kind==="array"&&Array.isArray(n)?He(e,t,n,s,i):I(e,t,n,i))}function ue(e,t,n){return n!==void 0?J(e.text,n):J(e.text,t.start)+e.format.indent}function Be(e,t,n,s,i){var d;const o=H(e,t,i),c=t.members.filter(f=>Object.prototype.hasOwnProperty.call(n,f.key)&&n[f.key]!==void 0),l=Object.keys(n).filter(f=>n[f]!==void 0&&!t.members.some(h=>h.key===f));if(c.length===0&&t.members.length>0){I(e,t,n,i);return}for(const f of c)Y(e,f.value,n[f.key],`${s}/${Qe(f.key)}`,o);if(pe(e,t.members.map(f=>({start:f.start,end:f.value.end})),t.members.map(f=>c.includes(f))),l.length===0)return;const u=e.format.colonSpace?": ":":";if(o){const f=l.map(h=>`${JSON.stringify(h)}${u}${A(n[h],e.format,e.compact)}`);he(e,t,c.length>0?c[c.length-1].value.end:void 0,f);return}const r=ue(e,t,(d=t.members[0])==null?void 0:d.start),a=l.map(f=>`${r}${JSON.stringify(f)}${u}${E(n[f],e.format,r)}`);me(e,t,c.length>0?c[c.length-1].value.end:void 0,a)}const Xe=["name","id","code","key","slug","state","Id"];function Ge(e,t,n,s){var u,r;const i=[...n,...s];if(i.length===0||!i.every(fe))return;const o=(a,d)=>{const f=a.map(h=>h[d]);return f.every(h=>typeof h=="string"||typeof h=="number")&&new Set(f).size===f.length},c=(r=(u=e.options)==null?void 0:u.arrayKey)==null?void 0:r.call(u,t);return(c?[c]:Xe).find(a=>o(n,a)&&o(s,a))}function He(e,t,n,s,i){var g;const o=H(e,t,i),c=t.items.map(L),l=Ge(e,s,c,n),u=p=>p[l],r=l!==void 0?c.map(p=>{const m=u(p);return n.findIndex(w=>u(w)===m)}):Ze(c,n);{const p=new Set(r.filter(m=>m>=0));for(let m=0;m<r.length;m++){if(r[m]>=0)continue;let w=-1;for(let y=m-1;y>=0;y--)if(r[y]>=0){w=r[y];break}let $=n.length;for(let y=m+1;y<r.length;y++)if(r[y]>=0){$=r[y];break}for(let y=w+1;y<$;y++)if(!p.has(y)){r[m]=y,p.add(y);break}}}const a=r.filter(p=>p>=0);if(a.some((p,m)=>m>0&&p<a[m-1])){I(e,t,n,i);return}if(a.length===0&&t.items.length>0){I(e,t,n,i);return}t.items.forEach((p,m)=>{r[m]>=0&&Y(e,p,n[r[m]],`${s}/${r[m]}`,o)}),pe(e,t.items.map(p=>({start:p.start,end:p.end})),r.map(p=>p>=0));const d=t.items.length>0&&t.items.every(p=>p.kind!=="scalar"&&de(e.text,p)),f=ue(e,t,(g=t.items[0])==null?void 0:g.start),h=new Map;n.forEach((p,m)=>{if(r.includes(m))return;let w;for(let j=t.items.length-1;j>=0;j--)if(r[j]>=0&&r[j]<m){w=j;break}const $=o?A(p,e.format,e.compact):d?`${f}${A(p,e.format)}`:`${f}${E(p,e.format,f)}`,y=h.get(w)??[];y.push($),h.set(w,y)});for(const[p,m]of h){const w=p===void 0?void 0:t.items[p].end;if(p===void 0&&a.length>0){const $=t.items[r.findIndex(j=>j>=0)],y=o?le(e):`,${e.format.eol}`;e.edits.push({start:$.start,end:$.start,text:o?m.join(y)+y:m.join(y).trimStart()+y+f});continue}o?he(e,t,w,m):me(e,t,w,m)}}const Ye=4e6;function Ze(e,t){const n=e.length,s=t.length;if(n*s>Ye)return e.map((a,d)=>d<s?d:-1);const i=e.map(a=>JSON.stringify(a)),o=t.map(a=>JSON.stringify(a)),c=Array.from({length:n+1},()=>new Uint32Array(s+1));for(let a=n-1;a>=0;a--)for(let d=s-1;d>=0;d--)c[a][d]=i[a]===o[d]?c[a+1][d+1]+1:Math.max(c[a+1][d],c[a][d+1]);const l=new Array(n).fill(-1);let u=0,r=0;for(;u<n&&r<s;)i[u]===o[r]?l[u++]=r++:c[u+1][r]>=c[u][r+1]?u++:r++;return l}function pe(e,t,n){for(let s=0;s<t.length;s++){if(n[s])continue;let i=s;for(;i+1<t.length&&!n[i+1];)i++;i+1<t.length?e.edits.push({start:t[s].start,end:t[i+1].start,text:""}):s>0?e.edits.push({start:t[s-1].end,end:t[i].end,text:""}):e.edits.push({start:t[s].start,end:t[i].end,text:""}),s=i}}function me(e,t,n,s){const i=e.format.eol;if(n!==void 0){e.edits.push({start:n,end:n,text:`,${i}${s.join(`,${i}`)}`});return}const o=t.end-1;if((t.kind==="object"?t.members.length:t.items.length)===0)e.edits.push({start:t.start+1,end:o,text:`${i}${s.join(`,${i}`)}${i}${J(e.text,t.start)}`});else{const l=t.kind==="object"?t.members[0].start:t.items[0].start;e.edits.push({start:l,end:l,text:`${s.join(`,${i}`).trimStart()}`})}}function he(e,t,n,s){const i=le(e);if(n!==void 0){e.edits.push({start:n,end:n,text:`${i}${s.join(i)}`});return}const o=t.kind==="object"&&!e.compact?" ":"";e.edits.push({start:t.start+1,end:t.end-1,text:`${o}${s.join(i)}${o}`})}function Qe(e){return e.replace(/~/g,"~0").replace(/\//g,"~1")}const K=e=>e.slice(e.lastIndexOf("/")+1),et=e=>e.charCodeAt(0)===65279?e.slice(1):e;function V(e){return{id:e.id,label:e.label,labelKey:e.labelKey,icon:e.icon,match:e.match,editor:e.editor,decode(t,n){return e.select(O(t[0].text).value,n)},encode(t,n,s){const i=n[0].text,o=O(i).value,c=e.assign(o,t,s);return{files:[{path:n[0].path,text:G(i,c,{arrayKey:e.arrayKey})}]}}}}const P=V({id:"json",label:"JSON",labelKey:"devStudio.kind.json",icon:"code",match:e=>e.toLowerCase().endsWith(".json"),editor:"json",select:e=>e,assign:(e,t)=>t}),D={id:"text",label:"Text",labelKey:"devStudio.kind.text",icon:"file",match:()=>!0,editor:"text",decode:e=>e[0].text,encode:(e,t)=>({files:[{path:t[0].path,text:ae(e,t[0].text)}]})};function ye(e,t){return e.find(n=>n.match(t))??(P.match(t)?P:D)}function tt(e,t,n){for(const s of[P,D])if(s.match(e.path))try{const i=s.decode([e],n);return{key:`${s.id}:${e.path}`,kind:s,paths:[e.path],label:K(e.path),model:i,error:t}}catch{}return{key:`text:${e.path}`,kind:D,paths:[e.path],label:K(e.path),model:e.text,error:t}}function nt(e,t,n,s){var l,u;const i=e.encode(t,n,s),o=new Map(n.map(r=>[r.path,r.text])),c=((l=i.files.find(r=>o.get(r.path)!==r.text))==null?void 0:l.path)??((u=i.deleted)==null?void 0:u.find(r=>o.has(r)));if(c!==void 0)throw new Error(`${K(c)} would not be stored as it is`)}function st(e,t,n){const s=new Map;for(const o of t){const c=ye(e,o.path),l=c.group?c.group(o.path):o.path,u=`${c.id}:${l}`,r=s.get(u)??{kind:c,group:l,files:[]};r.files.push(o),s.set(u,r)}const i=[];for(const[o,{kind:c,group:l,files:u}]of s){const r=u.map(d=>d.path).sort(),a=K(c.group?l:r[0]);try{const d=c.decode(u,n);nt(c,d,u,n),i.push({key:o,kind:c,paths:r,label:a,model:d})}catch(d){const f=d instanceof Error?d.message:String(d);for(const h of u)i.push(tt(h,f,n))}}return i.sort((o,c)=>o.label.localeCompare(c.label))}function it(e,t,n,s){const i=n.filter(u=>e.paths.includes(u.path)),o=e.kind.encode(t,i,s),c=new Map(n.map(u=>[u.path,u])),l=[];for(const u of o.files){const r=c.get(u.path);r&&r.text===u.text||l.push({type:"write",path:u.path,text:u.text,baseVersion:r==null?void 0:r.version})}for(const u of o.deleted??[]){const r=c.get(u);r&&l.push({type:"delete",path:u,baseVersion:r.version})}return l}function ge(e,t){try{return JSON.parse(et(e))}catch{return t}}const v=e=>typeof e=="object"&&e!==null&&!Array.isArray(e),S=(...e)=>t=>{const n=t.toLowerCase();return e.some(s=>n.endsWith(s.toLowerCase()))};function M(e){return V({id:e.id,label:e.label,labelKey:e.labelKey,icon:e.icon,editor:e.editor,match:e.match,select:t=>{if(Array.isArray(t))return t;const n=v(t)?t[e.property]:void 0;return Array.isArray(n)?n:[]},assign:(t,n)=>Array.isArray(t)?n:v(t)&&!(e.property in t)&&n.length===0?t:{...v(t)?t:{},[e.property]:n},arrayKey:e.itemKey?()=>e.itemKey:void 0})}function Z(e){const t=M(e);return{...t,decode:(n,s)=>t.decode(n,s).map((i,o)=>e.toItem(i,o)),encode:(n,s,i)=>t.encode(n.map(o=>e.fromItem(o)),s,i)}}function Q(e){return V({...e,select:t=>v(t)?t:{},assign:(t,n)=>n})}const rt=/^(.*)\.([a-z]{2,3}(?:-[A-Za-z]{2,4})?)\.i18n\.json$/i,ot=e=>{const t=rt.exec(e);return t?{group:t[1],locale:t[2]}:null},q=e=>v(e)&&Object.values(e).every(t=>typeof t=="string");function be(e){if(v(e)){for(const t of["translations","keys"])if(t in e){if(q(e[t]))return e[t];throw new Error(`"${t}" is not a flat map of texts`)}if(q(e))return e}throw new Error("no translations in this file")}function B(e,t){return v(e)?v(e.translations)?{...e,translations:t}:v(e.keys)?{...e,keys:t}:q(e)?t:{...e,translations:t}:{translations:t}}function we(e={}){const t=e.parse??ot,n=e.pathFor??((s,i)=>`${s}.${i}.i18n.json`);return{id:e.id??"i18n",label:e.label??"Translations",labelKey:e.labelKey??"devStudio.kind.i18n",icon:"globe",editor:"i18n",match:s=>t(s)!==null,group:s=>{var i;return((i=t(s))==null?void 0:i.group)??s},decode(s){const i={};for(const o of s){const c=t(o.path);c&&(i[c.locale]={...be(O(o.text).value)})}return i},encode(s,i){const o=new Map;let c="";for(const a of i){const d=t(a.path);d&&(o.set(d.locale,a),c=d.group)}const l=o.get("en")??i[0],u=[];for(const[a,d]of Object.entries(s)){const f=o.get(a);if(f){const g=O(f.text).value;u.push({path:f.path,text:G(f.text,B(g,d))});continue}const h=n(c||K((l==null?void 0:l.path)??"module"),a);if(l){const g=O(l.text).value,p=v(g)&&"locale"in g?{...g,locale:a}:g;u.push({path:h,text:k(B(p,d),C(l.text))})}else u.push({path:h,text:k({locale:a,translations:d})})}const r=[...o.entries()].filter(([a])=>!(a in s)).map(([,a])=>a.path);return{files:u,deleted:r}}}}const F=e=>JSON.parse(JSON.stringify(e));function at(e){const t=e.revisions!==!1;let n=0;const s=e.workspaces.map(r=>({meta:{id:r.id,label:r.label,description:r.description,icon:r.icon,readOnly:r.readOnly},packages:new Map((r.packages??[]).map(a=>[a.id,{...a,workspaceId:r.id}])),modules:new Map(r.modules.map(a=>[a.id,{...a,files:new Map(Object.entries(a.files).map(([d,f])=>[d,{text:f,version:++n}])),revisions:[]}]))}));let i=(e.templates??[]).map(r=>F(r));const o=r=>{const a=s.find(d=>d.meta.id===r);if(!a)throw new Error(`Unknown workspace "${r}"`);return a},c=r=>{const a=o(r.workspaceId).modules.get(r.id);if(!a)throw new Error(`Unknown module "${r.id}"`);return a},l=(r,a)=>({workspaceId:r,id:a.id,packageId:a.packageId,label:a.label??a.id,description:a.description,icon:a.icon,version:a.version,readOnly:a.readOnly||o(r).meta.readOnly,files:[...a.files.keys()].sort()}),u=(r,a)=>({path:r,text:a.text,version:String(a.version)});return{async listWorkspaces(){return s.map(r=>({...r.meta}))},async listModules(r){return[...o(r).modules.values()].map(d=>l(r,d))},async listPackages(r){const a=o(r),d=[...a.packages.values()],f=[...new Set([...a.modules.values()].map(h=>h.packageId).filter(Boolean))].filter(h=>!a.packages.has(h)).map(h=>({id:h,workspaceId:r,label:h,derived:!0}));return[...d,...f]},async readModule(r){return[...c(r).files.entries()].map(([d,f])=>u(d,f))},async writeModule(r,a){const d=c(r);if(d.readOnly||o(r.workspaceId).meta.readOnly)throw new Error(`Module "${r.id}" is read-only`);const f=a.filter(p=>p.baseVersion!==void 0).filter(p=>{const m=d.files.get(p.path);return m?String(m.version)!==p.baseVersion:!1}).map(p=>{var m;return{path:p.path,currentVersion:String((m=d.files.get(p.path))==null?void 0:m.version)}});if(f.length>0)return{ok:!1,conflicts:f};let h;if(t){const p={};for(const[m,w]of d.files)p[m]=w.text;h=`r${++n}`,d.revisions.unshift({id:h,timestamp:Date.now(),label:h,summary:a.map(m=>`${m.type} ${m.path}`).join(", "),files:p})}const g={};for(const p of a)if(p.type==="delete")d.files.delete(p.path);else{const m=++n;d.files.set(p.path,{text:p.text,version:m}),g[p.path]=String(m)}return{ok:!0,versions:g,revision:h}},async createModule(r){const a=o(r.workspaceId);if(a.meta.readOnly)throw new Error(`Workspace "${r.workspaceId}" is read-only`);if(a.modules.has(r.id))throw new Error(`Module "${r.id}" already exists`);const d={id:r.id,packageId:r.packageId,files:new Map(r.files.map(f=>[f.path,{text:f.text,version:++n}])),revisions:[]};return a.modules.set(r.id,d),l(r.workspaceId,d)},async deleteModule(r){const a=o(r.workspaceId);if(a.meta.readOnly)throw new Error(`Workspace "${r.workspaceId}" is read-only`);a.modules.delete(r.id)},async savePackage(r){return o(r.workspaceId).packages.set(r.id,{...r,derived:!1}),{...r,derived:!1}},async deletePackage(r){o(r.workspaceId).packages.delete(r.id)},async listTemplates(){return i.map(r=>F(r))},async saveTemplate(r,a){const d=(a==null?void 0:a.previousId)??r.id,f=F(r),h=i.findIndex(g=>g.id===d);return i=h>=0?i.map((g,p)=>p===h?f:g):[...i,f],F(f)},async deleteTemplate(r){i=i.filter(a=>a.id!==r)},async listRevisions(r,a){return c(r).revisions.filter(d=>!a||a in d.files).map(({files:d,...f})=>({...f,...a?{path:a}:{}}))},async readRevision(r,a,d){const f=c(r).revisions.find(h=>h.id===a);if(!f)throw new Error(`Unknown revision "${a}"`);return d?f.files[d]??"":JSON.stringify(f.files,null,2)},async rollback(r,a,d){const f=c(r),h=f.revisions.find(p=>p.id===a);if(!h)throw new Error(`Unknown revision "${a}"`);const g=d?{[d]:h.files[d]}:h.files;if(!d)for(const p of[...f.files.keys()])p in g||f.files.delete(p);for(const[p,m]of Object.entries(g))m!==void 0&&f.files.set(p,{text:m,version:++n})},snapshot(){return{workspaces:s.map(r=>({...r.meta,packages:[...r.packages.values()].map(({workspaceId:a,...d})=>d),modules:[...r.modules.values()].map(a=>({id:a.id,packageId:a.packageId,label:a.label,description:a.description,icon:a.icon,version:a.version,readOnly:a.readOnly,files:Object.fromEntries([...a.files.entries()].map(([d,f])=>[d,f.text]))}))})),templates:i.map(r=>F(r)),revisions:t}}}}function ct(e){return e}function R(e,t){if(!t||e===void 0||e===null)return!0;if(t.enum&&!t.enum.includes(e))return!1;switch(t.type){case"string":return typeof e=="string";case"number":return typeof e=="number";case"integer":return Number.isInteger(e);case"boolean":return typeof e=="boolean";case"array":return Array.isArray(e)&&(!t.items||e.every(n=>R(n,t.items)));case"object":{if(typeof e!="object"||Array.isArray(e))return!1;const n=t.properties;return!n||Object.entries(e).every(([s,i])=>s in n&&R(i,n[s]))}default:return!0}}function lt(e,t){var c;const n=(e.fields??[]).map(l=>l.name),s=(c=e.schema)==null?void 0:c.properties;if(!e.schema||!s)return{section:e,keys:n};const i=Object.entries(s).filter(([l,u])=>!(l in t)||R(t[l],u)),o=i.map(([l])=>l);return{section:{...e,schema:{...e.schema,properties:Object.fromEntries(i),...e.schema.required?{required:e.schema.required.filter(l=>o.includes(l))}:{}}},keys:[...o,...n]}}function dt(e){var n;const t=new Set;for(const s of e){for(const i of Object.keys(((n=s.schema)==null?void 0:n.properties)??{}))t.add(i);for(const i of s.fields??[])t.add(i.name)}return t}function ft(e){return e.map(t=>{const n=t;return{name:String(n.tableName||n.name||"Entity"),columns:(Array.isArray(n.fields)?n.fields:[]).map(s=>({name:String(s.name??""),dataType:String(s.dataType??s.type??"string"),isPrimaryKey:!!s.isPrimaryKey,isForeignKey:!!(s.isForeignKey??s.foreignKey)}))}})}function ut(e){const t=e.manifest??{},n=String(t.displayName||t.packageName||"Module"),s=(e.views??[]).map(o=>({id:`view:${o.id}`,label:o.name,type:"view"})),i=(e.entities??[]).map(o=>{const c=String(o.name??"Entity");return{id:`entity:${c}`,label:c,type:"entity"}});return{roles:[{id:"admin",label:"Admin"},{id:"user",label:"User"}],actions:[{id:"view",label:"View"},{id:"create",label:"Create"},{id:"edit",label:"Edit"},{id:"delete",label:"Delete"}],resources:[{id:"module",label:n,type:"module",children:[...s.length?[{id:"views",label:"Views",type:"group",children:s}]:[],...i.length?[{id:"entities",label:"Entities",type:"group",children:i}]:[]]}],grants:{}}}const U=Q({id:"manifest",label:"Manifest",labelKey:"devStudio.kind.manifest",icon:"file",editor:"manifest",match:S(".manifest.json")}),ke=M({id:"entities",label:"Entities",labelKey:"devStudio.kind.entities",icon:"database",editor:"entities",match:S(".entities.json"),property:"entities",itemKey:"name"}),ve=we();function Se(e,t){const n=e,s=typeof e=="object"&&e!==null&&typeof n.id=="string";return{key:s?n.id:`#${t}`,label:s&&n.name||(s?n.id:`#${t+1}`),...s?{definition:n}:{rawReason:"no id"},source:e}}const $e=Z({id:"views",label:"Views",labelKey:"devStudio.kind.views",icon:"grid",editor:"views",match:S(".views.json"),property:"views",itemKey:"id",toItem:(e,t)=>Se(e,t),fromItem:e=>e.definition??e.source}),je=Z({id:"workflows",label:"Workflows",labelKey:"devStudio.kind.workflows",icon:"git-branch",editor:"workflows",match:S(".workflows.json"),property:"workflows",itemKey:"id",toItem:(e,t)=>Se(e,t),fromItem:e=>e.definition??e.source}),Ke=M({id:"dataSources",label:"Data sources",labelKey:"devStudio.kind.dataSources",icon:"database",editor:"dataSources",match:S(".datasources.json"),property:"dataSources",itemKey:"key"}),Oe=Q({id:"rbac",label:"Access",labelKey:"devStudio.kind.rbac",icon:"shield",editor:"rbac",match:S(".rbac.json")}),Ee=M({id:"hooks",label:"Lifecycle hooks",labelKey:"devStudio.kind.hooks",icon:"zap",editor:"hooks",match:S(".hooks.json"),property:"bindings",itemKey:"id"}),Ae=[U,ke,ve,$e,je,Ke,Oe,Ee];function X(e){return e.normalize("NFKD").replace(/[̀-ͯ]/g,"").replace(/ł/g,"l").replace(/Ł/g,"L").toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"")||"module"}const te=e=>{const t=e.find(n=>U.match(n.path));return t?ge(t.text,void 0):void 0};function Ne(e){const t=e.find(n=>U.match(n.path));return t?K(t.path).replace(/\.manifest\.json$/i,""):"module"}const ne=e=>Array.isArray(e.fields)?e.fields:[],pt={id:"native",kinds:Ae,locales:["en","pl","de","fr","es","uk"],requiredLocales:["en"],moduleId:e=>{const t=te(e),n=(t==null?void 0:t.id)??(t==null?void 0:t.packageName);return typeof n=="string"?n:void 0},validateModule:({files:e})=>{const t=te(e);return t?["id","name","version"].filter(n=>typeof t[n]!="string"||!t[n]).map(n=>({severity:"error",code:"manifest.required",message:`The manifest needs "${n}".`,messageKey:"devStudio.issue.manifestRequired",params:{field:n},pointer:`/${n}`})):[{severity:"error",code:"manifest.missing",message:"The module has no manifest.",messageKey:"devStudio.issue.manifestMissing"}]},newFile:(e,{files:t})=>{const n=Ne(t),i={entities:["entities.json",{entities:[]}],views:["views.json",{views:[]}],workflows:["workflows.json",{workflows:[]}],dataSources:["datasources.json",{dataSources:[]}],rbac:["rbac.json",{roles:[],actions:[],resources:[],grants:{}}],hooks:["hooks.json",{bindings:[]}]}[e];return i?{path:`${n}.${i[0]}`,text:k(i[1])}:void 0},generateModule:async(e,{existingIds:t})=>{let n=X(e.name);for(let i=2;t.has(n);i++)n=`${X(e.name)}-${i}`;const s=[{path:`${n}.manifest.json`,text:k({id:n,name:e.name,version:"1.0.0",...e.description?{description:e.description}:{},...e.icon?{icon:e.icon}:{},...e.packageId?{category:e.packageId}:{}})},{path:`${n}.entities.json`,text:k({entities:e.entities})}];for(const i of e.locales){const o={"module.displayName":e.name};for(const c of e.entities){const l=String(c.name??"");o[`entity.${l}.displayName`]=l;for(const u of ne(c))o[`field.${l}.${String(u.name)}.label`]=String(u.name)}s.push({path:`${n}.${i}.i18n.json`,text:k({locale:i,translations:o})})}if(e.views){const i=e.entities.map(o=>{const c=String(o.name??"Item");return{id:`${c}List`,name:`${c} list`,kind:"grid",version:2,columns:12,dataSources:[{key:"rows",type:"entity",entity:c,autoLoad:!0}],rows:[{id:"r1",cells:[{id:"grid",controlType:"dataGrid",colSpan:12,props:{columns:ne(o).map(l=>({field:String(l.name),header:String(l.name)}))},bindings:{data:{source:"rows",field:""}}}]}]}});s.push({path:`${n}.views.json`,text:k({views:i})})}if(e.permissions){const i={roles:[{id:"viewer",label:"Viewer"},{id:"editor",label:"Editor"},{id:"admin",label:"Admin"}],actions:[{id:"view",label:"View"},{id:"edit",label:"Edit"},{id:"delete",label:"Delete"}],resources:e.entities.map(o=>({id:`entity:${String(o.name)}`,label:String(o.name),type:"entity"})),grants:{}};s.push({path:`${n}.rbac.json`,text:k(i)})}return{id:n,packageId:e.packageId,files:s}}};exports.addStudioFolder=Ce;exports.addStudioSection=Re;exports.arrayFileKind=M;exports.buildDocuments=st;exports.createMemoryStudioProvider=at;exports.defineManifestSection=ct;exports.deriveDefaultRbac=ut;exports.detectJsonTextFormat=C;exports.emptyStudioLayout=T;exports.encodeDocument=it;exports.endsWithAny=S;exports.entitiesToSchemas=ft;exports.fileName=K;exports.fitManifestSection=lt;exports.i18nFileKind=we;exports.isEmptyStudioLayout=Je;exports.isStudioLayoutPath=se;exports.itemsFileKind=Z;exports.jsonFallbackKind=P;exports.jsonFileKind=V;exports.jsonValueFitsSchema=R;exports.jsonValuesEqual=x;exports.keepTextFormat=ae;exports.manifestSectionKeys=dt;exports.modulePrefix=Ne;exports.nativeDataSourcesKind=Ke;exports.nativeEntitiesKind=ke;exports.nativeFileKinds=Ae;exports.nativeHooksKind=Ee;exports.nativeI18nKind=ve;exports.nativeManifestKind=U;exports.nativeRbacKind=Oe;exports.nativeStudioPreset=pt;exports.nativeViewsKind=$e;exports.nativeWorkflowsKind=je;exports.objectFileKind=Q;exports.parseJsonText=O;exports.parseStudioLayout=Le;exports.patchJsonText=G;exports.patchJsonTextDetailed=ce;exports.placeStudioEntry=_e;exports.readTranslations=be;exports.removeStudioLayoutNode=Ue;exports.renameStudioEntryRef=ze;exports.renameStudioLayoutNode=Ve;exports.resolveFileKind=ye;exports.safeJson=ge;exports.serializeStudioLayout=Pe;exports.slugifyModuleId=X;exports.stringifyJsonText=k;exports.studioEntryRef=Ie;exports.studioLayoutPath=Te;exports.textFallbackKind=D;exports.writeTranslations=B;
package/dist/studio.d.ts CHANGED
@@ -7,6 +7,18 @@ import { NiceRbacModel } from '@nice2dev/ui';
7
7
  import { NiceViewDefinition } from '@nice2dev/ui';
8
8
  import { NiceWorkflowDefinition } from '@nice2dev/ui';
9
9
 
10
+ /** The layout with a new folder in `group` (inside `parent` / `section`); returns its id too. */
11
+ export declare function addStudioFolder(layout: NiceStudioLayout, folder: Omit<NiceStudioLayoutFolder, 'id'>): {
12
+ layout: NiceStudioLayout;
13
+ id: string;
14
+ };
15
+
16
+ /** The layout with a new section; returns the layout and the section's id. */
17
+ export declare function addStudioSection(layout: NiceStudioLayout, label: string): {
18
+ layout: NiceStudioLayout;
19
+ id: string;
20
+ };
21
+
10
22
  /** A file holding one array, either bare or under `property`; the rest of the file is kept. */
11
23
  export declare function arrayFileKind<T>(o: NiceArrayFileKindOptions): NiceStudioFileKind<T[]>;
12
24
 
@@ -40,6 +52,9 @@ export declare function deriveDefaultRbac(module: {
40
52
  /** Reads how `text` is written: BOM, line breaks, indentation, final newline, colon spacing. */
41
53
  export declare function detectJsonTextFormat(text: string): NiceJsonTextFormat;
42
54
 
55
+ /** An empty layout: no sections, no folders — the flat tree. */
56
+ export declare const emptyStudioLayout: () => NiceStudioLayout;
57
+
43
58
  /**
44
59
  * The file changes that store a document's new model: only files whose text differs from what
45
60
  * was read, plus files the encoder adds or removes.
@@ -137,6 +152,12 @@ declare interface FormFieldValidation {
137
152
  */
138
153
  export declare function i18nFileKind(o?: NiceI18nFileKindOptions): NiceStudioFileKind<NiceStudioTranslations>;
139
154
 
155
+ /** Whether a layout holds nothing (its file can go). */
156
+ export declare const isEmptyStudioLayout: (layout: NiceStudioLayout) => boolean;
157
+
158
+ /** Whether a path is a module's layout file. */
159
+ export declare const isStudioLayoutPath: (path: string) => boolean;
160
+
140
161
  /**
141
162
  * A file holding a list of entries edited one at a time (views, workflows). Entries the editor
142
163
  * does not understand stay raw and round-trip as they are.
@@ -381,6 +402,9 @@ export declare interface NiceObjectFileKindOptions {
381
402
  match(path: string): boolean;
382
403
  }
383
404
 
405
+ /** The studio's own editors. */
406
+ export declare type NiceStudioBuiltinEditorId = 'manifest' | 'entities' | 'i18n' | 'views' | 'workflows' | 'permissions' | 'rbac' | 'dataSources' | 'seeds' | 'hooks' | 'script' | 'json' | 'text';
407
+
384
408
  /** What a file kind's decode and encode know about the module. */
385
409
  export declare interface NiceStudioCodecContext {
386
410
  moduleId: string;
@@ -402,8 +426,11 @@ export declare interface NiceStudioDocument<M = unknown> {
402
426
  error?: string;
403
427
  }
404
428
 
405
- /** The built-in editors a file kind can open in. */
406
- export declare type NiceStudioEditorId = 'manifest' | 'entities' | 'i18n' | 'views' | 'workflows' | 'permissions' | 'rbac' | 'dataSources' | 'seeds' | 'hooks' | 'script' | 'json' | 'text';
429
+ /**
430
+ * The editors a file kind can open in: a built-in one, or the id of an editor the host registers
431
+ * (1.4.5 — the union was closed; an unknown id opens as raw JSON / text until one is registered).
432
+ */
433
+ export declare type NiceStudioEditorId = NiceStudioBuiltinEditorId | (string & {});
407
434
 
408
435
  /** New and removed files of an encoded document. */
409
436
  export declare interface NiceStudioEncoded {
@@ -463,6 +490,11 @@ export declare interface NiceStudioFileKind<M = unknown> {
463
490
  /** The document a file belongs to (files with the same group open together). Default: the path. */
464
491
  group?(path: string): string;
465
492
  editor: NiceStudioEditorId;
493
+ /**
494
+ * The tree group its documents are listed under (1.4.5): one of the preset's `groups`, or a
495
+ * built-in group id. Default: the built-in group of its editor (none for raw JSON / text).
496
+ */
497
+ treeGroup?: string;
466
498
  /** The files of one document → the editor's model. Throwing opens the files as raw JSON / text. */
467
499
  decode(files: readonly NiceStudioFile[], ctx: NiceStudioCodecContext): M;
468
500
  /** The model → the document's files (only their text; unchanged files may be returned as they were). */
@@ -479,6 +511,20 @@ export declare interface NiceStudioGeneratedModule {
479
511
  }>;
480
512
  }
481
513
 
514
+ /**
515
+ * A group of the tree a preset adds (1.4.5): its documents — of the kinds whose `treeGroup` names
516
+ * it — are listed one per row under it, like scripts.
517
+ */
518
+ export declare interface NiceStudioGroupDef {
519
+ id: string;
520
+ label: string;
521
+ labelKey?: string;
522
+ /** NiceIcon name. */
523
+ icon?: string;
524
+ /** Where it goes among the groups (the built-in ones are 10, 20, … 100). Default: after them. */
525
+ order?: number;
526
+ }
527
+
482
528
  /** A problem found in a module. */
483
529
  export declare interface NiceStudioIssue {
484
530
  severity: 'error' | 'warning' | 'info';
@@ -512,6 +558,40 @@ export declare interface NiceStudioItem<D> {
512
558
  rawReason?: string;
513
559
  }
514
560
 
561
+ /** The layout of a module — the content of its `{prefix}.studio.json`. */
562
+ export declare interface NiceStudioLayout {
563
+ version: 1;
564
+ sections: NiceStudioLayoutSection[];
565
+ folders: NiceStudioLayoutFolder[];
566
+ /** By entry ref, `group:key` — `entities:Customer`, `views:customer-list`. */
567
+ placement: Record<string, NiceStudioLayoutPlacement>;
568
+ }
569
+
570
+ /** A folder inside one group of a module (entities, views…), optionally nested and in a section. */
571
+ export declare interface NiceStudioLayoutFolder {
572
+ id: string;
573
+ label: string;
574
+ /** The group it belongs to: `entities`, `views`, `workflows`, a preset's own group… */
575
+ group: string;
576
+ /** The folder it sits in. */
577
+ parent?: string;
578
+ /** The section it sits in (absent: the module's own groups). */
579
+ section?: string;
580
+ }
581
+
582
+ /** Where one entry sits: a section, a folder, an order among its siblings. */
583
+ export declare interface NiceStudioLayoutPlacement {
584
+ section?: string;
585
+ folder?: string;
586
+ order?: number;
587
+ }
588
+
589
+ /** A section of a module: a band of the tree that holds groups (Sales, Warehouse…). */
590
+ export declare interface NiceStudioLayoutSection {
591
+ id: string;
592
+ label: string;
593
+ }
594
+
515
595
  /** What validators and generators get. */
516
596
  export declare interface NiceStudioModuleContext {
517
597
  key: NiceStudioModuleKey;
@@ -579,6 +659,11 @@ export declare interface NiceStudioPackage {
579
659
  /** Computed from the modules (e.g. their `category`) rather than stored: it cannot be edited. */
580
660
  derived?: boolean;
581
661
  readOnly?: boolean;
662
+ /**
663
+ * The package it sits in (1.4.5): packages nest in the tree. An id with `/` (`Finance/Banking`, an
664
+ * OmniVerk category path) nests under the part before its last `/` without it.
665
+ */
666
+ parentId?: string;
582
667
  }
583
668
 
584
669
  /** The model of the `permissions` editor: permission codes and the groups (roles) granting them. */
@@ -604,6 +689,8 @@ export declare interface NiceStudioPreset {
604
689
  id: string;
605
690
  /** Tried in order; a path no kind matches opens as raw JSON (`*.json`) or text. */
606
691
  kinds: NiceStudioFileKind[];
692
+ /** Groups of the tree the preset adds to the built-in ones (1.4.5). */
693
+ groups?: NiceStudioGroupDef[];
607
694
  /** The manifest's sections, each a form over part of the manifest. */
608
695
  manifestSections?: NiceManifestSection[];
609
696
  entities?: NiceStudioEntityOptions;
@@ -767,6 +854,12 @@ export declare function parseJsonText(text: string): {
767
854
  format: NiceJsonTextFormat;
768
855
  };
769
856
 
857
+ /**
858
+ * A layout from its file's text — what it can read of it: unknown fields and broken entries are
859
+ * dropped, a text that does not parse gives the empty layout.
860
+ */
861
+ export declare function parseStudioLayout(text: string | undefined): NiceStudioLayout;
862
+
770
863
  /**
771
864
  * `previous` with its content replaced by `next`, changing as few bytes as possible. Falls back
772
865
  * to {@link stringifyJsonText} in the file's own format when the text cannot be patched (invalid
@@ -777,9 +870,36 @@ export declare function patchJsonText(previous: string, next: unknown, options?:
777
870
  /** {@link patchJsonText}, also telling whether the patch was exact. */
778
871
  export declare function patchJsonTextDetailed(previous: string, next: unknown, options?: NiceJsonPatchOptions): NiceJsonPatchResult;
779
872
 
873
+ /**
874
+ * The layout with an entry put somewhere: into a folder (its section follows the folder's), into a
875
+ * section (out of any folder), or back to its group (`{}`).
876
+ */
877
+ export declare function placeStudioEntry(layout: NiceStudioLayout, ref: string, target: {
878
+ folder?: string;
879
+ section?: string;
880
+ }): NiceStudioLayout;
881
+
780
882
  /** The translations inside a file: `translations`, `keys`, or the whole file when it is a flat map. */
781
883
  export declare function readTranslations(root: unknown): Record<string, string>;
782
884
 
885
+ /**
886
+ * The layout without a section or folder. What it held moves up: a folder's entries and folders go
887
+ * to its parent (or the group), a section's folders and entries back to the module's own groups.
888
+ */
889
+ export declare function removeStudioLayoutNode(layout: NiceStudioLayout, node: {
890
+ kind: 'section' | 'folder';
891
+ id: string;
892
+ }): NiceStudioLayout;
893
+
894
+ /** The layout after an entry was renamed — its placement follows it (`entities:Old` → `entities:New`). */
895
+ export declare function renameStudioEntryRef(layout: NiceStudioLayout, from: string, to: string): NiceStudioLayout;
896
+
897
+ /** The layout with a section or folder renamed. */
898
+ export declare function renameStudioLayoutNode(layout: NiceStudioLayout, node: {
899
+ kind: 'section' | 'folder';
900
+ id: string;
901
+ }, label: string): NiceStudioLayout;
902
+
783
903
  /** The kind a path opens with: the first that matches, else JSON or text. */
784
904
  export declare function resolveFileKind(kinds: readonly NiceStudioFileKind[], path: string): NiceStudioFileKind;
785
905
 
@@ -790,12 +910,24 @@ declare type Row_2 = Record<string, unknown>;
790
910
  /** Parses JSON without a BOM and returns `fallback` when the text is not JSON. */
791
911
  export declare function safeJson<T = unknown>(text: string, fallback: T): T;
792
912
 
913
+ /** A layout's file text: two-space JSON with a final newline, in the line ending of `previous`. */
914
+ export declare function serializeStudioLayout(layout: NiceStudioLayout, previous?: string): string;
915
+
793
916
  /** A file-name-safe id out of a display name: "Bike rental" → `bike-rental`. */
794
917
  export declare function slugifyModuleId(name: string): string;
795
918
 
796
919
  /** Writes `value` in a given format (defaults: two spaces, LF, final newline, no BOM). */
797
920
  export declare function stringifyJsonText(value: unknown, format?: Partial<NiceJsonTextFormat>): string;
798
921
 
922
+ /** The ref of an entry in a layout: `group:key`. */
923
+ export declare const studioEntryRef: (group: string, key: string) => string;
924
+
925
+ /**
926
+ * The path of a module's layout file: the one it has, else `{prefix}.studio.json` after the prefix
927
+ * of its files, else `module.studio.json`.
928
+ */
929
+ export declare function studioLayoutPath(files: readonly NiceStudioFile[]): string;
930
+
799
931
  /** Any other file, edited as text. */
800
932
  export declare const textFallbackKind: NiceStudioFileKind<string>;
801
933