@jawache/flow 0.1.1 → 0.1.2
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/flow.mjs +57 -57
- package/dist/index.mjs +15 -15
- package/dist/packs.mjs +45 -45
- package/dist/types/checks/domain.d.ts +40 -2
- package/dist/types/glob.d.ts +17 -0
- package/dist/types/index.d.ts +2 -2
- package/dist/types/language/domain.d.ts +19 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
|
-
function y(
|
|
2
|
-
`)}function
|
|
3
|
-
`),r=[];for(let o of
|
|
4
|
-
`),
|
|
5
|
-
`]),
|
|
1
|
+
function y(e){return e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}function D(e){return e.startsWith("^")||e.includes("(?")||e.includes("|")||e.endsWith("$")}function O(e){let n=[],t="",r=()=>{t!==""&&n.push({kind:"literal",text:t}),t=""};for(let o=0;o<e.length;o++){let s=e[o];if(s==="*")r(),e[o+1]==="*"?(n.push({kind:"globstar"}),o++,e[o+1]==="/"&&o++):n.push({kind:"star"});else if(s==="?")r(),n.push({kind:"single"});else if(s==="{"){let a=e.indexOf("}",o);if(a===-1){t+=s;continue}r(),n.push({kind:"options",options:e.slice(o+1,a).split(",")}),o=a}else t+=s??""}return r(),n}function v(e){switch(e.kind){case"literal":return y(e.text);case"star":return"[^/]*";case"globstar":return".*";case"single":return"[^/]";case"options":return`(${e.options.map(y).join("|")})`}}function ie(e){return new RegExp(`^${O(e).map(v).join("")}$`)}function ae(e,n){return ie(n).test(e)}function g(e,n){return(n||[]).some(t=>ae(e,t))}function de(e){let n=e.includes("/")?e.slice(0,e.lastIndexOf("/")):".",t=e.slice(e.lastIndexOf("/")+1),r=t.lastIndexOf("."),o=r>0?t.slice(0,r):t,s=n==="."?o:`${n}/${o}`;return{dir:n,base:t,name:o,path:s}}function A(e,n){let t=de(n);return e.replace(/\{(dir|base|name|path)\}/g,(r,o)=>t[o])}var L={write:["edit"],command:["edit","commit"],commit:["commit"],delete:["delete"],"turn-end":["turn"]},le=Object.keys(L),ce=["session","touch","command","turn-end"],ue="write",fe="command",pe="commit",ge="delete",ye="turn-end",me="session",he="touch";function ke(e){let n=[];for(let t of e)for(let r of L[t])n.includes(r)||n.push(r);return n}function be(e){return le.includes(e)}function xe(e){return ce.includes(e)}var M=["write","delete","commit","touch"];function we(e){return M.includes(e)}var F=[...M,"command"];function Se(e,n){return e==="breadcrumb"?F.includes(n):we(n)}var I=Symbol.for("flow.category");function Re(e,n){return{[I]:!0,name:e,classify:n}}function h(e,n){if(!(typeof e!="object"||e===null))return e[n]}function W(e){return h(e,I)===!0}var K=Symbol.for("flow.settings"),_=Symbol.for("flow.faults");function P(e,n){return n.length>0&&Object.defineProperty(e,_,{value:n,enumerable:!1,configurable:!0}),e}function q(e){if(e===void 0)return[];let n=e[_];return Array.isArray(n)?n:[]}function f(e){return n=>{let t=e(n);return Object.defineProperty(t,K,{value:n,enumerable:!1,configurable:!0}),t}}function Ce(e){return e===void 0?void 0:e[K]}function Ee(e){return e?(e.pass?.length??0)+(e.block?.length??0)>0:!1}var $e=["at","for","on","ignore","check","message","disabled","test","description"],Oe=["at","for","on","ignore","text","file","disabled","description"];function x(e,n){let t=r=>x({...e,...r},n);return{...n(e),at:(...r)=>t({at:r}),for:(...r)=>t({for:r}),on:(...r)=>t({on:r}),ignore:(...r)=>t({ignore:r}),check:r=>t({check:r}),message:r=>t({message:r}),text:r=>t({text:r}),file:r=>t({file:r}),disabled:r=>t({disabled:r===void 0?{}:{reason:r}}),test:r=>t({test:r}),description:r=>t({description:r})}}var U=e=>({spec:e});function ve(){return x({kind:"guardrail"},U)}function Ae(){return x({kind:"breadcrumb"},U)}function Me(e){let n=h(h(e,"spec"),"kind");return n==="guardrail"||n==="breadcrumb"}var V=Symbol.for("flow.pack"),H=Symbol.for("flow.ref");function Pe(e,n){let t=typeof n=="function"&&n.length>0;return J(e,[],{name:e,build:o=>typeof n=="function"?n(o):n,takesParams:t})}function J(e,n,t){let r={[H]:{pack:e,id:n.join(".")}};return t&&(r[V]=t),new Proxy(r,{get(o,s){return s in o?o[s]:typeof s=="string"?J(e,[...n,s]):void 0}})}function Be(e){let n=h(e,V);return Ge(n)?n:void 0}function Ge(e){return typeof e=="object"&&e!==null&&typeof e.name=="string"&&typeof e.build=="function"}function Te(e){let n=h(e,H),t=h(n,"pack"),r=h(n,"id");return typeof t=="string"&&typeof r=="string"?{pack:t,id:r}:void 0}function je(e,...n){return{kind:"pack",pack:Be(e),params:n[0],hasParams:n.length>0}}function De(e){let n=Te(e)??{pack:"",id:""};return x({},t=>({binding:{kind:"override",ref:n,spoken:t}}))}function Ne(e,n={}){return{bindings:e.map(t=>"binding"in t?t.binding:t),settings:n}}function N(e,n,t){let r={};for(let o of Object.keys(e))r[o]=t?.[o]??"pack";for(let o of Object.keys(n))r[o]="override";return{spec:{...e,...n},source:r}}var Le=["not-a-pack","missing-parameter","unknown-entry","unknown-key","unknown-moment","missing-mandatory","undeclared-category","no-cases","duplicate-id","dead-scope","bad-check-options"];function w(e){return[`flow: the config will not load \u2014 ${e.length} refusal${e.length===1?"":"s"}.`,...e.map(n=>` ${n.code}: ${n.detail}`)].join(`
|
|
2
|
+
`)}function Fe(e){let n=[],t=[],r=new Map;for(let o of e.bindings){if(o.kind!=="pack")continue;if(!o.pack||o.pack.name===""){n.push({code:"not-a-pack",entry:"",detail:"A `pack(\u2026)` line was given a value that no `definePack` ever made. Import the pack's default export, not one of its entries."});continue}let{name:s,build:a,takesParams:i}=o.pack;if(i&&!o.hasParams){n.push({code:"missing-parameter",entry:s,detail:`The pack \`${s}\` declares parameters and was bound without any \u2014 write \`pack(${s}, { \u2026 })\`. Which fields it needs is stated by its factory's type.`});continue}for(let{key:d,spec:c}of Y(a(o.params))){let l={id:`${s}.${d}`,pack:s,key:d,...N(c,{})};if(r.get(l.id)){n.push({code:"duplicate-id",entry:l.id,detail:`Two entries claim the id \`${l.id}\`. An id is its property name inside its pack, so this is one pack bound twice, or two packs sharing a name.`});continue}r.set(l.id,l),t.push(l)}}for(let o of e.bindings){if(o.kind!=="override")continue;let s=`${o.ref.pack}.${o.ref.id}`,a=r.get(s);if(!a){n.push({code:"unknown-entry",entry:s,detail:`\`override(${s})\` names an entry no bound pack has. Bind the pack it lives in, or correct the reference.`});continue}let i=N(a.spec,o.spoken,a.source);a.spec=i.spec,a.source=i.source}for(let o of t)n.push(...Ie(o));return n.length>0?{ok:!1,refusals:n}:{ok:!0,entries:t.map(o=>({id:o.id,pack:o.pack,key:o.key,spec:o.spec,source:o.source,categories:(o.spec.for??[]).map(s=>s.name),phases:o.spec.kind==="guardrail"?ke(o.spec.at??[]):[],settings:o.spec.kind==="guardrail"?Ce(o.spec.check):void 0}))}}function Y(e,n=[]){let t=[];for(let[r,o]of Object.entries(e))Me(o)?t.push({key:[...n,r].join("."),spec:o.spec}):typeof o=="object"&&o!==null&&t.push(...Y(o,[...n,r]));return t}function Ie(e){let{id:n,spec:t}=e,r=[],o=(u,se)=>r.push({code:u,entry:n,detail:se}),s=t.kind==="guardrail"?$e:Oe,a=Object.keys(t).filter(u=>u!=="kind"&&!s.includes(u));a.length>0&&o("unknown-key",`\`${n}\` carries ${a.map(u=>`\`${u}\``).join(", ")}, which the ${t.kind} grammar does not have. It is closed: ${s.join(" \xB7 ")}.`);let i=t.at??[],d=t.kind==="guardrail"?be:xe,c=i.filter(u=>!d(u));if(c.length>0&&o("unknown-moment",`\`${n}\` fires at ${c.map(u=>`\`${u}\``).join(", ")}, which is not a moment a ${t.kind} has a rail for.`),(t.for??[]).some(u=>!W(u))&&o("undeclared-category",`\`${n}\` is scoped with \`.for(\u2026)\` to something \`defineCategory\` never made. A category is a value with its recognizer aboard \u2014 import the one you mean.`),t.disabled)return r;let p=[];i.length===0&&p.push(".at(\u2026)"),t.kind==="guardrail"?(t.check||p.push(".check(\u2026)"),t.message===void 0&&p.push(".message(\u2026)")):t.text===void 0&&t.file===void 0&&p.push(".text(\u2026) or .file(\u2026)"),p.length>0&&o("missing-mandatory",`\`${n}\` never said ${p.join(" and ")}. Nothing in this grammar defaults \u2014 an absent key is absent, not a fallback.`),((t.on?.length??0)>0||(t.ignore?.length??0)>0)&&i.length>0&&!i.some(u=>Se(t.kind,u))&&o("dead-scope",`\`${n}\` narrows by path but fires only at ${i.map(u=>`\`${u}\``).join(", ")}, which name no subject to narrow \u2014 its \`on\`/\`ignore\` would be read by nothing. Drop the scope, or add a moment that carries one (${(t.kind==="breadcrumb"?F:M).join(" \xB7 ")}).`),t.kind==="guardrail"&&!Ee(t.test)&&o("no-cases",`\`${n}\` carries no cases. A rule declares what must pass it and what it must block (\`.test({ pass, block })\`) \u2014 a fence whose block-case was never written is a fence nothing proves is alive.`);for(let u of q(t.kind==="guardrail"?t.check:void 0))o("bad-check-options",`\`${n}\` ${u}`);return r}function m(e,n,t=" \xB7 "){return n.length===0?e.ok():e.fail(n.join(t))}function k(e){return e.file??{path:"",content:""}}function qe(e,n){let t=e.split(`
|
|
3
|
+
`),r=[];for(let o of n){let s=new RegExp(o);t.forEach((a,i)=>{s.test(a)&&r.push({pattern:o,line:i+1})})}return r}var Ue=f(e=>n=>{let t=qe(k(n).content,e.ban);return m(n,t.map(r=>`line ${r.line}: matches /${r.pattern}/`))}),Ve=f(e=>n=>{let t=n.command??"",r=e.ban.filter(o=>new RegExp(o).test(t));return m(n,r.map(o=>`matches banned /${o}/`))});function He(e){return`(?:${e.join("|")})[^"\`]*(?:"(?:(?!<<-?')[^"])*"[^"\`]*)*"(?:(?!<<-?')[^"])*\``}var Je=["You are recording prose through a shell command, and a backtick inside a DOUBLE-quoted argument is not Markdown \u2014 the shell RUNS it and splices its output into your text before the command ever sees it.","On an append-only record there is no undo: no amend, no redact. And once the binary has argv the splice has already happened, so this is the only moment it can be caught.","Fix: SINGLE-quote the argument (backticks are literal there), or feed the prose on stdin with a QUOTED heredoc \u2014 `git commit -F -` plus `<<'EOF'`, which this rule treats as safe.","ALREADY single-quoted and still blocked? Then your PROSE carries an unbalanced double quote before the backtick, and the matcher cannot tell that quote from a real open argument. Nothing would splice \u2014 this one is the rule's cost, not your mistake. Balance the quote, drop it, or use the heredoc; do not go back to double quotes to make it pass."].join(`
|
|
4
|
+
`),Ye=f(e=>async n=>{let{path:t}=k(n);return e.existingOnly===!0?n.moment!=="delete"&&!await n.fs.exists(t)?n.ok():n.fail(`'${t}' is append-only \u2014 an existing file here is history and may not be edited or deleted (adding a new one is fine)`):n.fail(`'${t}' is a protected path (do not edit directly)`)}),ze=f(e=>async n=>{let t=A(e.sibling,k(n).path);return await n.fs.exists(t)?n.ok():n.fail(`required sibling missing: ${t}`)}),Qe=/\.(ts|tsx|mts|cts|js|mjs|cjs|jsx)$/;function Ze(e,n){let t=e.replace(/\\/g,"/"),r=n.root.replace(/^\/+|\/+$/g,"")+"/",o=t.indexOf(r);if(o===-1)return{ok:!0};let s=t.slice(o+r.length);if(n.folders?.length){let l=s.split("/")[0]??"",p=l.replace(/\.[^.]+$/,"");if(l!==""&&!n.folders.includes(l)&&!n.folders.includes(p))return{ok:!1,tier:"folder",found:l}}if(!n.allow.length)return{ok:!0};let a=Qe.exec(t);if(!a)return{ok:!0};if(t.endsWith(".d.ts"))return{ok:!0};if(!s.includes("/"))return{ok:!0};let d=s.slice(s.lastIndexOf("/")+1).slice(0,-a[0].length);return(d.endsWith(".test")?d.slice(0,-5)!==(n.thinking??""):!n.allow.includes(d))?{ok:!1,tier:"filename"}:{ok:!0}}function Xe(e,n,t){return e.ok?"":e.tier==="folder"?`'${e.found}' is not one of the names ${t.root}/ may hold: ${t.folders?.join(" \xB7 ")??""} (found ${n})`:`non-canonical file in a ${t.root} feature folder: ${n} (allowed: ${t.allow.join(" \xB7 ")}${t.thinking===void 0?"":` \u2014 only ${t.thinking} may carry a .test sibling`})`}var en=f(e=>n=>{let{path:t}=k(n),r=Ze(t,e);return r.ok?n.ok():n.fail(Xe(r,t,e))});function nn(e,n){let t=e;for(let r of(n??"").split(".").filter(Boolean)){if(t==null||typeof t!="object"||!(r in t))return{found:!1};t=t[r]}return{found:!0,value:t}}function tn(e,n){let t=[],{path:r}=n,o=nn(e,r);if(!o.found)return n.required===!0&&t.push(`"${r}" is missing (required)`),t;let s=o.value;if(n.keysPrefixedWith!==void 0){if(!s||typeof s!="object")return t;for(let a of Object.keys(s))a.startsWith(n.keysPrefixedWith)||t.push(`"${r}.${a}" must be prefixed "${n.keysPrefixedWith}"`)}return"equals"in n&&JSON.stringify(s)!==JSON.stringify(n.equals)&&t.push(`"${r}" must equal ${JSON.stringify(n.equals)} (is ${JSON.stringify(s)})`),n.matches!==void 0&&!new RegExp(n.matches).test(String(s))&&t.push(`"${r}" (${JSON.stringify(s)}) must match /${n.matches}/`),t}function rn(e,n){let t;try{t=JSON.parse(e)}catch{return[]}return n.flatMap(r=>tn(t,r))}var on=f(e=>n=>m(n,rn(k(n).content,e.assert)));function sn(e,n){return e.filter(t=>!new RegExp(`\\b${y(t)}\\b`).test(n))}async function an(e){let{parse:n,Lang:t}=await import("@ast-grep/napi"),r=n(t.Tsx,e).root(),o=new Set;for(let s of["export function $N($$$) { $$$ }","export class $N { $$$ }","export const $N = $V"])for(let a of r.findAll(s)){let i=a.getMatch("N");i&&o.add(i.text())}return[...o]}var dn=f(e=>async n=>{let{path:t,content:r}=k(n),o=A(e.sibling,t);if(!await n.fs.exists(o))return n.fail(`sibling test not found: ${o}`);let s=await n.fs.read(o),a=sn(await an(r),s);return m(n,a.map(i=>`exported '${i}' is never referenced in ${o}`))});async function X(e){return e.staged?e.staged:e.git.stagedFiles()}function ln(e,n){let t=[];for(let r of n)e.some(o=>g(o,r.if))&&(e.some(o=>g(o,r.thenAny))||t.push(`${r.if.join(", ")} changed but none of [${r.thenAny.join(", ")}] did in the same commit`));return t}var cn=f(e=>async n=>m(n,ln(await X(n),e.groups))),C=new Set([";","&&","||","|","&","|&",`
|
|
5
|
+
`]),un=new Set(["-C","-c","--git-dir","--work-tree","--namespace","--exec-path","--config-env"]);function fn(e,n){for(let t=n;t<e.length;t++){if(e[t]==="\\"){t++;continue}if(e[t]==='"')return t}return-1}function T(e){let n=e,t=[],r="",o=!1,s=0,a=()=>{o&&t.push(r),r="",o=!1};for(;s<n.length;){let i=n[s];if(i==="'"||i==='"'){let d=i==="'"?n.indexOf("'",s+1):fn(n,s+1);if(d===-1)return null;r+=i==='"'?n.slice(s+1,d).replace(/\\(["\\$`])/g,"$1"):n.slice(s+1,d),o=!0,s=d+1}else if(i==="\\"&&s+1<n.length)r+=n[s+1],o=!0,s+=2;else if(i===`
|
|
6
6
|
`)a(),t.push(`
|
|
7
|
-
`),s++;else if(/\s/.test(i))a(),s++;else if(i===";"||i==="|"||i==="&"){a();let d=
|
|
7
|
+
`),s++;else if(/\s/.test(i))a(),s++;else if(i===";"||i==="|"||i==="&"){a();let d=n.slice(s,s+2);d==="&&"||d==="||"||d==="|&"?(t.push(d),s+=2):(t.push(i),s++)}else r+=i,o=!0,s++}return a(),t}function j(e){let n=T(e);if(!n)return null;let t=[],r=0,o=!0;for(;r<n.length;){let s=n[r];if(C.has(s)){o=!0,r++;continue}if(o&&s==="git"){let a=[],i=r+1;for(;i<n.length&&!C.has(n[i]);)a.push(n[i++]);let d=0;for(;d<a.length;){let c=a[d];if(un.has(c))d+=2;else if(c.startsWith("-"))d+=1;else break}t.push({globals:a.slice(0,d),subcommand:a[d]??null,args:a.slice(d+1)}),r=i,o=!1;continue}o=!1,r++}return t}function pn(e){let n=/<<-?\s*(['"]?)([A-Za-z_][A-Za-z0-9_]*)\1/.exec(e);if(!n)return null;let t=n[2],o=e.slice(n.index+n[0].length).split(`
|
|
8
8
|
`).slice(1),s=o.findIndex(i=>i.trim()===t);if(s===-1)return null;let a=o.slice(0,s).join(`
|
|
9
|
-
`).trim();return a===""?null:a}function
|
|
9
|
+
`).trim();return a===""?null:a}function ee(e){let n=j(e);if(!n)return null;let t=n.find(o=>o.subcommand==="commit");if(!t)return null;let r=[];for(let o=0;o<t.args.length;o++){let s=t.args[o];if(s==="-m"||s==="--message"){let a=t.args[o+1];if(a===void 0)break;r.push(a),o++;continue}s.startsWith("-m")&&s!=="-m"?r.push(s.slice(2)):s.startsWith("--message=")&&r.push(s.slice(10))}return r.length?r.join(`
|
|
10
10
|
|
|
11
|
-
`):
|
|
12
|
-
`)){if(!s.startsWith("+")||s.startsWith("+++"))continue;let a=s.slice(1);for(let i of
|
|
13
|
-
`).map(
|
|
14
|
-
`).filter(Boolean),r=t.filter(o=>/\b(fail|failed|error|not ok|assert|expected|cannot|undefined)\b/i.test(o)||/[✖✗✘]/.test(o));return(r.length?r:t.slice(-6)).slice(0,
|
|
15
|
-
`)}var
|
|
16
|
-
${
|
|
17
|
-
`)}function
|
|
18
|
-
`)),
|
|
11
|
+
`):pn(e)}function b(e){return`'${e.replace(/'/g,"'\\''")}'`}function ne(e){let n=[],t=T(e),r=t?.[1];t?.[0]==="cd"&&r!==void 0&&!r.startsWith("-")&&!C.has(r)&&C.has(t[2]??"")&&n.push("-C",b(r));let o=j(e)?.[0];if(!o)return n.join(" ");for(let s=0;s<o.globals.length-1;s++)o.globals[s]==="-C"&&n.push("-C",b(o.globals[s+1]));return n.join(" ")}function te(e,n){return new RegExp(`^[ \\t]*${y(n)}[ \\t]*:`,"im").test(e)}function gn(e,n,t=[]){let r=new Set(t),o=new Set;for(let s of e.split(`
|
|
12
|
+
`)){if(!s.startsWith("+")||s.startsWith("+++"))continue;let a=s.slice(1);for(let i of n){let d=new RegExp(i,"g"),c;for(;(c=d.exec(a))!==null;)c[1]!==void 0&&!r.has(c[1])&&o.add(c[1]),c[0]===""&&d.lastIndex++}}return[...o]}function yn(e){let{message:n,state:t,whenChanged:r,whenAdded:o,except:s,namesAdded:a,token:i}=e,d=new Set(t.added),c=[];for(let l of t.changed)s&&g(l,s)||(d.has(l)&&o&&g(l,o)?c.push(`\`${l}\` (new)`):r&&g(l,r)&&c.push(`\`${l}\` (changed)`));for(let{name:l,file:p}of a??[])c.push(`\`${l}\` (added in ${p})`);return c.length?te(n,i)?[]:[`${c.join(" \xB7 ")} \u2014 and this commit's message records no reason. Put \`${i}: <why>\` on a line of its own in the message; the act is fine, doing it silently is not.`]:[]}function B(e){return e.split(`
|
|
13
|
+
`).map(n=>n.trim()).filter(Boolean)}var mn=f(e=>async n=>{let t=ee(n.command??"");if(t==null)return n.ok();let r=`git ${ne(n.command??"")}`.trimEnd(),o={changed:[],added:[]};if(e.whenChanged||e.whenAdded){let[i,d,c]=await Promise.all([n.exec(`${r} diff HEAD --name-only`),n.exec(`${r} diff HEAD --name-only --diff-filter=A`),n.exec(`${r} ls-files --others --exclude-standard`)]);if(i.code!==0||d.code!==0||c.code!==0)return n.ok();let l=B(c.stdout);o={changed:[...new Set([...B(i.stdout),...l])],added:[...B(d.stdout),...l]}}let s=[];for(let i of e.diffAdds??[]){let d=await n.exec(`${r} diff HEAD -- ${b(i.file)}`);if(d.code!==0)return n.ok();for(let c of gn(d.stdout,i.patterns,i.known??[]))s.push({name:c,file:i.file})}let a=yn({message:t,state:o,whenChanged:e.whenChanged,whenAdded:e.whenAdded,except:e.except,namesAdded:s,token:e.token});return m(n,a)});function hn(e,n,t){if(t===""||n.length===0)return!1;let r=-1,o=-1;return e.forEach((s,a)=>{s.did==="edit"&&g(s.path,n)&&(r=a),s.did==="run"&&s.command.includes(t)&&(o=a)}),r>=0&&r>o}var kn=f(e=>n=>n.turn&&hn(n.turn,e.edited,e.mustRun)?n.fail(`edited ${e.edited.join(", ")} this turn but never ran \`${e.mustRun}\` afterwards`):n.ok());function bn(e,n){let t=n??[];return!t.length||!e.length?!1:!e.some(r=>g(r,t))}function re(e,n=8){let t=e.trim().split(`
|
|
14
|
+
`).filter(Boolean),r=t.filter(o=>/\b(fail|failed|error|not ok|assert|expected|cannot|undefined)\b/i.test(o)||/[✖✗✘]/.test(o));return(r.length?r:t.slice(-6)).slice(0,n).join(`
|
|
15
|
+
`)}var xn=f(e=>async n=>{let t=await X(n);if(bn(t,e.changed))return n.ok();let r=e.run.includes("{files}");if(r&&t.length===0)return n.ok();let o=r?e.run.replace("{files}",t.map(b).join(" ")):e.run,s=await n.exec(o);return s.code===0?n.ok():n.fail(`\`${o}\` failed (exit ${s.code}):
|
|
16
|
+
${re(s.stderr||s.stdout)}`)});function R(e){let n=O(e),t=n[n.length-1]?.kind==="globstar";return`^${(t?n.slice(0,-1):n).map(v).join("")}${t?"":"$"}`}function z(e){return e==="node:*"?{core:!0}:e.startsWith("node:")?{path:`^${y(e)}$`}:e.includes("/")||e.includes("*")||e.includes(".")?{path:R(e)}:{path:`node_modules/${y(e)}(/|$)`}}function E(e){return e===void 0?{path:[],not:[]}:Array.isArray(e)?{path:e,not:[]}:{path:e.path,not:e.not??[]}}function S(e,n){let t=[],r=[],o=!1;for(let a of e){let{path:i,not:d}=E(n[a]);for(let c of i){let l=z(c);l.core?o=!0:l.path&&t.push(l.path)}for(let c of d){let l=z(c);l.path&&r.push(l.path)}}let s={};return t.length&&(s.path=t),r.length&&(s.pathNot=r),o&&(s.dependencyTypes=["core"]),s}function wn(e){let n=e.layers,t=[],r=[],o=(e.except??[]).includes("type-only"),s=i=>o?{...i,dependencyTypesNot:["type-only"]}:i;for(let[i,d]of Object.entries(e.only??{})){let l={pathNot:S(d,n).path??[]};t.push({name:`${i}-only`,severity:"error",comment:`${i} may import only: ${d.join(", ")} \u2014 an unlisted import blocks here (add it to a layer, or keep it out).`,from:S([i],n),to:s(l)})}for(let i of e.forbid??[])if(i==="circular")t.push({name:"no-circular",severity:"error",comment:"no dependency cycles",from:{pathNot:"node_modules"},to:{circular:!0}});else if(i==="orphans")t.push({name:"no-orphans",severity:"warn",comment:"unreferenced module",from:{orphan:!0,pathNot:"node_modules|\\.d\\.ts$"},to:{}});else if(i.cyclesBetween!==void 0){let d=i.cyclesBetween,c=E(n[d]).path[0]??"",l=R(c).replace(/\$$/,"").replace(/\[\^\/\]\*$/,"([^/]+)");t.push({name:`no-cycles-between-${d}`,severity:"error",comment:i.why??`${d} must not import sideways`,from:{path:`${l}/`},to:s({path:`${l.replace(/\(\[\^\/\]\+\)/,"[^/]+")}/`,pathNot:"$1/"})})}else if(i.from!==void 0&&i.to!==void 0){let d={...S([i.to],n)};i.transitive===!0&&(d.reachable=!0),t.push({name:`no-${i.from}-to-${i.to}${i.transitive===!0?"-transitive":""}`,severity:"error",comment:i.why??`${i.from} must not import ${i.to}`,from:S([i.from],n),to:s(d)})}for(let i of e.require??[])r.push({name:`must-import-${i.import}`,severity:"error",comment:i.why??`modules in ${i.in} must import ${i.import}`,module:{path:R(i.in)},to:{path:R(i.import)}});for(let i of e.warn??[])i==="sdp"&&t.push({name:"sdp",severity:"warn",comment:"depends on a more-unstable module (Stable Dependencies Principle)",from:{},to:{moreUnstable:!0}});let a={enhancedResolveOptions:{extensions:[".js",".jsx",".ts",".tsx",".mjs",".cjs",".json"]},doNotFollow:{path:"node_modules"},tsPreCompilationDeps:!1,...e.options??{}};return{forbidden:t,required:r,options:a}}var Q="FLOW_DEPCRUISE_CONFIG";function Sn(e){let n=JSON.stringify(wn(e));return["d=$(mktemp -d)",`cat > "$d/dc.json" <<'${Q}'`,n,Q,`npx --no-install depcruise --config "$d/dc.json" --output-type json ${b(e.scan)}`,"rc=$?",'rm -rf "$d"',"exit $rc"].join(`
|
|
17
|
+
`)}function Rn(e){let n;try{n=JSON.parse(e.stdout||"")}catch{return e.code===0?[]:[`depcruise failed (exit ${e.code}): ${re(e.stderr||e.stdout,3)}`]}return(n.summary?.violations??[]).map(t=>{let r=t.rule?.name??"fence",o=t.comment??t.rule?.comment??"";return`${r}: ${t.from} \u2192 ${t.to}${o?` \u2014 ${o}`:""}`})}function Cn(e){let n=[];for(let[t,r]of Object.entries(e)){let{path:o,not:s}=E(r);s.includes("node:*")&&n.push(`binds a depcruise layer \`${t}\` whose \`not\` list excludes \`node:*\`. A builtin is matched as a dependency TYPE, not a path, and the only exclusion available says "not a core module at all" \u2014 wider than this layer means. Say the layer's globs without it, or forbid the edge you actually mean.`);for(let a of[...o,...s])D(a)&&n.push(`binds a depcruise layer \`${t}\` whose entry is a regular expression, not a glob: \`${a}\`. Layers are GLOBS here \u2014 \`src/pages/**\`, \`src/lib/auth/**\` \u2014 and a regex is escaped into a literal, so the fence would load, report armed and match nothing. For a layer with holes in it, say \`{ path: ["src/pages/**"], not: ["src/pages/api/**"] }\` rather than a lookahead.`)}return n}function En(e){let n=[];for(let[t,r]of Object.entries(e.only??{}))for(let o of r)E(e.layers[o]).not.length>0&&n.push(`binds a depcruise \`only\` for \`${t}\` naming the layer \`${o}\`, which has a \`not\` list. An allowlist is compiled by inverting the layers it names, and that inversion reads \`path\` alone \u2014 so \`${o}\`'s exclusions would be silently dropped and the allowlist would be wider than it reads. Give \`${o}\` plain globs, or say the exclusion as a \`forbid\` edge.`);return n}var $n=f(e=>P(async t=>m(t,Rn(await t.exec(Sn(e))),`
|
|
18
|
+
`),[...Cn(e.layers),...En(e)])),oe={html:"Html",css:"Css",javascript:"JavaScript",js:"JavaScript",typescript:"TypeScript",ts:"TypeScript",tsx:"Tsx",jsx:"Tsx"},On=Object.keys(oe),G=new Set,Z=Symbol.for("flow.grammars");function vn(){let e=globalThis,n=e[Z];if(n!==void 0)return n;let t={declared:[],present:()=>!1};return e[Z]=t,t}function An(e,n){return`\`${e}\`: no library at ${n}. A grammar is a BUILD ARTEFACT \u2014 machine-specific, never committed \u2014 so this is the ordinary state of a fresh clone. Build it (the repo that declares a grammar carries the recipe that builds it), or every ast-grep rule on that language refuses rather than passing quietly.`}async function Mn(e){let{Lang:n,registerDynamicLanguage:t}=await import("@ast-grep/napi"),r=oe[e];if(r!==void 0)return{ok:!0,lang:n[r]};if(G.has(e))return{ok:!0,lang:e};let{declared:o,present:s}=vn(),a=o.find(i=>i.name===e);if(a!==void 0)return s(a.libraryPath)?(t({[e]:{libraryPath:a.libraryPath,extensions:[...a.extensions],...a.languageSymbol===void 0?{}:{languageSymbol:a.languageSymbol}}}),G.add(e),{ok:!0,lang:e}):{ok:!1,detail:An(e,a.libraryPath)};try{let i=await import(`@ast-grep/lang-${e}`);return t({[e]:i.default??i}),G.add(e),{ok:!0,lang:e}}catch{return{ok:!1,detail:`unknown ast-grep grammar: '${e}'. Built in: ${On.join(", ")}. Anything else is either a published package \u2014 \`npm i -D @ast-grep/lang-${e}\` \u2014 or a grammar you build yourself and declare in flow.config.ts's \`grammars\` setting.`}}}async function Pn(e,n,t){let r=await Mn(t);if(!r.ok)return r;let{parse:o}=await import("@ast-grep/napi");return{ok:!0,hits:o(r.lang,e).root().findAll({rule:n}).map(a=>`${a.range().start.line+1}: ${a.text()}`)}}var Bn=f(e=>async n=>{let t=await Pn(k(n).content,e.rule,e.language);return t.ok?m(n,t.hits):n.fail(t.detail)});function Gn(e){return n=>{let t=n.agentType;return e.parent===!0?!n.subagent&&t===void 0:t===void 0?!1:(e.types??[]).includes(t)?!0:(e.generic??[]).includes(t)?(e.brief??[]).some(r=>n.head.includes(r)):!1}}var qn=14400*1e3;var $=class extends Error{refusals;constructor(n){super(w(n)),this.name="FlowConfigError",this.refusals=n}};function Tn(e){if(e.ok)return e.entries;throw new $(e.refusals)}export{$ as FlowConfigError,Le as REFUSAL_CODES,Je as SUBSTITUTION_MESSAGE,Bn as astGrep,Ve as banCommands,Ae as breadcrumb,en as canonicalFiles,cn as changeTogether,fe as command,pe as commit,ee as commitMessage,mn as commitReason,Re as defineCategory,f as defineCheck,Ne as defineConfig,Pe as definePack,ge as deletion,$n as depcruise,Tn as entriesOrThrow,y as escapeRe,xn as execPasses,q as faultsOf,ne as gitDirPrefix,j as gitInvocations,te as givesReason,ve as guardrail,on as jsonInvariant,Fe as loadConfig,De as override,je as pack,Ye as protectedPath,b as quoteArg,kn as ranSinceEdit,w as refusalText,me as session,ze as siblingExists,Gn as spawnedAs,He as substitutionInProse,dn as symbolsInSibling,Ue as textBan,T as tokenizeCommand,he as touch,ye as turnEnd,P as withFaults,ue as write};
|