@archdoc/cli 0.4.0 → 0.4.1

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@archdoc/cli",
3
- "version": "0.4.0",
3
+ "version": "0.4.1",
4
4
  "description": "The archdoc command-line tool.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -28,11 +28,11 @@
28
28
  "dependencies": {
29
29
  "commander": "^14.0.3",
30
30
  "yaml": "^2.9.1",
31
- "@archdoc/analyzers": "0.4.0",
32
- "@archdoc/core": "0.4.0",
33
- "@archdoc/federation": "0.4.0",
34
- "@archdoc/mcp": "0.4.0",
35
- "@archdoc/spec": "0.4.0"
31
+ "@archdoc/core": "0.4.1",
32
+ "@archdoc/analyzers": "0.4.1",
33
+ "@archdoc/federation": "0.4.1",
34
+ "@archdoc/mcp": "0.4.1",
35
+ "@archdoc/spec": "0.4.1"
36
36
  },
37
37
  "publishConfig": {
38
38
  "access": "public"
@@ -173,7 +173,7 @@ $&`).replace(/(?:^|\n)([\t ].*)(?:([\n\t ]*)\n(?![\n\t ]))?/g,`$1$2`).replace(/\
173
173
  `:case`\r`:this.pos++;continue;case`=`:if(t[e+1]!==`=`)break;return this.token((this.pos+=2)-2,rg.EQ);case`&`:if(t[e+1]!==`&`)break;return this.token((this.pos+=2)-2,rg.AND);case`|`:if(t[e+1]!==`|`)break;return this.token((this.pos+=2)-2,rg.OR);case`+`:return this.token(this.pos++,rg.PLUS);case`-`:return this.token(this.pos++,rg.MINUS);case`*`:return this.token(this.pos++,rg.MULTIPLY);case`/`:if(t[e+1]===`/`){for(;this.pos<n&&this.input[this.pos]!==`
174
174
  `;)this.pos++;continue}return this.token(this.pos++,rg.DIVIDE);case`%`:return this.token(this.pos++,rg.MODULO);case`<`:return t[e+1]===`=`?this.token((this.pos+=2)-2,rg.LE):this.token(this.pos++,rg.LT);case`>`:return t[e+1]===`=`?this.token((this.pos+=2)-2,rg.GE):this.token(this.pos++,rg.GT);case`!`:return t[e+1]===`=`?this.token((this.pos+=2)-2,rg.NE):this.token(this.pos++,rg.NOT);case`(`:return this.token(this.pos++,rg.LPAREN);case`)`:return this.token(this.pos++,rg.RPAREN);case`[`:return this.token(this.pos++,rg.LBRACKET);case`]`:return this.token(this.pos++,rg.RBRACKET);case`{`:return this.token(this.pos++,rg.LBRACE);case`}`:return this.token(this.pos++,rg.RBRACE);case`.`:return this.token(this.pos++,rg.DOT);case`,`:return this.token(this.pos++,rg.COMMA);case`:`:return this.token(this.pos++,rg.COLON);case`?`:return this.token(this.pos++,rg.QUESTION);case`"`:case`'`:return this.readString(r);case`b`:case`B`:case`r`:case`R`:{let n=t[e+1];return n===`"`||n===`'`?++this.pos&&this.readString(n,r):this.readIdentifier()}default:{let e=r.charCodeAt(0);if(e<=57&&e>=48)return this.readNumber();if(this._isIdentifierCharCode(e))return this.readIdentifier()}}throw Om(`unexpected_character`,`Unexpected character: ${r}`,{pos:e,start:e,end:e+1,input:t})}}_isIdentifierCharCode(e){return e<48||e>122?!1:e>=97||e>=65&&e<=90||e<=57||e===95}_parseAsDouble(e,t){let n=Number(this.input.substring(e,t));if(Number.isFinite(n))return this.token(e,rg.NUMBER,n);throw Om(`invalid_number`,`Invalid number: ${n}`,{pos:e,start:e,end:t,input:this.input})}_parseAsBigInt(e,t,n,r){let i=this.input.substring(e,t);if(r===`u`||r===`U`){this.pos++;try{return this.token(e,rg.NUMBER,new qm(i))}catch{}}else try{return this.token(e,rg.NUMBER,BigInt(i))}catch{}throw Om(n?`invalid_hex_integer`:`invalid_integer`,n?`Invalid hex integer: ${i}`:`Invalid integer: ${i}`,{pos:e,start:e,end:this.pos,input:this.input})}_readDigits(e,t,n,r){for(;n<t&&(r=e.charCodeAt(n))&&!(r>57||r<48);)n++;return n}_readExponent(e,t,n){let r=n<t&&e[n];if(r===`e`||r===`E`){r=++n<t&&e[n],(r===`-`||r===`+`)&&n++;let i=n;if(n=this._readDigits(e,t,n),i===n)throw Om(`invalid_exponent`,`Invalid exponent`,{pos:n,start:n,end:Math.min(n+1,e.length),input:e})}return n}readNumber(){let{input:e,length:t,pos:n}=this,r=n;if(e[r]===`0`&&(e[r+1]===`x`||e[r+1]===`X`)){for(r+=2;r<t&&og[e[r].charCodeAt(0)];)r++;return this._parseAsBigInt(n,this.pos=r,!0,e[r])}if(r=this._readDigits(e,t,r),r+1<t){let i=!1,a=e[r]===`.`?this._readDigits(e,t,r+1):r+1;if(a!==r+1&&(i=!0)&&(r=a),a=this._readExponent(e,t,r),a!==r&&(i=!0)&&(r=a),i)return this._parseAsDouble(n,this.pos=r)}return this._parseAsBigInt(n,this.pos=r,!1,e[r])}readString(e,t){let{input:n,pos:r}=this;return n[r+1]===e&&n[r+2]===e?this.readTripleQuotedString(e,t):this.readSingleQuotedString(e,t)}_closeQuotedString(e,t,n,r){switch(n){case`b`:case`B`:{let n=this.processEscapes(e,t,!0),i=new Uint8Array(n.length);for(let e=0;e<n.length;e++)i[e]=n.charCodeAt(e)&255;return this.token(r-1,rg.BYTES,i)}case`r`:case`R`:return this.token(r-1,rg.STRING,t);default:{let n=this.processEscapes(e,t,!1);return this.token(r,rg.STRING,n)}}}readSingleQuotedString(e,t){let{input:n,length:r,pos:i}=this,a,o=this.pos+1;for(;o<r&&(a=n[o]);){switch(a){case e:let r=i+1,a=n.slice(r,o);return this.pos=++o,this._closeQuotedString(r,a,t,i);case`
175
175
  `:case`\r`:throw Om(`newline_in_string`,`Newlines not allowed in single-quoted strings`,{pos:o,start:o,end:o+1,input:n});case`\\`:o++}o++}throw Om(`unterminated_string`,`Unterminated string`,{pos:i,start:i,end:n.length,input:n})}readTripleQuotedString(e,t){let{input:n,length:r,pos:i}=this,a,o=this.pos+3;for(;o<r&&(a=n[o]);){switch(a){case e:if(n[o+1]===e&&n[o+2]===e){let e=i+3,r=n.slice(e,o);return this.pos=o+3,this._closeQuotedString(e,r,t,i)}break;case`\\`:o++}o++}throw Om(`unterminated_triple_quoted_string`,`Unterminated triple-quoted string`,{pos:i,start:i,end:n.length,input:n})}#e(e,t,n,r,i,a){let o=t+r;return Om(e,sg[e](a),{input:this.input,pos:o,start:o,end:Math.min(o+i,t+n)})}processEscapes(e,t,n){if(!t.includes(`\\`))return t;let r=t.length,i=``,a=0;for(;a<r;){if(t[a]!==`\\`||a+1>=r){i+=t[a++];continue}let o=t[a+1];if(fte[o])i+=fte[o],a+=2;else if(o===`u`||o===`U`){if(n)throw this.#e(`bytes_unicode_escape`,e,r,a,2,o);let s=o===`u`?4:8,c=t.substring(a+2,a+2+s),l=Number.parseInt(c,16);if(c.length!==s||!/^[0-9a-fA-F]+$/.test(c)||l>1114111)throw this.#e(`invalid_unicode_escape`,e,r,a,2+s,o+c);if(l>=55296&&l<=57343)throw this.#e(`invalid_unicode_surrogate`,e,r,a,2+s,o+c);i+=String.fromCodePoint(l),a+=2+s}else if(o===`x`||o===`X`){let n=t.substring(a+2,a+4);if(!/^[0-9a-fA-F]{2}$/.test(n))throw this.#e(`invalid_hex_escape`,e,r,a,4,o+n);i+=String.fromCharCode(Number.parseInt(n,16)),a+=4}else if(o>=`0`&&o<=`7`){let n=t.substring(a+1,a+4);if(!/^[0-7]{3}$/.test(n))throw this.#e(`invalid_octal_escape`,e,r,a,4);let o=Number.parseInt(n,8);if(o>255)throw this.#e(`octal_escape_out_of_range`,e,r,a,4,n);i+=String.fromCharCode(o),a+=4}else throw this.#e(`invalid_escape_sequence`,e,r,a,2,o)}return i}readIdentifier(){let{pos:e,input:t,length:n}=this,r=e;for(;r<n&&this._isIdentifierCharCode(t[r].charCodeAt(0));)r++;let i=t.substring(e,this.pos=r);switch(i){case`true`:return this.token(e,rg.BOOLEAN,!0);case`false`:return this.token(e,rg.BOOLEAN,!1);case`null`:return this.token(e,rg.NULL,null);case`in`:return this.token(e,rg.IN);default:return this.token(e,rg.IDENTIFIER,i)}}},hte=class{lexer=mte;input=null;maxDepthRemaining=null;astNodesRemaining=null;type=null;pos=null;constructor(e,t){this.limits=e,this.registry=t}#e(e,t=this.pos){throw Om(`limit_exceeded`,`Exceeded ${e} (${this.limits[e]})`,{pos:t,start:t,end:t,input:this.input})}#t(e,t,n,r,i=e){let a=new pte(this.input,i,e,t,n,r);return this.astNodesRemaining--||this.#e(`maxAstNodes`,i),a}#n(e,t,n){return this.#t(t.start,n.end,e,[t,n])}#r(e,t,n){return this.#t(e.start,n.end,Qh.ternary,[e,t,n])}#i(e,t,n){return this.#t(e,n.end,t,n)}#a(e,t,n,r,i=t.start){return this.#t(t.start,r,e,[t,n],i)}#o(e=this.pos){let t=this.lexer.nextToken();return this.pos=t.tokenPos,this.type=t.tokenType,e}get value(){return this.lexer.tokenValue}consume(e){if(this.type===e)return this.#o();throw Om(`expected_token`,`Expected ${ag[e]}, got ${ag[this.type]}`,{pos:this.pos,start:this.pos,end:this.lexer.pos,input:this.input})}match(e){return this.type===e}parse(e){if(typeof e!=`string`)throw Om(`expression_must_be_string`,`Expression must be a string`);this.input=this.lexer.reset(e),this.#o(),this.maxDepthRemaining=this.limits.maxDepth,this.astNodesRemaining=this.limits.maxAstNodes;let t=this.parseExpression();if(this.match(rg.EOF))return t;throw Om(`unexpected_character`,`Unexpected character: '${this.input[this.lexer.pos-1]}'`,{pos:this.pos,start:this.pos,end:this.lexer.pos,input:this.input})}#s(e,t,n,r){let i=r[0],a=n===Qh.rcall?r[1]:null,o=n===Qh.rcall?r[2]:r[1],s=this.registry.findMacro(i,!!a,o.length),c=this.#t(e,t,n,r);if(!s)return c;let l=s.handler({ast:c,args:o,receiver:a,methodName:i,parser:this});return l.callAst?c.setMeta(`alternate`,l.callAst):c.setMeta(`macro`,l).setMeta(`async`,Gm(l.evaluate,l.async))}parseExpression(){this.maxDepthRemaining--||this.#e(`maxDepth`);let e=this.parseLogicalOr();if(!this.match(rg.QUESTION))return++this.maxDepthRemaining&&e;this.#o();let t=this.parseExpression();this.consume(rg.COLON);let n=this.parseExpression();return this.maxDepthRemaining++,this.#r(e,t,n)}parseLogicalOr(){let e=this.parseLogicalAnd();for(;this.match(rg.OR);)this.#o(),e=this.#n(Qh[`||`],e,this.parseLogicalAnd());return e}parseLogicalAnd(){let e=this.parseEquality();for(;this.match(rg.AND);)this.#o(),e=this.#n(Qh[`&&`],e,this.parseEquality());return e}parseEquality(){let e=this.parseRelational();for(;this.match(rg.EQ)||this.match(rg.NE);){let t=ig[this.type];this.#o(),e=this.#n(t,e,this.parseRelational())}return e}parseRelational(){let e=this.parseAdditive();for(;this.match(rg.LT)||this.match(rg.LE)||this.match(rg.GT)||this.match(rg.GE)||this.match(rg.IN);){let t=ig[this.type];this.#o(),e=this.#n(t,e,this.parseAdditive())}return e}parseAdditive(){let e=this.parseMultiplicative();for(;this.match(rg.PLUS)||this.match(rg.MINUS);){let t=ig[this.type];this.#o(),e=this.#n(t,e,this.parseMultiplicative())}return e}parseMultiplicative(){let e=this.parseUnary();for(;this.match(rg.MULTIPLY)||this.match(rg.DIVIDE)||this.match(rg.MODULO);){let t=ig[this.type];this.#o(),e=this.#n(t,e,this.parseUnary())}return e}parseUnary(){return this.type===rg.NOT?this.#i(this.#o(),Qh.unaryNot,this.parseUnary()):this.type===rg.MINUS?this.#i(this.#o(),Qh.unaryMinus,this.parseUnary()):this.parsePostfix()}parsePostfix(){let e=this.parsePrimary(),t=this.maxDepthRemaining;for(;;)if(this.match(rg.DOT)){let t=this.#o();this.maxDepthRemaining--||this.#e(`maxDepth`,t);let n=this.match(rg.QUESTION)&&this.registry.enableOptionalTypes&&this.#o()?Qh.optionalFieldAccess:Qh.fieldAccess,r=this.value,i=this.pos,a=this.lexer.pos;if(this.consume(rg.IDENTIFIER),n===Qh.fieldAccess&&this.match(rg.LPAREN)&&this.#o()){let t=this.parseArgumentList(),n=this.lexer.pos;this.consume(rg.RPAREN),e=this.#s(e.start,n,Qh.rcall,[r,e,t])}else e=this.#a(n,e,r,a,i)}else if(this.match(rg.LBRACKET)){let t=this.#o();this.maxDepthRemaining--||this.#e(`maxDepth`,t);let n=this.match(rg.QUESTION)&&this.registry.enableOptionalTypes&&this.#o()?Qh.optionalBracketAccess:Qh.bracketAccess,r=this.parseExpression(),i=this.lexer.pos;this.consume(rg.RBRACKET),e=this.#a(n,e,r,i)}else break;return this.maxDepthRemaining=t,e}parsePrimary(){switch(this.type){case rg.NUMBER:case rg.STRING:case rg.BYTES:case rg.BOOLEAN:case rg.NULL:return this.#c();case rg.IDENTIFIER:return this.#l();case rg.LPAREN:return this.#u();case rg.LBRACKET:return this.parseList();case rg.LBRACE:return this.parseMap()}throw Om(`unexpected_token`,`Unexpected token: ${ag[this.type]}`,{pos:this.pos,start:this.pos,end:this.lexer.pos,input:this.input})}#c(){return this.#o(this.#t(this.pos,this.lexer.pos,Qh.value,this.value))}#l(){let e=this.value,t=this.lexer.pos,n=this.consume(rg.IDENTIFIER);if(Km.has(e))throw Om(`reserved_identifier`,`Reserved identifier: ${e}`,{pos:n,start:n,end:t,input:this.input});if(!this.match(rg.LPAREN))return this.#t(n,t,Qh.id,e);this.#o();let r=this.parseArgumentList(),i=this.lexer.pos;return this.consume(rg.RPAREN),this.#s(n,i,Qh.call,[e,r])}#u(){this.consume(rg.LPAREN);let e=this.parseExpression();return this.consume(rg.RPAREN),e}parseList(){let e=this.consume(rg.LBRACKET),t=[],n=this.limits.maxListElements;if(!this.match(rg.RBRACKET))for(t.push(this.parseExpression()),n--||this.#e(`maxListElements`,t.at(-1).pos);this.match(rg.COMMA)&&(this.#o(),!this.match(rg.RBRACKET));)t.push(this.parseExpression()),n--||this.#e(`maxListElements`,t.at(-1).pos);let r=this.lexer.pos;return this.consume(rg.RBRACKET),this.#t(e,r,Qh.list,t)}parseMap(){let e=this.consume(rg.LBRACE),t=[],n=this.limits.maxMapEntries;if(!this.match(rg.RBRACE))for(t.push(this.parseProperty()),n--||this.#e(`maxMapEntries`,t.at(-1)[0].pos);this.match(rg.COMMA)&&(this.#o(),!this.match(rg.RBRACE));)t.push(this.parseProperty()),n--||this.#e(`maxMapEntries`,t.at(-1)[0].pos);let r=this.lexer.pos;return this.consume(rg.RBRACE),this.#t(e,r,Qh.map,t)}parseProperty(){return[this.parseExpression(),(this.consume(rg.COLON),this.parseExpression())]}parseArgumentList(){let e=[],t=this.limits.maxCallArguments;if(!this.match(rg.RPAREN))for(e.push(this.parseExpression()),t--||this.#e(`maxCallArguments`,e.at(-1).pos);this.match(rg.COMMA)&&(this.#o(),!this.match(rg.RPAREN));)e.push(this.parseExpression()),t--||this.#e(`maxCallArguments`,e.at(-1).pos);return e}},cg=Vm({maxAstNodes:1e5,maxDepth:250,maxListElements:1e3,maxMapEntries:1e3,maxCallArguments:32}),gte=new Set(Bm(cg));function _te(e,t=cg){let n=e?Bm(e):void 0;if(!n?.length)return t;let r={...t};for(let t of n){if(!gte.has(t))throw TypeError(`Unknown limits option: ${t}`);let n=e[t];typeof n==`number`&&(r[t]=n)}return Vm(r)}var vte=Vm({unlistedVariablesAreDyn:!1,homogeneousAggregateLiterals:!0,enableOptionalTypes:!1,limits:cg});function lg(e,t,n){let r=e?.[n]??t?.[n];if(typeof r!=`boolean`)throw TypeError(`Invalid option: ${n}`);return r}function yte(e,t=vte){return e?Vm({unlistedVariablesAreDyn:lg(e,t,`unlistedVariablesAreDyn`),homogeneousAggregateLiterals:lg(e,t,`homogeneousAggregateLiterals`),enableOptionalTypes:lg(e,t,`enableOptionalTypes`),limits:_te(e.limits,t.limits)}):t}var ug=Mh({enableOptionalTypes:!1});Qm(ug),lte(ug),cte(ug);var dg=class e{#e;#t;#n;#r;#i;constructor(t,n){this.opts=yte(t,n?.opts),this.#e=(n instanceof e?n.#e:ug).clone(this.opts);let r={registry:this.#e,opts:this.opts};this.#n=new dte(r),this.#r=new dte(r,!0),this.#t=new bte(r),this.#i=new hte(this.opts.limits,this.#e),Object.freeze(this)}clone(t){return new e(t,this)}registerFunction(e,t,n){return this.#e.registerFunctionOverload(e,t,n),this}registerOperator(e,t,n){return this.#e.registerOperatorOverload(e,t,n),this}registerType(e,t){return this.#e.registerType(e,t),this}registerVariable(e,t,n){return this.#e.registerVariable(e,t,n),this}registerConstant(e,t,n){return this.#e.registerConstant(e,t,n),this}hasVariable(e){return this.#e.variables.has(e)}getDefinitions(){return this.#e.getDefinitions()}check(e){try{return this.#a(this.#i.parse(e))}catch(e){return{valid:!1,error:e}}}#a(e){try{let t=this.#n.check(e,new Nh(this.#e));return{valid:!0,type:this.#o(t)}}catch(e){return{valid:!1,error:e}}}#o(e){return e.name===`list<dyn>`?`list`:e.name===`map<dyn, dyn>`?`map`:e.name}parse(e){let t=this.#i.parse(e),n=this.#s.bind(this,t);return n.check=this.#a.bind(this,t),n.ast=t,n}evaluate(e,t){return this.#s(this.#i.parse(e),t)}#s(e,t){return e.checkedType?e.evaluate(this.#t,e,new Nh(this.#e,t)):(this.#r.check(e,t=new Nh(this.#e,t)),e.evaluate(this.#t,e,t))}},bte=class extends Rh{constructor(e){super(e),this.createError=km}#e(e){if(e instanceof Map)return e.entries().next().value;for(let t in e)return[t,e[t]]}debugRuntimeType(e,t){return t?.hasDynType===!1?t:this.debugTypeDeep(e)}debugTypeDeep(e){let t=this.debugType(e);switch(t.kind){case`list`:{let n=e instanceof Array?e[0]:e.values().next().value;return n===void 0?t:this.registry.getListType(this.debugTypeDeep(n))}case`map`:{let n=this.#e(e);return n?this.registry.getMapType(t.keyType.hasDynType?this.debugTypeDeep(n[0]):t.keyType,t.valueType.hasDynType?this.debugTypeDeep(n[1]):t.valueType):t}default:return t}}tryEval(e,t){try{let n=this.run(e,t);return n instanceof Promise?n.catch(e=>e):n}catch(e){return e}}run(e,t){return e.evaluate(this,e,t)}};new dg({unlistedVariablesAreDyn:!0});var xte=`2026-01-01T00:00:00.000Z`,Ste=new dg({unlistedVariablesAreDyn:!0}).registerFunction(`now(): google.protobuf.Timestamp`,()=>new Date(xte));function fg(e,t){let n;try{n=Ste.parse(e).ast}catch(e){return{ok:!1,error:Cte(e)}}let r=[],i=new Set,a=new Set,o=e=>{if(!e||typeof e!=`object`)return;if(Array.isArray(e)){for(let t of e)o(t);return}let n=e;if(n.op===`.`&&Array.isArray(n.args)){let[e,o]=n.args;if(e?.op===`id`&&typeof e.args==`string`){t.has(e.args)?r.push({input:e.args,field:o}):a.has(e.args)||i.add(e.args);return}}if(n.op===`id`&&typeof n.args==`string`)!t.has(n.args)&&!a.has(n.args)&&i.add(n.args);else if(n.op===`rcall`&&Array.isArray(n.args)){let[,e,t]=n.args;o(e);let r=t?.[0],i=r?.op===`id`&&typeof r.args==`string`&&t.length>1?r.args:void 0;i&&a.add(i);for(let e of i?t.slice(1):t??[])o(e);i&&a.delete(i)}else o(n.args)};o(n);let s=new Set;return{ok:!0,refs:r.filter(e=>{let t=`${e.input}.${e.field}`;return!s.has(t)&&(s.add(t),!0)}),unknownInputs:[...i]}}function Cte(e){return(e instanceof Error?e.message:String(e)).split(`
