@crustjs/core 0.0.15 → 0.0.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -124,6 +124,8 @@ interface BooleanFlagDef extends SingleFlagBase {
124
124
  type: "boolean";
125
125
  /** Default boolean value */
126
126
  default?: boolean;
127
+ /** When `true`, hide the generated `--no-{name}` help label */
128
+ noNegate?: true;
127
129
  }
128
130
  /** Base for multi-value flags — `multiple` is required as `true` */
129
131
  interface MultiFlagBase extends FlagDefBase {
@@ -147,6 +149,8 @@ interface BooleanMultiFlagDef extends MultiFlagBase {
147
149
  type: "boolean";
148
150
  /** Default boolean array value */
149
151
  default?: boolean[];
152
+ /** When `true`, hide the generated `--no-{name}` help label */
153
+ noNegate?: true;
150
154
  }
151
155
  /**
152
156
  * Defines a single named flag for a CLI command.
@@ -789,6 +793,23 @@ declare class Crust<
789
793
  */
790
794
  command(builder: Crust<any, any, any>): Crust<Inherited, Local, A, Eff>;
791
795
  /**
796
+ * Build a frozen, validated copy of the command tree after running plugin
797
+ * `setup()` hooks. Does not mutate this builder or call command handlers.
798
+ *
799
+ * Use for documentation generators (e.g. man pages) that need the same
800
+ * tree shape as runtime, including flags injected by plugins.
801
+ *
802
+ * @param options - Optional synthetic `argv` passed to `setup()` (defaults to `[]`)
803
+ * @returns The cloned root node and any plugin-setup warnings
804
+ * @throws {CrustError} When the tree fails validation (same as `execute()`)
805
+ */
806
+ prepareCommandTree(options?: {
807
+ argv?: readonly string[];
808
+ }): Promise<{
809
+ root: CommandNode;
810
+ warnings: readonly string[];
811
+ }>;
812
+ /**
792
813
  * Parse `process.argv`, resolve subcommands, run plugins and middleware,
793
814
  * and execute the matched command handler.
794
815
  *
package/dist/index.js CHANGED
@@ -1,2 +1,2 @@
1
1
  // @bun
2
- import{a as A,b as $,c as B,d as S}from"./shared/chunk-vt64gs69.js";function I(j){return{meta:{name:j},localFlags:{},effectiveFlags:{},args:void 0,subCommands:{},plugins:[],preRun:void 0,run:void 0,postRun:void 0}}function X(j,q){let J={};for(let[Q,G]of Object.entries(j))if(G.inherit===!0)J[Q]=G;for(let[Q,G]of Object.entries(q))J[Q]=G;return J}function D(j,q){let J=[j.meta.name],Q=j,G=q;while(G.length>0){let H=Q.subCommands;if(!H||Object.keys(H).length===0)break;let Z=G[0];if(!Z||Z.startsWith("-"))break;if(Z in H&&H[Z]){Q=H[Z],J.push(Z),G=G.slice(1);continue}if(Q.run)break;let Y=Object.keys(H);throw new $("COMMAND_NOT_FOUND",`Unknown command "${Z}".`,{input:Z,available:Y,commandPath:[...J],parentCommand:Q})}return{command:Q,argv:G,commandPath:J}}function F(j){for(let[q,J]of Object.entries(j)){if(q.startsWith("no-")){let Q=q.slice(3);throw new $("DEFINITION",`Flag "--${q}" must not use "no-" prefix; define "${Q}" and negate with "--no-${Q}"`)}if(J.short?.startsWith("no-"))throw new $("DEFINITION",`Short alias "-${J.short}" on "--${q}" must not use "no-" prefix (reserved for negation)`);if(J.aliases){for(let Q of J.aliases)if(Q.startsWith("no-"))throw new $("DEFINITION",`Alias "--${Q}" on "--${q}" must not use "no-" prefix (reserved for negation)`)}}}var P="CRUST_INTERNAL_VALIDATE_ONLY",_=130,k="__CRUST_VALIDATE_RESULT__";function w(){let j=new Map;return{get(q){return j.get(q)},has(q){return j.has(q)},set(q,J){j.set(q,J)},delete(q){return j.delete(q)}}}function L(j){if(!(j instanceof Error))return!1;return j.name==="CancelledError"}function O(j,q){j.effectiveFlags=X(q,j.localFlags);for(let J of Object.values(j.subCommands))O(J,j.effectiveFlags)}function N(j){return{addFlag(q,J,Q){if(J in q.effectiveFlags)j?.push(`Plugin flag "--${J}" on "${q.meta.name}" overrides existing flag`);q.effectiveFlags[J]=Q},addSubCommand(q,J,Q){if(!J.trim())throw new $("DEFINITION","addSubCommand: name must be a non-empty string");if(q.subCommands[J]){j?.push(`Plugin subcommand "${J}" on "${q.meta.name}" skipped (already exists)`);return}O(Q,q.effectiveFlags),q.subCommands[J]=Q}}}async function b(j,q,J){for(let Q of j){if(!Q.setup)continue;await Q.setup(q,J)}}async function T(j,q,J){let Q=j.map((Z)=>Z.middleware).filter((Z)=>Boolean(Z)),G=-1,H=async(Z)=>{if(Z<=G)throw new $("DEFINITION","Plugin middleware called next() multiple times");if(G=Z,Z===Q.length){await J();return}let Y=Q[Z];if(!Y)throw new $("DEFINITION","Plugin middleware stack is invalid");await Y(q,()=>H(Z+1))};await H(0)}function x(j){let q=[...j.plugins];for(let J of Object.values(j.subCommands))q.push(...x(J));return q}function y(j){if(Object.freeze(j),Object.freeze(j.localFlags),Object.freeze(j.effectiveFlags),Object.freeze(j.meta),Object.freeze(j.plugins),j.args)Object.freeze(j.args);for(let q of Object.values(j.subCommands))y(q);Object.freeze(j.subCommands)}class R{_node;_inheritedFlags;constructor(j){if(!j.trim())throw new $("DEFINITION","meta.name must be a non-empty string");this._node=I(j),this._inheritedFlags={}}static _createChild(j,q){let J=new R(j);return J._inheritedFlags=q,J}_clone(j){let q=Object.create(Object.getPrototypeOf(this)),J={...this._node,localFlags:{...this._node.localFlags},effectiveFlags:{...this._node.effectiveFlags},subCommands:{...this._node.subCommands},plugins:[...this._node.plugins],meta:{...this._node.meta},args:this._node.args?[...this._node.args]:void 0,...j};return q._node=J,q._inheritedFlags=this._inheritedFlags,q}meta(j){return this._clone({meta:{...this._node.meta,...j}})}flags(j){F(j);let q={};for(let[J,Q]of Object.entries(j))q[J]={...Q};return this._clone({localFlags:q,effectiveFlags:X(this._inheritedFlags,q)})}args(j){let q=j.map((J)=>({...J}));return this._clone({args:q})}run(j){return this._clone({run:j})}preRun(j){return this._clone({preRun:j})}postRun(j){return this._clone({postRun:j})}use(j){return this._clone({plugins:[...this._node.plugins,j]})}sub(j){if(!j.trim())throw new $("DEFINITION","Subcommand name must be a non-empty string");let q=X(this._inheritedFlags,this._node.localFlags);return R._createChild(j,q)}command(j,q){if(typeof j==="string"){let H=j;if(!q)throw new $("DEFINITION","command(name, cb) requires a callback");if(!H.trim())throw new $("DEFINITION","Subcommand name must be a non-empty string");if(this._node.subCommands[H])throw new $("DEFINITION",`Subcommand "${H}" is already registered`);let Z=X(this._inheritedFlags,this._node.localFlags),Y=R._createChild(H,Z),z=q(Y),W={...z._node,effectiveFlags:X(z._inheritedFlags,z._node.localFlags)};return this._clone({subCommands:{...this._node.subCommands,[H]:W}})}let J=j,Q=J._node.meta.name;if(!Q.trim())throw new $("DEFINITION","Subcommand name must be a non-empty string");if(this._node.subCommands[Q])throw new $("DEFINITION",`Subcommand "${Q}" is already registered`);let G={...J._node,effectiveFlags:X(J._inheritedFlags,J._node.localFlags)};return this._clone({subCommands:{...this._node.subCommands,[Q]:G}})}async execute(j){let q=j?.argv??process.argv.slice(2),J=this._node,Q=x(J),G=[],H=w(),Z={argv:[...q],rootCommand:J,state:H},Y=N(G);try{await b(Q,Z,Y)}catch(W){if(L(W)){process.exitCode=_;return}if(W instanceof $){console.error(`Error: ${W.message}`),process.exitCode=1;return}let K=W instanceof Error?W.message:String(W);console.error(`Error: ${K}`),process.exitCode=1;return}if(y(J),process.env[P]==="1"){let W=(async()=>{try{let{validateCommandTree:K}=await import("./shared/chunk-5apf3vnv.js");K(J);for(let U of G)console.warn(`Warning: ${U}`);return{ok:!0}}catch(K){let U=K instanceof Error?K.message:String(K);return console.error(U),process.exitCode=1,{ok:!1,error:K}}})();return globalThis[k]=W,await W,process.exit(process.exitCode??0)}for(let W of G)console.warn(`Warning: ${W}`);let z={argv:[...q],rootCommand:J,state:H,route:null,input:null};try{let W,K;try{let U=D(J,[...q]);z.route=U,W=U.command,K=B(W,U.argv),z.input=K}catch(U){await T(Q,z,async()=>{throw U});return}await T(Q,z,async()=>{if(S(W,K),!W.run)return;let U={args:K.args,flags:K.flags,rawArgs:K.rawArgs,command:W},V;try{if(W.preRun)await W.preRun(U);await W.run(U)}catch(M){V=M}if(W.postRun)try{await W.postRun(U)}catch(M){if(!V)V=M;else console.error(`Error in postRun: ${M instanceof Error?M.message:String(M)}`)}if(V)throw V})}catch(W){if(L(W)){process.exitCode=_;return}if(W instanceof $){console.error(`Error: ${W.message}`),process.exitCode=1;return}if(W instanceof Error){let K=new $("EXECUTION",W.message).withCause(W);console.error(`Error: ${K.message}`),process.exitCode=1;return}console.error(`Error: ${String(W)}`),process.exitCode=1}}}export{S as validateParsed,D as resolveCommand,B as parseArgs,P as VALIDATION_MODE_ENV,$ as CrustError,R as Crust};
2
+ import{a as O,b as G,c as L,d as S}from"./shared/chunk-vt64gs69.js";function T(j){return{meta:{name:j},localFlags:{},effectiveFlags:{},args:void 0,subCommands:{},plugins:[],preRun:void 0,run:void 0,postRun:void 0}}function z(j,q){let J={};for(let[Q,$]of Object.entries(j))if($.inherit===!0)J[Q]=$;for(let[Q,$]of Object.entries(q))J[Q]=$;return J}function D(j,q){let J=[j.meta.name],Q=j,$=q;while($.length>0){let K=Q.subCommands;if(!K||Object.keys(K).length===0)break;let Z=$[0];if(!Z||Z.startsWith("-"))break;if(Z in K&&K[Z]){Q=K[Z],J.push(Z),$=$.slice(1);continue}if(Q.run)break;let H=Object.keys(K);throw new G("COMMAND_NOT_FOUND",`Unknown command "${Z}".`,{input:Z,available:H,commandPath:[...J],parentCommand:Q})}return{command:Q,argv:$,commandPath:J}}function N(j){for(let[q,J]of Object.entries(j)){if(q.startsWith("no-")){let Q=q.slice(3);throw new G("DEFINITION",`Flag "--${q}" must not use "no-" prefix; define "${Q}" and negate with "--no-${Q}"`)}if(J.short?.startsWith("no-"))throw new G("DEFINITION",`Short alias "-${J.short}" on "--${q}" must not use "no-" prefix (reserved for negation)`);if(J.aliases){for(let Q of J.aliases)if(Q.startsWith("no-"))throw new G("DEFINITION",`Alias "--${Q}" on "--${q}" must not use "no-" prefix (reserved for negation)`)}}}var w="CRUST_INTERNAL_VALIDATE_ONLY",P=130,v="__CRUST_VALIDATE_RESULT__";function x(){let j=new Map;return{get(q){return j.get(q)},has(q){return j.has(q)},set(q,J){j.set(q,J)},delete(q){return j.delete(q)}}}function B(j){if(!(j instanceof Error))return!1;return j.name==="CancelledError"}function b(j,q){j.effectiveFlags=z(q,j.localFlags);for(let J of Object.values(j.subCommands))b(J,j.effectiveFlags)}function y(j){return{addFlag(q,J,Q){if(J in q.effectiveFlags)j?.push(`Plugin flag "--${J}" on "${q.meta.name}" overrides existing flag`);q.effectiveFlags[J]=Q},addSubCommand(q,J,Q){if(!J.trim())throw new G("DEFINITION","addSubCommand: name must be a non-empty string");if(q.subCommands[J]){j?.push(`Plugin subcommand "${J}" on "${q.meta.name}" skipped (already exists)`);return}b(Q,q.effectiveFlags),q.subCommands[J]=Q}}}async function A(j,q,J){for(let Q of j){if(!Q.setup)continue;await Q.setup(q,J)}}async function F(j,q,J){let Q=j.map((Z)=>Z.middleware).filter((Z)=>Boolean(Z)),$=-1,K=async(Z)=>{if(Z<=$)throw new G("DEFINITION","Plugin middleware called next() multiple times");if($=Z,Z===Q.length){await J();return}let H=Q[Z];if(!H)throw new G("DEFINITION","Plugin middleware stack is invalid");await H(q,()=>K(Z+1))};await K(0)}function I(j){let q=[...j.plugins];for(let J of Object.values(j.subCommands))q.push(...I(J));return q}function k(j){let q={};for(let[J,Q]of Object.entries(j))q[J]={...Q,aliases:Q.aliases?[...Q.aliases]:void 0};return q}function h(j){let q={};for(let[J,Q]of Object.entries(j.subCommands))q[J]=h(Q);return{meta:{...j.meta},localFlags:k(j.localFlags),effectiveFlags:k(j.effectiveFlags),args:j.args?j.args.map((J)=>({...J})):void 0,subCommands:q,plugins:[...j.plugins],preRun:j.preRun,run:j.run,postRun:j.postRun}}function _(j){if(Object.freeze(j),Object.freeze(j.localFlags),Object.freeze(j.effectiveFlags),Object.freeze(j.meta),Object.freeze(j.plugins),j.args)Object.freeze(j.args);for(let q of Object.values(j.subCommands))_(q);Object.freeze(j.subCommands)}class R{_node;_inheritedFlags;constructor(j){if(!j.trim())throw new G("DEFINITION","meta.name must be a non-empty string");this._node=T(j),this._inheritedFlags={}}static _createChild(j,q){let J=new R(j);return J._inheritedFlags=q,J}_clone(j){let q=Object.create(Object.getPrototypeOf(this)),J={...this._node,localFlags:{...this._node.localFlags},effectiveFlags:{...this._node.effectiveFlags},subCommands:{...this._node.subCommands},plugins:[...this._node.plugins],meta:{...this._node.meta},args:this._node.args?[...this._node.args]:void 0,...j};return q._node=J,q._inheritedFlags=this._inheritedFlags,q}meta(j){return this._clone({meta:{...this._node.meta,...j}})}flags(j){N(j);let q={};for(let[J,Q]of Object.entries(j))q[J]={...Q};return this._clone({localFlags:q,effectiveFlags:z(this._inheritedFlags,q)})}args(j){let q=j.map((J)=>({...J}));return this._clone({args:q})}run(j){return this._clone({run:j})}preRun(j){return this._clone({preRun:j})}postRun(j){return this._clone({postRun:j})}use(j){return this._clone({plugins:[...this._node.plugins,j]})}sub(j){if(!j.trim())throw new G("DEFINITION","Subcommand name must be a non-empty string");let q=z(this._inheritedFlags,this._node.localFlags);return R._createChild(j,q)}command(j,q){if(typeof j==="string"){let K=j;if(!q)throw new G("DEFINITION","command(name, cb) requires a callback");if(!K.trim())throw new G("DEFINITION","Subcommand name must be a non-empty string");if(this._node.subCommands[K])throw new G("DEFINITION",`Subcommand "${K}" is already registered`);let Z=z(this._inheritedFlags,this._node.localFlags),H=R._createChild(K,Z),X=q(H),W={...X._node,effectiveFlags:z(X._inheritedFlags,X._node.localFlags)};return this._clone({subCommands:{...this._node.subCommands,[K]:W}})}let J=j,Q=J._node.meta.name;if(!Q.trim())throw new G("DEFINITION","Subcommand name must be a non-empty string");if(this._node.subCommands[Q])throw new G("DEFINITION",`Subcommand "${Q}" is already registered`);let $={...J._node,effectiveFlags:z(J._inheritedFlags,J._node.localFlags)};return this._clone({subCommands:{...this._node.subCommands,[Q]:$}})}async prepareCommandTree(j){let q=j?.argv??[],J=h(this._node),Q=I(J),$=[],K=x(),Z={argv:[...q],rootCommand:J,state:K},H=y($);try{await A(Q,Z,H)}catch(W){if(B(W))throw W;if(W instanceof G)throw W;if(W instanceof Error)throw W;throw new G("DEFINITION",String(W))}_(J);let{validateCommandTree:X}=await import("./shared/chunk-5apf3vnv.js");return X(J),{root:J,warnings:$}}async execute(j){let q=j?.argv??process.argv.slice(2),J=this._node,Q=I(J),$=[],K=x(),Z={argv:[...q],rootCommand:J,state:K},H=y($);try{await A(Q,Z,H)}catch(W){if(B(W)){process.exitCode=P;return}if(W instanceof G){console.error(`Error: ${W.message}`),process.exitCode=1;return}let U=W instanceof Error?W.message:String(W);console.error(`Error: ${U}`),process.exitCode=1;return}if(_(J),process.env[w]==="1"){let W=(async()=>{try{let{validateCommandTree:U}=await import("./shared/chunk-5apf3vnv.js");U(J);for(let Y of $)console.warn(`Warning: ${Y}`);return{ok:!0}}catch(U){let Y=U instanceof Error?U.message:String(U);return console.error(Y),process.exitCode=1,{ok:!1,error:U}}})();return globalThis[v]=W,await W,process.exit(process.exitCode??0)}for(let W of $)console.warn(`Warning: ${W}`);let X={argv:[...q],rootCommand:J,state:K,route:null,input:null};try{let W,U;try{let Y=D(J,[...q]);X.route=Y,W=Y.command,U=L(W,Y.argv),X.input=U}catch(Y){await F(Q,X,async()=>{throw Y});return}await F(Q,X,async()=>{if(S(W,U),!W.run)return;let Y={args:U.args,flags:U.flags,rawArgs:U.rawArgs,command:W},V;try{if(W.preRun)await W.preRun(Y);await W.run(Y)}catch(M){V=M}if(W.postRun)try{await W.postRun(Y)}catch(M){if(!V)V=M;else console.error(`Error in postRun: ${M instanceof Error?M.message:String(M)}`)}if(V)throw V})}catch(W){if(B(W)){process.exitCode=P;return}if(W instanceof G){console.error(`Error: ${W.message}`),process.exitCode=1;return}if(W instanceof Error){let U=new G("EXECUTION",W.message).withCause(W);console.error(`Error: ${U.message}`),process.exitCode=1;return}console.error(`Error: ${String(W)}`),process.exitCode=1}}}export{S as validateParsed,D as resolveCommand,L as parseArgs,w as VALIDATION_MODE_ENV,G as CrustError,R as Crust};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@crustjs/core",
3
- "version": "0.0.15",
3
+ "version": "0.0.16",
4
4
  "description": "Core library for the Crust CLI framework",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -43,9 +43,9 @@
43
43
  },
44
44
  "devDependencies": {
45
45
  "@crustjs/config": "0.0.0",
46
- "bunup": "^0.16.29"
46
+ "bunup": "^0.16.31"
47
47
  },
48
48
  "peerDependencies": {
49
- "typescript": "^5"
49
+ "typescript": "^6.0.2"
50
50
  }
51
51
  }