@webpieces/rules-config 0.3.166 → 0.3.168

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": "@webpieces/rules-config",
3
- "version": "0.3.166",
3
+ "version": "0.3.168",
4
4
  "description": "Shared webpieces.config.json loader. Single source of truth for validation rule configuration consumed by @webpieces/ai-hook-rules, @webpieces/code-rules, and @webpieces/nx-webpieces-rules.",
5
5
  "type": "commonjs",
6
6
  "main": "./src/index.js",
@@ -1,3 +1,6 @@
1
1
  export declare class InformAiError extends Error {
2
- constructor(message: string);
2
+ cause?: Error;
3
+ constructor(message: string, options?: {
4
+ cause?: Error;
5
+ });
3
6
  }
@@ -2,9 +2,11 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.InformAiError = void 0;
4
4
  class InformAiError extends Error {
5
- constructor(message) {
5
+ cause;
6
+ constructor(message, options) {
6
7
  super(message);
7
8
  this.name = 'InformAiError';
9
+ this.cause = options?.cause;
8
10
  }
9
11
  }
10
12
  exports.InformAiError = InformAiError;
@@ -1 +1 @@
1
- {"version":3,"file":"inform-ai-error.js","sourceRoot":"","sources":["../../../../../packages/tooling/rules-config/src/inform-ai-error.ts"],"names":[],"mappings":";;;AAAA,MAAa,aAAc,SAAQ,KAAK;IACpC,YAAY,OAAe;QACvB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,eAAe,CAAC;IAChC,CAAC;CACJ;AALD,sCAKC","sourcesContent":["export class InformAiError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'InformAiError';\n }\n}\n"]}
1
+ {"version":3,"file":"inform-ai-error.js","sourceRoot":"","sources":["../../../../../packages/tooling/rules-config/src/inform-ai-error.ts"],"names":[],"mappings":";;;AAAA,MAAa,aAAc,SAAQ,KAAK;IAC3B,KAAK,CAAS;IAEvB,YAAY,OAAe,EAAE,OAA2B;QACpD,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,eAAe,CAAC;QAC5B,IAAI,CAAC,KAAK,GAAG,OAAO,EAAE,KAAK,CAAC;IAChC,CAAC;CACJ;AARD,sCAQC","sourcesContent":["export class InformAiError extends Error {\n override cause?: Error;\n\n constructor(message: string, options?: { cause?: Error }) {\n super(message);\n this.name = 'InformAiError';\n this.cause = options?.cause;\n }\n}\n"]}
package/src/types.js CHANGED
@@ -16,6 +16,7 @@ exports.ResolvedConfig = exports.ResolvedRuleConfig = void 0;
16
16
  * removed in favor of this single, more flexible switch.)
17
17
  */
18
18
  class ResolvedRuleConfig {
19
+ options;
19
20
  constructor(options) {
20
21
  this.options = options;
21
22
  }
@@ -39,6 +40,10 @@ exports.ResolvedRuleConfig = ResolvedRuleConfig;
39
40
  * should treat that as "no validation configured").
40
41
  */