176
- `)[0]??``}function wte(e){return[...new Set(e.map(e=>`then`in e?e.then:e.else))]}function Tte(e,t){let n=[],r=new hu(e),i=t=>ru(e,t),a=e=>t===`imported`===e,o=(e,t,r)=>n.push({severity:`error`,code:e,message:t,location:r}),s=(t,n,r)=>{let s=new Map;for(let[c,l]of Object.entries(n)){let n=tu(e,l);s.set(c,n),a(i(l))&&n.status===`missing`&&o(n.local?`ref/unresolved-data`:`ref/unknown-in-import`,`${t} reads ${c} as "${l}", which ${n.local?`is not defined under data`:`${n.namespace} doesn't have`}.${n.hint?` ${n.hint}`:``}`,r)}return s},c=(e,n,r,i)=>{let s=fg(n,new Set(r.keys()));if(!s.ok)t===`local`&&o(`logic/invalid-expression`,`${e}: "${n}" isn't valid CEL: ${s.error}`,i);else{t===`local`&&s.unknownInputs.length&&o(`logic/unknown-input`,`${e}: "${n}" reads ${s.unknownInputs.join(`, `)}, which ${s.unknownInputs.length===1?`isn't an input`:`aren't inputs`}. Its inputs are ${[...r.keys()].join(`, `)||`none`}.`,i);for(let t of s.refs){let s=r.get(t.input);if(s?.status!==`found`||!a(!s.local))continue;let c=s.node.spec.fields;c&&!c[t.field]&&o(`data/unknown-field`,`${e}: "${n}" reads ${t.input}.${t.field}, but ${s.node.id} has no field "${t.field}".`,i)}}};for(let t of e.mappings.values()){let n=`Mapping "${t.id}"`,l=s(n,t.spec.from,t.location),u=r.target(t.spec.to,e.namespace),d=i(t.spec.to);if(!u)a(d)&&(!d||r.models.has(t.spec.to.split(`.`)[0]??``))&&o(`logic/unknown-target`,`${n} writes to "${t.spec.to}", which is neither a data entry nor a datastore table (element.table) that stores one.`,t.location);else{let i=r.entry(u.entry),s=!u.entry.startsWith(`${e.namespace}.`),c=i?.node.spec.fields;if(c&&a(s))for(let e of Object.keys(t.spec.fields))c[e]||o(`data/unknown-field`,`${n} writes ${e}, but ${i?.node.id} has no field "${e}".`,t.location)}for(let[e,r]of Object.entries(t.spec.fields))c(`${n}, field ${e}`,r,l,t.location)}for(let r of e.logic.values()){let a=`Logic "${r.id}"`,l=s(a,r.spec.input,r.location),u=r.spec[`runs-in`];if(u&&t===`local`&&!i(u)&&!e.elements.has(u.replace(`${e.namespace}.`,``))&&o(`ref/unresolved`,`${a} runs in "${u}", which isn't an element.`,r.location),u&&t===`imported`&&i(u)){let t=u.slice(0,u.indexOf(`.`)),n=e.imported?.get(t);n&&!n.model.elements.has(u.slice(t.length+1))&&o(`ref/unknown-in-import`,`${a} runs in ${u}, which ${t}@${n.version??`?`} doesn't have.`,r.location)}for(let[e,n]of r.spec.rules.entries())`when`in n&&c(`${a}, rule ${e+1}`,n.when,l,r.location),t===`local`&&`else`in n&&e<r.spec.rules.length-1&&o(`logic/unreachable`,`${a}: rule ${e+2} comes after "else", so it never runs. Move else last.`,r.location);t===`local`&&!r.spec.rules.some(e=>`else`in e)&&n.push({severity:`warning`,code:`logic/no-default`,message:`${a} has no else, so a request no rule matches gets no outcome. Add else: <outcome>.`,location:r.location})}for(let n of e.journeys.values()){let e=new Set,s=!1,c=!1;for(let l of n.steps){let u=`Journey "${n.id}", step ${l.index+1}`;if(l.spec.when&&!s&&a(c)&&!e.has(l.spec.when)&&o(`journey/unknown-outcome`,`${u} runs when "${l.spec.when}", but no earlier step decides it.${e.size?` Earlier outcomes: ${[...e].join(`, `)}.`:``}`,l.location),l.spec.decides){let t=l.spec.decides,n=r.logic(t),d=i(t);if(c||=d,n||(s=!0),!n)a(d)&&(!d||r.models.has(t.split(`.`)[0]??``))&&o(`journey/unknown-logic`,`${u} decides with "${t}", which isn't a logic block.`,l.location);else{let r=wte(n.node.spec.rules);for(let t of r)e.add(t);if(a(d))for(let e of Object.keys(l.spec.branches??{}))r.includes(e)||o(`journey/unknown-branch`,`${u} has a branch "${e}", which ${t} never decides. Its outcomes: ${r.join(`, `)}.`,l.location)}}else l.spec.branches&&t===`local`&&o(`journey/unknown-branch`,`${u} has branches but no decides. Name the logic block that picks one.`,l.location);if(l.spec.via){let e=l.spec.via,t=i(e);!r.mapping(e)&&a(t)&&(!t||r.models.has(e.split(`.`)[0]??``))&&o(`journey/unknown-mapping`,`${u} writes via "${e}", which isn't a mapping.`,l.location)}}}return n}function pg(e,t){let n=[],r=e=>t===`imported`===e,i=e=>e.type===`external`?e.ref:e.id,a=(t,i,a)=>{if(!r(ru(e,t)))return;let o=tu(e,t);if(o.status===`found`)return o;if(o.status!==`not-synced`){if(o.local)n.push({severity:`warning`,code:`ref/unresolved-data`,message:`${i} "${t}", which is not defined under data.${o.hint?` ${o.hint}`:``}`,location:a});else{let r=e.imported?.get(o.namespace);n.push({severity:`error`,code:`ref/unknown-in-import`,message:`${i} ${t}, which ${o.namespace}@${r?.version??`?`} doesn't have.${o.hint?` ${o.hint}`:``}`,location:a})}}};for(let t of e.relationships)for(let e of t.sends)a(e,`${t.from.id} → ${t.ref} sends`,t.location);for(let t of e.elements.values()){for(let e of t.spec.provides??[]){let n=`api`in e?e.api:`topic`in e?e.topic:e.event;for(let r of[`accepts`,`returns`,`carries`])for(let i of[e[r]??[]].flat())a(i,`${t.id} provides ${n}, which ${r}`,t.location)}for(let[e,n]of Object.entries(t.spec.stores??{}))a(n.entity,`${t.id} stores ${e} as`,t.location)}if(t===`local`)for(let t of e.data.values()){if(!t.spec.source){let e=Object.entries(t.spec.fields??{}).filter(([,e])=>e.type===void 0);e.length&&n.push({severity:`warning`,code:`data/missing-type`,message:`${t.id} doesn't say the type of ${e.map(([e])=>e).join(`, `)}. Add type, or a source to read it from.`,location:t.location})}let{invalid:e}=ou(t.spec.states??[]);for(let r of e)n.push({severity:`error`,code:`data/invalid-states`,message:`${t.id} has the state line "${r}", which isn't "a -> b" (or "a -> b | c").`,location:t.location})}for(let t of e.journeys.values())for(let e of t.steps){let r=`Journey "${t.id}", step ${e.index+1}`;for(let t of[e.spec.sends??[]].flat())a(t,`${r} sends`,e.location);s(r,e.spec,e.location);for(let[t,n]of Object.entries(e.spec.branches??{}))s(`${r}, when ${t}`,n,e.location);if(e.from&&e.to&&e.spec.sends!==void 0)for(let t of[e.spec.sends].flat()){let a=c(t,e.from,e.to,void 0,!0);a&&n.push({severity:`error`,code:`data/not-accepted`,message:`${r}: ${i(e.from)} → ${i(e.to)} sends ${t}, ${a}`,location:e.location})}}for(let t of e.relationships)for(let e of t.sends){let r=c(e,t.from,t.to,t.via,!1);r&&n.push({severity:`error`,code:`data/not-accepted`,message:`${t.from.id} → ${t.ref} sends ${e}, ${r}`,location:t.location})}let o=gu(e);for(let r of e.journeys.values())for(let a of r.steps){if(!a.from||!a.to||[a.from,a.to].some(t=>t.type===`external`&&!!e.imports[t.namespace])!==(t===`imported`))continue;let s=$l(e);[a.from,a.to].some(e=>e.type===`external`&&!s.has(e.namespace))||yu(e,a,o)||n.push({severity:`warning`,code:`journey/step-without-message`,message:`Journey "${r.id}", step ${a.index+1} (${i(a.from)} → ${i(a.to)}) doesn't say what it sends. Add sends: to the step, or to the relationship it travels along.`,location:a.location})}if(t===`local`){for(let t of e.journeys.values())for(let r of t.steps)if(r.from&&r.to)for(let a of Tu(e,r)){let o=Dte(a.entries.map(t=>Ete(e,t)));n.push({severity:`warning`,code:`journey/step-writes-elsewhere`,message:`Journey "${t.id}", step ${r.index+1} (${i(r.from)} → ${i(r.to)}) also writes ${o} into ${a.store}. Make storing it a step of its own, from ${i(a.writer)} to ${a.store}, and move what it creates and changes there.`,location:r.location})}}return n.push(...Tte(e,t)),n.push(...Fu(e,t)),n;function s(e,r,i){let o=r.creates,s=o===void 0?[]:typeof o==`string`||Array.isArray(o)?[o].flat().map(e=>[e,{}]):Object.entries(o);for(let[t,r]of s){let o=a(t,`${e} creates`,i);if(o)for(let[a,s]of Object.entries(r)){let r=mg(o,a,s===null?void 0:String(s));r&&n.push({...r,message:`${e} creates ${t}: ${r.message}`,location:i})}}for(let[o,s]of Object.entries(r.changes??{})){let r=iu(o);if(!r){t===`local`&&n.push({severity:`error`,code:`data/invalid-change`,message:`${e} changes "${o}". Name the entry and the field, such as Charge.status.`,location:i});continue}let c=a(r.entry,`${e} changes`,i);if(!c)continue;let l=su(s);if(!l){n.push({severity:`error`,code:`data/invalid-change`,message:`${e} changes ${o} to "${s}". Write it as "before -> after".`,location:i});continue}let u=mg(c,r.field,l.from)??mg(c,r.field,l.to);if(u){n.push({...u,message:`${e} changes ${o}: ${u.message}`,location:i});continue}let d=ou(c.node.spec.states??[]);if(!d.states.has(l.from)&&!d.states.has(l.to)||d.next.get(l.from)?.has(l.to))continue;let f=[...d.next.get(l.from)??[]];n.push({severity:`error`,code:`data/invalid-transition`,message:`${e} changes ${o} from ${l.from} to ${l.to}, which ${c.node.id}'s states don't allow.${f.length?` From ${l.from} it can go to ${f.join(`, `)}.`:d.states.has(l.from)?` ${l.from} is a final state.`:` ${l.from} isn't one of its states.`}`,location:i})}}function c(t,n,i,a,o){if(i.type===`actor`||!r(i.type===`external`))return;let s=uu(e,i);if(!s)return;let c=lu(e,i),l=(e,t)=>[e??[]].flat().map(e=>nu(e,t)),u=pu(s,a);if(u&&(`topic`in u||`event`in u))return;let d=u?l(u.accepts,c):s.flatMap(e=>`api`in e?l(e.accepts,c):[]);if(d.length===0||tu(e,t).status===`missing`)return;let f=nu(t,e.namespace);if(!d.includes(f)){if(o){let t=n.type===`actor`?e.namespace:lu(e,n);if((uu(e,n)??[]).flatMap(e=>[...l(e.carries,t),...l(e.returns,t)]).includes(f))return}return`which ${i.type===`external`?i.ref:i.id} doesn't accept${u?` through ${a}`:``}. It accepts: ${d.map(t=>t.startsWith(`${e.namespace}.`)?t.slice(e.namespace.length+1):t).join(`, `)}.`}}}function mg(e,t,n){let r=e.node.spec.fields;if(!r)return;let i=r[t];if(!i)return{severity:`error`,code:`data/unknown-field`,message:`${e.node.id} has no field "${t}".`};if(n!==void 0&&i.values&&!i.values.map(String).includes(n))return{severity:`error`,code:`data/invalid-value`,message:`"${n}" isn't one of ${t}'s values: ${i.values.join(`, `)}.`}}function Ete(e,t){let n=`${e.namespace}.`;return t.startsWith(n)?t.slice(n.length):t}function Dte(e){return e.length<3?e.join(` and `):`${e.slice(0,-1).join(`, `)}, and ${e[e.length-1]}`}function hg(e,t){let n=new um,r=bm(t,{lineCounter:n,prettyErrors:!1,uniqueKeys:!0}),i=t=>{let{line:r,col:i}=n.linePos(t);return{file:e,line:r,column:i}},a=[...r.errors,...r.warnings].map(e=>({severity:r.errors.includes(e)?`error`:`warning`,code:`yaml/syntax`,message:e.message.split(`
176
+ `)[0]??``}function wte(e){return[...new Set(e.map(e=>`then`in e?e.then:e.else))]}function Tte(e,t){let n=[],r=new hu(e),i=t=>ru(e,t),a=e=>t===`imported`===e,o=(e,t,r)=>n.push({severity:`error`,code:e,message:t,location:r}),s=(t,n,r)=>{let s=new Map;for(let[c,l]of Object.entries(n)){let n=tu(e,l);s.set(c,n),a(i(l))&&n.status===`missing`&&o(n.local?`ref/unresolved-data`:`ref/unknown-in-import`,`${t} reads ${c} as "${l}", which ${n.local?`is not defined under data`:`${n.namespace} doesn't have`}.${n.hint?` ${n.hint}`:``}`,r)}return s},c=(e,n,r,i)=>{let s=fg(n,new Set(r.keys()));if(!s.ok)t===`local`&&o(`logic/invalid-expression`,`${e}: "${n}" isn't valid CEL: ${s.error}`,i);else{t===`local`&&s.unknownInputs.length&&o(`logic/unknown-input`,`${e}: "${n}" reads ${s.unknownInputs.join(`, `)}, which ${s.unknownInputs.length===1?`isn't an input`:`aren't inputs`}. Its inputs are ${[...r.keys()].join(`, `)||`none`}.`,i);for(let t of s.refs){let s=r.get(t.input);if(s?.status!==`found`||!a(!s.local))continue;let c=s.node.spec.fields;c&&!c[t.field]&&o(`data/unknown-field`,`${e}: "${n}" reads ${t.input}.${t.field}, but ${s.node.id} has no field "${t.field}".`,i)}}};for(let t of e.mappings.values()){let n=`Mapping "${t.id}"`,l=s(n,t.spec.from,t.location),u=r.target(t.spec.to,e.namespace),d=i(t.spec.to);if(!u)a(d)&&(!d||r.models.has(t.spec.to.split(`.`)[0]??``))&&o(`logic/unknown-target`,`${n} writes to "${t.spec.to}", which is neither a data entry nor a datastore table (element.table) that stores one.`,t.location);else{let i=r.entry(u.entry),s=!u.entry.startsWith(`${e.namespace}.`),c=i?.node.spec.fields;if(c&&a(s))for(let e of Object.keys(t.spec.fields))c[e]||o(`data/unknown-field`,`${n} writes ${e}, but ${i?.node.id} has no field "${e}".`,t.location)}for(let[e,r]of Object.entries(t.spec.fields))c(`${n}, field ${e}`,r,l,t.location)}for(let r of e.logic.values()){let a=`Logic "${r.id}"`,l=s(a,r.spec.input,r.location),u=r.spec[`runs-in`];if(u&&t===`local`&&!i(u)&&!e.elements.has(u.replace(`${e.namespace}.`,``))&&o(`ref/unresolved`,`${a} runs in "${u}", which isn't an element.`,r.location),u&&t===`imported`&&i(u)){let t=u.slice(0,u.indexOf(`.`)),n=e.imported?.get(t);n&&!n.model.elements.has(u.slice(t.length+1))&&o(`ref/unknown-in-import`,`${a} runs in ${u}, which ${t}@${n.version??`?`} doesn't have.`,r.location)}for(let[e,n]of r.spec.rules.entries())`when`in n&&c(`${a}, rule ${e+1}`,n.when,l,r.location),t===`local`&&`else`in n&&e<r.spec.rules.length-1&&o(`logic/unreachable`,`${a}: rule ${e+2} comes after "else", so it never runs. Move else last.`,r.location);t===`local`&&!r.spec.rules.some(e=>`else`in e)&&n.push({severity:`warning`,code:`logic/no-default`,message:`${a} has no else, so a request no rule matches gets no outcome. Add else: <outcome>.`,location:r.location})}for(let n of e.journeys.values()){let e=new Set,s=!1,c=!1;for(let l of n.steps){let u=`Journey "${n.id}", step ${l.index+1}`;if(l.spec.when&&!s&&a(c)&&!e.has(l.spec.when)&&o(`journey/unknown-outcome`,`${u} runs when "${l.spec.when}", but no earlier step decides it.${e.size?` Earlier outcomes: ${[...e].join(`, `)}.`:``}`,l.location),l.spec.decides){let t=l.spec.decides,n=r.logic(t),d=i(t);if(c||=d,n||(s=!0),!n)a(d)&&(!d||r.models.has(t.split(`.`)[0]??``))&&o(`journey/unknown-logic`,`${u} decides with "${t}", which isn't a logic block.`,l.location);else{let r=wte(n.node.spec.rules);for(let t of r)e.add(t);if(a(d))for(let e of Object.keys(l.spec.branches??{}))r.includes(e)||o(`journey/unknown-branch`,`${u} has a branch "${e}", which ${t} never decides. Its outcomes: ${r.join(`, `)}.`,l.location)}}else l.spec.branches&&t===`local`&&o(`journey/unknown-branch`,`${u} has branches but no decides. Name the logic block that picks one.`,l.location);if(l.spec.via){let e=l.spec.via,t=i(e);!r.mapping(e)&&a(t)&&(!t||r.models.has(e.split(`.`)[0]??``))&&o(`journey/unknown-mapping`,`${u} writes via "${e}", which isn't a mapping.`,l.location)}}}return n}function pg(e,t){let n=[],r=e=>t===`imported`===e,i=e=>e.type===`external`?e.ref:e.id,a=(t,i,a)=>{if(!r(ru(e,t)))return;let o=tu(e,t);if(o.status===`found`)return o;if(o.status!==`not-synced`){if(o.local)n.push({severity:`warning`,code:`ref/unresolved-data`,message:`${i} "${t}", which is not defined under data.${o.hint?` ${o.hint}`:``}`,location:a});else{let r=e.imported?.get(o.namespace);n.push({severity:`error`,code:`ref/unknown-in-import`,message:`${i} ${t}, which ${o.namespace}@${r?.version??`?`} doesn't have.${o.hint?` ${o.hint}`:``}`,location:a})}}};for(let t of e.relationships)for(let e of t.sends)a(e,`${t.from.id} → ${t.ref} sends`,t.location);for(let t of e.elements.values()){for(let e of t.spec.provides??[]){let n=`api`in e?e.api:`topic`in e?e.topic:e.event;for(let r of[`accepts`,`returns`,`carries`])for(let i of[e[r]??[]].flat())a(i,`${t.id} provides ${n}, which ${r}`,t.location)}for(let[e,n]of Object.entries(t.spec.stores??{}))a(n.entity,`${t.id} stores ${e} as`,t.location)}if(t===`local`)for(let t of e.data.values()){if(!t.spec.source){let e=Object.entries(t.spec.fields??{}).filter(([,e])=>e.type===void 0);e.length&&n.push({severity:`warning`,code:`data/missing-type`,message:`${t.id} doesn't say the type of ${e.map(([e])=>e).join(`, `)}. Add type, or a source to read it from.`,location:t.location})}let{invalid:e}=ou(t.spec.states??[]);for(let r of e)n.push({severity:`error`,code:`data/invalid-states`,message:`${t.id} has the state line "${r}", which isn't "a -> b" (or "a -> b | c").`,location:t.location})}for(let t of e.journeys.values())for(let e of t.steps){let r=`Journey "${t.id}", step ${e.index+1}`;for(let t of[e.spec.sends??[]].flat())a(t,`${r} sends`,e.location);u(r,e.spec,e.location);for(let[t,n]of Object.entries(e.spec.branches??{}))u(`${r}, when ${t}`,n,e.location);if(e.from&&e.to&&e.spec.sends!==void 0)for(let t of[e.spec.sends].flat()){let a=d(t,e.from,e.to,void 0,!0);a&&n.push({severity:`error`,code:`data/not-accepted`,message:`${r}: ${i(e.from)} → ${i(e.to)} sends ${t}, ${a}`,location:e.location})}}for(let t of e.relationships)for(let e of t.sends){let r=d(e,t.from,t.to,t.via,!1);r&&n.push({severity:`error`,code:`data/not-accepted`,message:`${t.from.id} → ${t.ref} sends ${e}, ${r}`,location:t.location})}let o=gu(e),s=e.data.size>0,c=[];for(let r of e.journeys.values())for(let a of r.steps){if(!a.from||!a.to||[a.from,a.to].some(t=>t.type===`external`&&!!e.imports[t.namespace])!==(t===`imported`))continue;let l=$l(e);[a.from,a.to].some(e=>e.type===`external`&&!l.has(e.namespace))||yu(e,a,o)||(s?n.push({severity:`warning`,code:`journey/step-without-message`,message:`Journey "${r.id}", step ${a.index+1} (${i(a.from)} → ${i(a.to)}) doesn't say what it sends. Add sends: to the step, or to the relationship it travels along.`,location:a.location}):c.push({journey:r.id,step:a.index+1,location:a.location}))}let[l]=c;if(l){let e=new Set(c.map(e=>e.journey)).size;n.push({severity:`info`,code:`journey/step-without-message`,message:`${c.length} journey step${c.length===1?``:`s`} in ${e} journey${e===1?``:`s`} ${c.length===1?`doesn't say what it sends`:`don't say what they send`}, since the model describes no data yet. When it does (data:), add sends: to the steps or the relationships they travel along.`,location:l.location})}if(t===`local`){for(let t of e.journeys.values())for(let r of t.steps)if(r.from&&r.to)for(let a of Tu(e,r)){let o=Dte(a.entries.map(t=>Ete(e,t)));n.push({severity:`warning`,code:`journey/step-writes-elsewhere`,message:`Journey "${t.id}", step ${r.index+1} (${i(r.from)} → ${i(r.to)}) also writes ${o} into ${a.store}. Make storing it a step of its own, from ${i(a.writer)} to ${a.store}, and move what it creates and changes there.`,location:r.location})}}return n.push(...Tte(e,t)),n.push(...Fu(e,t)),n;function u(e,r,i){let o=r.creates,s=o===void 0?[]:typeof o==`string`||Array.isArray(o)?[o].flat().map(e=>[e,{}]):Object.entries(o);for(let[t,r]of s){let o=a(t,`${e} creates`,i);if(o)for(let[a,s]of Object.entries(r)){let r=mg(o,a,s===null?void 0:String(s));r&&n.push({...r,message:`${e} creates ${t}: ${r.message}`,location:i})}}for(let[o,s]of Object.entries(r.changes??{})){let r=iu(o);if(!r){t===`local`&&n.push({severity:`error`,code:`data/invalid-change`,message:`${e} changes "${o}". Name the entry and the field, such as Charge.status.`,location:i});continue}let c=a(r.entry,`${e} changes`,i);if(!c)continue;let l=su(s);if(!l){n.push({severity:`error`,code:`data/invalid-change`,message:`${e} changes ${o} to "${s}". Write it as "before -> after".`,location:i});continue}let u=mg(c,r.field,l.from)??mg(c,r.field,l.to);if(u){n.push({...u,message:`${e} changes ${o}: ${u.message}`,location:i});continue}let d=ou(c.node.spec.states??[]);if(!d.states.has(l.from)&&!d.states.has(l.to)||d.next.get(l.from)?.has(l.to))continue;let f=[...d.next.get(l.from)??[]];n.push({severity:`error`,code:`data/invalid-transition`,message:`${e} changes ${o} from ${l.from} to ${l.to}, which ${c.node.id}'s states don't allow.${f.length?` From ${l.from} it can go to ${f.join(`, `)}.`:d.states.has(l.from)?` ${l.from} is a final state.`:` ${l.from} isn't one of its states.`}`,location:i})}}function d(t,n,i,a,o){if(i.type===`actor`||!r(i.type===`external`))return;let s=uu(e,i);if(!s)return;let c=lu(e,i),l=(e,t)=>[e??[]].flat().map(e=>nu(e,t)),u=pu(s,a);if(u&&(`topic`in u||`event`in u))return;let d=u?l(u.accepts,c):s.flatMap(e=>`api`in e?l(e.accepts,c):[]);if(d.length===0||tu(e,t).status===`missing`)return;let f=nu(t,e.namespace);if(!d.includes(f)){if(o){let t=n.type===`actor`?e.namespace:lu(e,n);if((uu(e,n)??[]).flatMap(e=>[...l(e.carries,t),...l(e.returns,t)]).includes(f))return}return`which ${i.type===`external`?i.ref:i.id} doesn't accept${u?` through ${a}`:``}. It accepts: ${d.map(t=>t.startsWith(`${e.namespace}.`)?t.slice(e.namespace.length+1):t).join(`, `)}.`}}}function mg(e,t,n){let r=e.node.spec.fields;if(!r)return;let i=r[t];if(!i)return{severity:`error`,code:`data/unknown-field`,message:`${e.node.id} has no field "${t}".`};if(n!==void 0&&i.values&&!i.values.map(String).includes(n))return{severity:`error`,code:`data/invalid-value`,message:`"${n}" isn't one of ${t}'s values: ${i.values.join(`, `)}.`}}function Ete(e,t){let n=`${e.namespace}.`;return t.startsWith(n)?t.slice(n.length):t}function Dte(e){return e.length<3?e.join(` and `):`${e.slice(0,-1).join(`, `)}, and ${e[e.length-1]}`}function hg(e,t){let n=new um,r=bm(t,{lineCounter:n,prettyErrors:!1,uniqueKeys:!0}),i=t=>{let{line:r,col:i}=n.linePos(t);return{file:e,line:r,column:i}},a=[...r.errors,...r.warnings].map(e=>({severity:r.errors.includes(e)?`error`:`warning`,code:`yaml/syntax`,message:e.message.split(`
177
177
  `)[0]??e.message,location:i(e.pos[0])}));return r.errors.length>0?{diagnostics:a}:{parsed:{file:e,doc:r,value:r.toJS(),locate:t=>{for(let e=t.length;e>0;e--){let n=e===1?r.contents:r.getIn(t.slice(0,e-1),!0),a=t[e-1];if(Qu(n)){let e=n.items.find(e=>String(ed(e.key)?e.key.value:e.key)===String(a)),t=e?.key??e?.value;if(t?.range)return i(t.range[0])}else if(td(n)&&typeof a==`number`){let e=n.items[a];if(e?.range)return i(e.range[0])}}return{file:e,line:1,column:1}}},diagnostics:a}}var gg=`(landscape)`,Ote=[`namespace`,`name`,`description`,`imports`,`landscape`];function _g(e,t={}){let n=[],r={namespace:``,imports:{},actors:new Map,elements:new Map,journeys:new Map,data:new Map,mappings:new Map,logic:new Map,rules:[],relationships:[],files:e.map(e=>e.path),diagnostics:n},i=t.root??e.find(e=>/(^|[/\\])archdoc\.ya?ml$/.test(e.path))?.path??e[0]?.path;if(!i)return n.push({severity:`error`,code:`model/not-found`,message:`No model files found. Create .archdoc/archdoc.yaml.`}),r;let a=!1,o=[],s=[],c=new Map;for(let t of e){let e=t.path===i,{parsed:c,diagnostics:l}=hg(t.path,t.text);if(n.push(...l),!c){a=!0;continue}let f=c.value;if(f==null){e&&n.push(Sg(`model/missing-root-field`,`The root file is empty.`,c,[]));continue}if(Tl(f)){a=!0,n.push(Sg(`spec/v1-model`,`This is a v1 model (users/components). Run "archdoc migrate" to convert it to v2.`,c,[`archdoc`]));continue}let p=typeof f==`object`&&`journey`in f,m=p?ll.safeParse(f):cl.safeParse(f);if(!m.success){a=!0,n.push(...wg(m.error,c));continue}if(p){let{journey:e,$schema:t,archdoc:n,...r}=m.data;d(e,r,c,[]);continue}let h=m.data;if(e)h.archdoc||n.push(Sg(`model/missing-root-field`,`The root file needs archdoc: "2.0".`,c,[])),h.namespace||n.push(Sg(`model/missing-root-field`,`The root file needs a namespace, such as namespace: payments. It makes IDs unique across repos.`,c,[])),r.namespace=h.namespace??``,r.name=h.name,r.description=h.description,r.imports=h.imports??{},r.importLocations=new Map(Object.keys(r.imports).map(e=>[e,c.locate([`imports`,e])])),h.landscape&&(r.landscapeImport=h.landscape,r.importLocations.set(gg,c.locate([`landscape`])));else for(let e of Ote)h[e]!==void 0&&n.push(Sg(`model/root-only-field`,`"${e}" can only be set in the root file (${i}).`,c,[e]));for(let[e,t]of Object.entries(h.actors??{})){let i=[`actors`,e];if(r.actors.has(e)){n.push(Cg(`actor`,e,c,i,r.actors.get(e)?.location));continue}let a={type:`actor`,id:e,spec:t,location:c.locate(i)};r.actors.set(e,a),t.uses&&o.push({from:a,uses:t.uses,file:c,path:i})}u(h.elements??{},void 0,c,[`elements`],0);for(let[e,t]of Object.entries(h.journeys??{}))d(e,t,c,[`journeys`,e]);for(let[e,t]of Object.entries(h.data??{})){let i=[`data`,e];r.data.has(e)?n.push(Cg(`data entry`,e,c,i,r.data.get(e)?.location)):(r.data.set(e,{id:e,spec:t,location:c.locate(i)}),t.owners&&s.push({owners:t.owners,file:c,path:i}))}for(let[e,t,i]of[[`mappings`,`mapping`,r.mappings],[`logic`,`logic block`,r.logic]])for(let[r,a]of Object.entries(h[e]??{})){let o=[e,r];i.has(r)?n.push(Cg(t,r,c,o,i.get(r)?.location)):i.set(r,{id:r,spec:a,location:c.locate(o)})}for(let[e,t]of Object.entries(h.logic??{}))t.owners&&s.push({owners:t.owners,file:c,path:[`logic`,e]});for(let[e,t]of(h.rules??[]).entries())r.rules.some(e=>e.id===t.id)?n.push(Sg(`model/duplicate`,`Rule "${t.id}" is defined twice.`,c,[`rules`,e])):r.rules.push(t);for(let[e,t]of Object.entries(h.domains??{}))r.domains?.has(e)?n.push(Sg(`model/duplicate`,`Domain "${e}" is defined twice.`,c,[`domains`,e])):(r.domains??=new Map,r.domains.set(e,{id:e,spec:t,location:c.locate([`domains`,e])}))}if(a)return n.push({severity:`info`,code:`model/incomplete`,message:`Reference and journey checks were skipped. Fix the errors above, then validate again.`}),r;let l=new Kl(r.namespace,new Set(Object.keys(r.imports)),new Set(r.elements.keys()),new Set(r.actors.keys()));for(let e of o)for(let[t,i]of Object.entries(e.uses)){let a=[...e.path,`uses`,t],o=e.file.locate(a),s=l.element(t,e.scope);if(s.status===`resolved`||s.status===`external`){let n=typeof i==`string`?{description:i}:i??{};r.relationships.push({from:{type:e.from.type,id:e.from.id},to:s.target,ref:t,description:n.description,technology:n.technology,via:n.via,transport:n.transport,status:n.status??`active`,sends:n.sends===void 0?[]:[n.sends].flat(),provenance:n.provenance,location:o})}else s.status===`unresolved`&&l.actor(t).status===`resolved`?n.push({severity:`error`,code:`ref/uses-actor`,message:`"${t}" is an actor. "uses" can only point to elements. To show an element serving an actor, add uses to the actor instead.`,location:o,path:a.join(`.`)}):n.push(jte(s,`${e.from.id} uses "${t}"`,o,a))}for(let e of s)for(let[t,r]of e.owners.entries()){let i=l.actor(r);i.status!==`resolved`&&i.status!==`external`&&n.push({severity:`warning`,code:`ref/unresolved-owner`,message:`Owner "${r}" is not an actor in this model. Add it under actors (usually kind: team), or import a landscape that defines it.`,location:e.file.locate([...e.path,`owners`,t]),path:[...e.path,`owners`,t].join(`.`)})}return Ate(r),kte(r,l),n.push(...Sm(r,l,c)),n.push(...pg(r,`local`)),r;function u(e,t,i,a,c){let l=[];for(let[d,f]of Object.entries(e)){let e=t?`${t}.${d}`:d,p=[...a,d];if(r.elements.has(e)){n.push(Cg(`element`,e,i,p,r.elements.get(e)?.location));continue}let m={type:`element`,id:e,key:d,parentId:t,childIds:[],depth:c,spec:f,code:xg(f.code),location:i.locate(p)};r.elements.set(e,m),l.push(e),f.uses&&o.push({from:m,uses:f.uses,scope:t,file:i,path:p}),f.owners&&s.push({owners:f.owners,file:i,path:p}),m.childIds=u(f.elements??{},e,i,[...p,`elements`],c+1)}return l}function d(e,t,i,a){r.journeys.has(e)?n.push(Cg(`journey`,e,i,a,r.journeys.get(e)?.location)):(r.journeys.set(e,{id:e,spec:t,steps:t.steps.map((e,t)=>({index:t,spec:e,location:i.locate([...a,`steps`,t])})),location:i.locate(a.length?a:[`journey`])}),c.set(e,{file:i,path:a}),t.owners&&s.push({owners:t.owners,file:i,path:a}))}}function kte(e,t){for(let n of e.domains?.values()??[]){for(let t of n.spec.namespaces??[])t===e.namespace||e.imports[t]||e.diagnostics.push({severity:`warning`,code:`ref/unknown-domain-member`,message:`Domain "${n.id}" lists namespace "${t}", which isn't imported. Add it to imports.`,location:n.location});for(let r of n.spec.elements??[]){let i=t.element(r);i.status!==`resolved`&&i.status!==`external`&&e.diagnostics.push({severity:`warning`,code:`ref/unknown-domain-member`,message:`Domain "${n.id}" lists "${r}", which isn't an element here or in an imported namespace.`,location:n.location})}}}function Ate(e){for(let t of e.relationships){if(!t.via||t.to.type!==`element`)continue;let n=vg(t,e.elements.get(t.to.id)?.spec.provides,t.to.id);n&&e.diagnostics.push(n)}}function vg(e,t,n){let r=(t??[]).find(t=>bg(t)===e.via);if(!r){let r=(t??[]).map(bg);return{severity:`error`,code:`ref/unknown-contract`,message:`${e.from.id} uses ${n} via "${e.via}", but ${n} doesn't provide it.${r.length?` It provides: ${r.join(`, `)}.`:` It provides nothing.`}`,location:e.location}}if(r.status===`deprecated`)return{severity:`warning`,code:`ref/deprecated-contract`,message:`${e.from.id} uses ${n} via "${e.via}", which is deprecated.`,location:e.location}}function yg(e,t){return(e??[]).some(e=>bg(e)===t&&(`topic`in e||`event`in e))}function bg(e){return`api`in e?e.api:`topic`in e?e.topic:e.event}function xg(e){return e===void 0?[]:[e].flat().map(e=>{if(typeof e==`string`)return{path:e};let{lines:t,...n}=e;return t===void 0?n:{...n,lines:String(t)}})}function Sg(e,t,n,r){return{severity:`error`,code:e,message:t,location:n.locate(r),path:r.join(`.`)||void 0}}function Cg(e,t,n,r,i){let a=i?` (first defined at ${i.file}:${i.line})`:``;return Sg(`model/duplicate`,`${Mte(e)} "${t}" is defined twice${a}.`,n,r)}function jte(e,t,n,r){return e.status===`ambiguous`?{severity:`error`,code:`ref/ambiguous`,message:`${t} could mean ${e.candidates.join(` or `)}. Use a longer path.`,location:n,path:r.join(`.`)}:{severity:`error`,code:`ref/unresolved`,message:`${t}, which doesn't exist.${e.hint?` ${e.hint}`:``}`,location:n,path:r.join(`.`)}}function wg(e,t){let n=[];for(let r of e.issues){let e=r.path.filter(e=>typeof e!=`symbol`);if(r.code===`unrecognized_keys`){for(let i of r.keys)n.push(Sg(`schema/unknown-field`,`Unknown field "${i}".`,t,[...e,i]));continue}let i=r.message;if(r.code===`invalid_key`){let t=r.issues.map(e=>e.message).join(`; `);i=`Invalid ID "${String(e.at(-1))}": ${t}`}else r.code===`invalid_union`&&e.length>0?i=`Invalid value for "${String(e.at(-1))}".`:e.length>0&&!t.doc.hasIn(e)&&(i=`Missing required field "${String(e.at(-1))}".`);n.push(Sg(`schema/invalid`,i,t,e))}return n}function Mte(e){return e.charAt(0).toUpperCase()+e.slice(1)}var Nte=/(^|\/)(test|tests|__tests__)\/|\.(test|spec)\.[cm]?[jt]sx?$/,Pte=/(^|\/)(node_modules|dist|build|coverage|\.archdoc|\.changeset)\/|(^|\/)(pnpm-lock\.yaml|package-lock\.json|yarn\.lock|CHANGELOG\.md)$/;function Fte(e){let t=[];for(let n of e.elements.values()){if(n.code.length===0)continue;let e=n.code.filter(e=>!zl(e));e.length&&t.push({key:`element:${n.id}`,label:`element ${n.id}`,kind:`structure`,refs:e.map(e=>e.path),location:n.location,element:n.id});for(let e of n.code.filter(zl)){let r=[e.lines,e.symbol].filter(Boolean).join(`:`);t.push({key:`element:${n.id}#${e.path}:${r}`,label:`element ${n.id}, ${Rl(e)}`,kind:`content`,refs:[Rl(e)],location:n.location,element:n.id})}for(let e of n.spec.provides??[]){let r=`api`in e?e.api:void 0;r&&/\.[a-z]+$/i.test(r)&&t.push({key:`contract:${n.id}#${r}`,label:`contract ${r} of ${n.id}`,kind:`content`,refs:[r],location:n.location,element:n.id})}}for(let n of e.journeys.values())for(let e of n.steps)e.spec.code&&t.push({key:`step:${n.id}#${e.index+1}`,label:`journey ${n.id}, step ${e.index+1}`,kind:`structure`,refs:[e.spec.code.replace(/:\d+(-\d+)?$/,``)],location:e.location??n.location});for(let[n,r]of[[`logic`,e.logic],[`mapping`,e.mappings]])for(let e of r.values()){let r=xg(e.spec.code);r.length&&t.push({key:`${n}:${e.id}`,label:`${n===`logic`?`decision`:`mapping`} ${e.id}`,kind:`content`,refs:r.map(Rl),location:e.location})}for(let n of e.data.values())n.spec.source&&Object.keys(n.spec.source).length!==0&&t.push({key:`data:${n.id}`,label:`data entry ${n.id}`,kind:`schema`,refs:Object.entries(n.spec.source).map(([e,t])=>`${e} ${t}`),location:n.location});return t.sort((e,t)=>e.key.localeCompare(t.key))}function Ite(e,t){let n=t.files.map(Al),r=Fl(e,n).files,i=new Map((t.index?.sources??[]).map(e=>[e.path,e.exports.map(e=>e.name).sort()])),a=e=>{let t={};for(let n of[...new Set(e)].filter(e=>!Pte.test(e)&&!Nte.test(e)).sort())t[n]=i.get(n)??[];return{kind:`structure`,hash:Tg(JSON.stringify(t)),files:t}},o=[];for(let i of Fte(e)){let s=[],c;if(i.key.startsWith(`element:`)&&i.kind===`structure`)c=a(r.get(i.element??``)??[]);else if(i.key.startsWith(`step:`)){let e=Al(i.refs[0]??``),t=n.filter(t=>t===e||Ol(e).test(t));t.length||s.push(`${e} matches no file`),c=a(t)}else if(i.kind===`schema`){let e=i.key.slice(5),n={};for(let r of t.schemas??[])if(r.data===e){r.error&&s.push(r.error);for(let[e,t]of Object.entries(r.fields??{}))n[e]=t.values?.length?`${t.type} (${t.values.join(`, `)})`:t.type}c={kind:`schema`,hash:Tg(JSON.stringify(Eg(n))),fields:Eg(n)}}else{let r=i.key.startsWith(`element:`)?e.elements.get(i.element??``)?.code.filter(e=>Rl(e)===i.refs[0])??[]:i.key.startsWith(`contract:`)?[{path:i.refs[0]??``}]:xg((i.key.startsWith(`logic:`)?e.logic.get(i.key.slice(6)):e.mappings.get(i.key.slice(8)))?.spec.code),a={};for(let e of r){let r=Rl(e),i=Vte(e,n,t.read);if(typeof i==`object`){s.push(`${r} ${i.problem}`),a[r]={hash:`missing`,lines:0};continue}let o=Hte(i);a[r]={hash:Tg(o),lines:o?o.split(`
178
178
  `).length:0}}c={kind:`content`,hash:Tg(JSON.stringify(Object.entries(a).map(([e,t])=>[e,t.hash]))),refs:a}}o.push({fact:i,seal:c,problems:s})}return o}function Lte(e,t){return e.map(({fact:e,seal:n,problems:r})=>{let i=t?.seals[e.key];return i?i.hash===n.hash?{fact:e,state:`sealed`,current:n,recorded:i,changes:[],problems:r}:{fact:e,state:`changed`,current:n,recorded:i,changes:Rte(i,n),problems:r}:{fact:e,state:`unsealed`,current:n,changes:[],problems:r}})}function Rte(e,t){let n=[];if(e.kind!==t.kind)return[`now fingerprinted by ${t.kind}, was ${e.kind}`];if(t.kind===`structure`){let r=e.files??{},i=t.files??{};for(let e of Object.keys(i).filter(e=>!(e in r)))n.push(`+ ${e}`);for(let e of Object.keys(r).filter(e=>!(e in i)))n.push(`- ${e}`);for(let e of Object.keys(i).filter(e=>e in r)){let t=new Set(r[e]),a=new Set(i[e]),o=[...a].filter(e=>!t.has(e)),s=[...t].filter(e=>!a.has(e));(o.length||s.length)&&n.push(`${e}: ${[...o.map(e=>`exports ${e}`),...s.map(e=>`no longer exports ${e}`)].join(`, `)}`)}}else if(t.kind===`content`){let r=e.refs??{},i=t.refs??{};for(let[e,t]of Object.entries(i)){let i=r[e];i?t.hash===`missing`&&i.hash!==`missing`?n.push(`${e} is gone`):t.hash!==i.hash&&n.push(`${e} changed${i.lines===t.lines?``:` (${i.lines} → ${t.lines} lines)`}`):n.push(`+ ${e}`)}for(let e of Object.keys(r).filter(e=>!(e in i)))n.push(`- ${e}`)}else{let r=e.fields??{},i=t.fields??{};for(let e of Object.keys(i).filter(e=>!(e in r)))n.push(`+ ${e} (${i[e]})`);for(let e of Object.keys(r).filter(e=>!(e in i)))n.push(`- ${e}`);for(let e of Object.keys(i).filter(e=>e in r&&r[e]!==i[e]))n.push(`${e}: ${r[e]} → ${i[e]}`)}return n.length?n:[`changed`]}function zte(e,t){let n=[];for(let r of e){if(r.state===`sealed`)continue;let e=[t,...r.fact.location?[r.fact.location.file]:[]];r.state===`changed`?n.push({severity:`warning`,code:`seal/changed`,message:`The code behind ${r.fact.label} changed since it was sealed (${r.changes.slice(0,3).join(`; `)}${r.changes.length>3?`; and ${r.changes.length-3} more`:``}). Check that the model still describes it, update it if not, then run archdoc seal ${r.fact.key}.`,element:r.fact.element,evidence:r.fact.refs,details:r.changes.length>3||r.problems.length?[...r.changes,...r.problems]:void 0,files:e,location:r.fact.location}):n.push({severity:`warning`,code:`seal/unsealed`,message:`${Ute(r.fact.label)} points at code no one has sealed. Check that the model describes ${r.fact.refs.join(`, `)}, then run archdoc seal ${r.fact.key}.`,element:r.fact.element,evidence:r.fact.refs,files:e,location:r.fact.location})}return n}function Bte(e){try{let t=Dl.safeParse(xm(e));if(t.success)return{sum:t.data};let n=t.error.issues[0];return{error:`${n?.path.join(`.`)||`root`}: ${n?.message}`}}catch(e){return{error:e instanceof Error?e.message:String(e)}}}function Vte(e,t,n){let r=Al(e.path);if(!t.includes(r))return{problem:`matches no file`};let i=n(r);if(i===void 0)return{problem:`can't be read`};if(!zl(e))return i;let a=Bl(e,i);return`problem`in a?{problem:a.problem}:a.text}function Hte(e){return e.replace(/\r\n?/g,`
179
179
  `).split(`
package/web/index.html CHANGED
@@ -5,7 +5,7 @@
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
6
  <link rel="icon" href="./favicon.svg" type="image/svg+xml" />
7
7
  <title>ArchDoc Explorer</title>
8
- <script type="module" crossorigin src="./assets/index-RPBTPN2V.js"></script>
8
+ <script type="module" crossorigin src="./assets/index-eAN2z5Hl.js"></script>
9
9
  <link rel="stylesheet" crossorigin href="./assets/index-CdX9OPsn.css">
10
10
  </head>
11
11
  <body>