41
42
  class ResolvedConfig {
43
+ rules;
44
+ userConfiguredRuleNames;
45
+ rulesDir;
46
+ configPath;
42
47
  constructor(rules, userConfiguredRuleNames, rulesDir, configPath) {
43
48
  this.rules = rules;
44
49
  this.userConfiguredRuleNames = userConfiguredRuleNames;
package/src/types.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../../../packages/tooling/rules-config/src/types.ts"],"names":[],"mappings":";;;AAGA;;;;;;;;;;;;;GAaG;AACH,MAAa,kBAAkB;IAG3B,YAAY,OAAoB;QAC5B,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;IAC3B,CAAC;IAED,oFAAoF;IACpF,IAAI,IAAI;QACJ,MAAM,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QAC/B,OAAO,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IACjD,CAAC;IAED,iFAAiF;IACjF,IAAI,KAAK;QACL,OAAO,IAAI,CAAC,IAAI,KAAK,KAAK,CAAC;IAC/B,CAAC;CACJ;AAjBD,gDAiBC;AAED;;;;;;;GAOG;AACH,MAAa,cAAc;IAMvB,YACI,KAAsC,EACtC,uBAA4C,EAC5C,QAA2B,EAC3B,UAAyB;QAEzB,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QACnB,IAAI,CAAC,uBAAuB,GAAG,uBAAuB,CAAC;QACvD,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;QACzB,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC;IACjC,CAAC;CACJ;AAjBD,wCAiBC","sourcesContent":["// webpieces-disable no-any-unknown -- rule options are opaque at framework level; each consumer casts internally\nexport type RuleOptions = Record<string, unknown>;\n\n/**\n * One rule entry from webpieces.config.json, merged with built-in defaults.\n *\n * `options` contains the raw option bag (mode, limit, disableAllowed,\n * ignoreModifiedUntilEpoch, enforcePaths, etc). Consumers extract the\n * fields they understand and ignore the rest.\n *\n * On/off is driven entirely by `mode`: a rule is OFF only when explicitly\n * set to `mode: \"OFF\"`. Any other value (or an absent mode) leaves the rule\n * ON. For code-rules, `mode` doubles as the scope selector\n * (e.g. \"MODIFIED_CODE\", \"NEW_AND_MODIFIED_METHODS\"); for simple on/off\n * rules it is just \"ON\"/\"OFF\". (The legacy `enabled` boolean has been\n * removed in favor of this single, more flexible switch.)\n */\nexport class ResolvedRuleConfig {\n readonly options: RuleOptions;\n\n constructor(options: RuleOptions) {\n this.options = options;\n }\n\n /** Raw mode string from the option bag (\"ON\" | \"OFF\" | scope value), if present. */\n get mode(): string | undefined {\n const m = this.options['mode'];\n return typeof m === 'string' ? m : undefined;\n }\n\n /** A rule is off only when explicitly `mode: \"OFF\"`. An absent mode means on. */\n get isOff(): boolean {\n return this.mode === 'OFF';\n }\n}\n\n/**\n * The fully-resolved workspace configuration: every rule known to the\n * workspace (built-in + consumer overrides) keyed by its canonical\n * kebab-case name.\n *\n * `configPath` is null when no webpieces.config.json was found (loaders\n * should treat that as \"no validation configured\").\n */\nexport class ResolvedConfig {\n readonly rules: Map<string, ResolvedRuleConfig>;\n readonly userConfiguredRuleNames: ReadonlySet<string>;\n readonly rulesDir: readonly string[];\n readonly configPath: string | null;\n\n constructor(\n rules: Map<string, ResolvedRuleConfig>,\n userConfiguredRuleNames: ReadonlySet<string>,\n rulesDir: readonly string[],\n configPath: string | null,\n ) {\n this.rules = rules;\n this.userConfiguredRuleNames = userConfiguredRuleNames;\n this.rulesDir = rulesDir;\n this.configPath = configPath;\n }\n}\n"]}
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../../../packages/tooling/rules-config/src/types.ts"],"names":[],"mappings":";;;AAGA;;;;;;;;;;;;;GAaG;AACH,MAAa,kBAAkB;IAClB,OAAO,CAAc;IAE9B,YAAY,OAAoB;QAC5B,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;IAC3B,CAAC;IAED,oFAAoF;IACpF,IAAI,IAAI;QACJ,MAAM,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QAC/B,OAAO,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IACjD,CAAC;IAED,iFAAiF;IACjF,IAAI,KAAK;QACL,OAAO,IAAI,CAAC,IAAI,KAAK,KAAK,CAAC;IAC/B,CAAC;CACJ;AAjBD,gDAiBC;AAED;;;;;;;GAOG;AACH,MAAa,cAAc;IACd,KAAK,CAAkC;IACvC,uBAAuB,CAAsB;IAC7C,QAAQ,CAAoB;IAC5B,UAAU,CAAgB;IAEnC,YACI,KAAsC,EACtC,uBAA4C,EAC5C,QAA2B,EAC3B,UAAyB;QAEzB,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QACnB,IAAI,CAAC,uBAAuB,GAAG,uBAAuB,CAAC;QACvD,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;QACzB,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC;IACjC,CAAC;CACJ;AAjBD,wCAiBC","sourcesContent":["// webpieces-disable no-any-unknown -- rule options are opaque at framework level; each consumer casts internally\nexport type RuleOptions = Record<string, unknown>;\n\n/**\n * One rule entry from webpieces.config.json, merged with built-in defaults.\n *\n * `options` contains the raw option bag (mode, limit, disableAllowed,\n * ignoreModifiedUntilEpoch, enforcePaths, etc). Consumers extract the\n * fields they understand and ignore the rest.\n *\n * On/off is driven entirely by `mode`: a rule is OFF only when explicitly\n * set to `mode: \"OFF\"`. Any other value (or an absent mode) leaves the rule\n * ON. For code-rules, `mode` doubles as the scope selector\n * (e.g. \"MODIFIED_CODE\", \"NEW_AND_MODIFIED_METHODS\"); for simple on/off\n * rules it is just \"ON\"/\"OFF\". (The legacy `enabled` boolean has been\n * removed in favor of this single, more flexible switch.)\n */\nexport class ResolvedRuleConfig {\n readonly options: RuleOptions;\n\n constructor(options: RuleOptions) {\n this.options = options;\n }\n\n /** Raw mode string from the option bag (\"ON\" | \"OFF\" | scope value), if present. */\n get mode(): string | undefined {\n const m = this.options['mode'];\n return typeof m === 'string' ? m : undefined;\n }\n\n /** A rule is off only when explicitly `mode: \"OFF\"`. An absent mode means on. */\n get isOff(): boolean {\n return this.mode === 'OFF';\n }\n}\n\n/**\n * The fully-resolved workspace configuration: every rule known to the\n * workspace (built-in + consumer overrides) keyed by its canonical\n * kebab-case name.\n *\n * `configPath` is null when no webpieces.config.json was found (loaders\n * should treat that as \"no validation configured\").\n */\nexport class ResolvedConfig {\n readonly rules: Map<string, ResolvedRuleConfig>;\n readonly userConfiguredRuleNames: ReadonlySet<string>;\n readonly rulesDir: readonly string[];\n readonly configPath: string | null;\n\n constructor(\n rules: Map<string, ResolvedRuleConfig>,\n userConfiguredRuleNames: ReadonlySet<string>,\n rulesDir: readonly string[],\n configPath: string | null,\n ) {\n this.rules = rules;\n this.userConfiguredRuleNames = userConfiguredRuleNames;\n this.rulesDir = rulesDir;\n this.configPath = configPath;\n }\n}\n"]}
@@ -671,6 +671,51 @@ If you believe you have a legitimate use case for try-catch:
671
671
 
672
672
  4. **Be prepared to justify** - 99% of try-catch can be removed
673
673
 
674
+ ## Rule: throw-cause-required
675
+
676
+ When you catch an exception and rethrow with additional context, you MUST chain the original
677
+ exception using `{ cause: error }`. Embedding `error.message` in a string loses the original
678
+ stack trace and is banned.
679
+
680
+ ### BAD (triggers violation)
681
+ ```typescript
682
+ } catch (err: unknown) {
683
+ const error = toError(err);
684
+ throw new InformAiError(`Cannot load config: ${error.message}`); // ← BANNED
685
+ }
686
+ ```
687
+
688
+ ### Why it's bad
689
+ The original stack trace is gone. Debugging tools only see the new error; the root cause
690
+ and its call stack have been discarded.
691
+
692
+ ### Fix Options
693
+
694
+ **Option 1 — Remove the try-catch (usually best)**
695
+ ```typescript
696
+ // Just let it bubble — the global handler logs it with full context
697
+ const config = JSON.parse(raw);
698
+ ```
699
+
700
+ **Option 2 — Rethrow with cause (generic)**
701
+ ```typescript
702
+ } catch (err: unknown) {
703
+ const error = toError(err);
704
+ throw new Error(`Cannot load config`, { cause: error });
705
+ }
706
+ ```
707
+
708
+ **Option 3 — Rethrow with specific error class + cause**
709
+ ```typescript
710
+ } catch (err: unknown) {
711
+ const error = toError(err);
712
+ throw new InformAiError(`Cannot load config — fix the JSON then retry`, { cause: error });
713
+ }
714
+ ```
715
+
716
+ The `cause` field is available on the original error object and will appear in stack traces
717
+ and in `/debugLocal/{traceId}` responses.
718
+
674
719
  ## Summary
675
720
 
676
721
  **The webpieces philosophy**: Errors should bubble to the global handler where they are logged with traceId and stored for debugging. Local try-catch blocks break this architecture and create blind spots in production.