@webpieces/code-rules 0.4.655 ā 0.4.656
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 +2 -2
- package/src/cli.js +1 -1
- package/src/cli.js.map +1 -1
- package/src/rule-reporter.d.ts +7 -2
- package/src/rule-reporter.js +11 -4
- package/src/rule-reporter.js.map +1 -1
- package/src/wp-ci.js +1 -1
- package/src/wp-ci.js.map +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@webpieces/code-rules",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.656",
|
|
4
4
|
"description": "Standalone code validation rules extracted from architecture-validators, no Nx dependency required",
|
|
5
5
|
"type": "commonjs",
|
|
6
6
|
"main": "./src/index.js",
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
"directory": "packages/tooling/code-rules"
|
|
17
17
|
},
|
|
18
18
|
"dependencies": {
|
|
19
|
-
"@webpieces/rules-config": "0.4.
|
|
19
|
+
"@webpieces/rules-config": "0.4.656",
|
|
20
20
|
"@inversifyjs/binding-decorators": "1.1.5",
|
|
21
21
|
"inversify": "7.10.4",
|
|
22
22
|
"reflect-metadata": "0.2.2"
|
package/src/cli.js
CHANGED
|
@@ -37,7 +37,7 @@ async function main() {
|
|
|
37
37
|
catch (err) {
|
|
38
38
|
const error = (0, rules_config_1.toError)(err);
|
|
39
39
|
if (error instanceof rules_config_1.RuleFailError) {
|
|
40
|
-
console.error(
|
|
40
|
+
console.error((0, rules_config_1.renderRuleFailForHuman)(error));
|
|
41
41
|
}
|
|
42
42
|
else if (err instanceof rules_config_1.InformAiError) {
|
|
43
43
|
console.error(error.message);
|
package/src/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../../../../../packages/tooling/code-rules/src/cli.ts"],"names":[],"mappings":";;;AACA,4BAA0B;AAC1B,yCAAsC;AACtC,
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../../../../../packages/tooling/code-rules/src/cli.ts"],"names":[],"mappings":";;;AACA,4BAA0B;AAC1B,yCAAsC;AACtC,0DAAyJ;AAEzJ,qDAAgD;AAChD,6DAAuE;AACvE,uEAA4D;AAE5D,KAAK,UAAU,IAAI;IACf,qFAAqF;IACrF,IAAI,CAAC;QACD,8FAA8F;QAC9F,6CAA6C;QAC7C,MAAM,aAAa,GAAG,IAAI,6BAAc,EAAE,CAAC,eAAe,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC;QAC1E,MAAM,MAAM,GAAG,IAAA,8BAAe,EAAC,aAAa,CAAC,CAAC;QAC9C,IAAI,MAAM,CAAC,UAAU,KAAK,IAAI,EAAE,CAAC;YAC7B,OAAO,CAAC,KAAK,CAAC,2EAA2E,CAAC,CAAC;YAC3F,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACpB,CAAC;QACD,OAAO,CAAC,GAAG,CAAC,uBAAuB,MAAM,CAAC,UAAU,EAAE,CAAC,CAAC;QAExD,2FAA2F;QAC3F,oEAAoE;QACpE,kHAAkH;QAClH,MAAM,SAAS,GAAG,IAAI,qBAAS,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC;QACpD,SAAS,CAAC,IAAI,CAAC,kCAAa,CAAC,CAAC,eAAe,CAAC,IAAI,kCAAa,CAAC,aAAa,CAAC,CAAC,CAAC;QAChF,SAAS,CAAC,IAAI,CAAC,qCAAgB,CAAC,CAAC,eAAe,CAAC,IAAI,qCAAgB,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC;QAC1F,KAAK,MAAM,OAAO,IAAI,yCAAe,EAAE,CAAC;YACpC,MAAM,WAAW,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;YAC/B,MAAM,UAAU,GAAG,MAAM,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC,CAAC,CAA+B,CAAC;YAChF,SAAS,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,eAAe,CAAC,UAAU,IAAI,IAAI,WAAW,EAAE,CAAC,CAAC;QACjF,CAAC;QAED,MAAM,GAAG,GAAG,SAAS,CAAC,GAAG,CAAC,6BAAY,CAAC,CAAC;QACxC,MAAM,MAAM,GAAG,MAAM,GAAG,CAAC,GAAG,EAAE,CAAC;QAC/B,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACzC,CAAC;IAAC,OAAO,GAAY,EAAE,CAAC;QACpB,MAAM,KAAK,GAAG,IAAA,sBAAO,EAAC,GAAG,CAAC,CAAC;QAC3B,IAAI,KAAK,YAAY,4BAAa,EAAE,CAAC;YACjC,OAAO,CAAC,KAAK,CAAC,IAAA,qCAAsB,EAAC,KAAK,CAAC,CAAC,CAAC;QACjD,CAAC;aAAM,IAAI,GAAG,YAAY,4BAAa,EAAE,CAAC;YACtC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QACjC,CAAC;aAAM,CAAC;YACJ,OAAO,CAAC,KAAK,CAAC,kCAAkC,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;QACrE,CAAC;QACD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACpB,CAAC;AACL,CAAC;AAED,IAAI,EAAE,CAAC","sourcesContent":["#!/usr/bin/env node\nimport 'reflect-metadata';\nimport { Container } from 'inversify';\nimport { InformAiError, RuleFailError, renderRuleFailForHuman, toError, loadAndValidate, RepoRootFinder, BaseRuleConfig } from '@webpieces/rules-config';\n\nimport { CodeRulesApp } from './code-rules-app';\nimport { WorkspaceRoot, MatchRulesHolder } from './code-rules-context';\nimport { CONFIG_BINDINGS } from './code-rules-config-table';\n\nasync function main(): Promise<void> {\n // webpieces-disable no-unmanaged-exceptions -- global entry point for code-rules CLI\n try {\n // Anchor at the repo root so `.webpieces/instruct-ai` docs land there, not in whatever subdir\n // this CLI ran from; load config from there.\n const workspaceRoot = new RepoRootFinder().resolveRepoRoot(process.cwd());\n const loaded = loadAndValidate(workspaceRoot);\n if (loaded.configPath === null) {\n console.error('\\nā No webpieces.config.json found at workspace root (or any ancestor).\\n');\n process.exit(1);\n }\n console.log(`\\nš Loaded config: ${loaded.configPath}`);\n\n // Composition root: bind the runtime values (workspace root, each rule's config), then let\n // inversify build the ENTIRE validator DAG when we resolve the app.\n // autobind self-binds every @injectable(Singleton) tooling class (replaces the buildProviderModule registry scan)\n const container = new Container({ autobind: true });\n container.bind(WorkspaceRoot).toConstantValue(new WorkspaceRoot(workspaceRoot));\n container.bind(MatchRulesHolder).toConstantValue(new MatchRulesHolder(loaded.matchRules));\n for (const binding of CONFIG_BINDINGS) {\n const ConfigClass = binding[0];\n const configured = loaded.rulesConfig[binding[1]] as BaseRuleConfig | undefined;\n container.bind(ConfigClass).toConstantValue(configured ?? new ConfigClass());\n }\n\n const app = container.get(CodeRulesApp);\n const result = await app.run();\n process.exit(result.success ? 0 : 1);\n } catch (err: unknown) {\n const error = toError(err);\n if (error instanceof RuleFailError) {\n console.error(renderRuleFailForHuman(error));\n } else if (err instanceof InformAiError) {\n console.error(error.message);\n } else {\n console.error(`[code-rules] unexpected error: ${error.message}`);\n }\n process.exit(1);\n }\n}\n\nmain();\n"]}
|
package/src/rule-reporter.d.ts
CHANGED
|
@@ -8,8 +8,13 @@ export declare class RuleReporter {
|
|
|
8
8
|
* expected failure) OR a plain `Error` (a bug) ā is caught, reported, and marks the whole run
|
|
9
9
|
* failed, but the remaining runs STILL execute. One validator can no longer abort the CI run.
|
|
10
10
|
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
11
|
+
* LEGACY, and still a back-compat shim: a run that reports its own failure by returning
|
|
12
|
+
* `{ success: false }` (usually after `console.error`-ing its own banner) still flips the
|
|
13
|
+
* aggregate. That is a SECOND spelling of "this validator failed" and it is scheduled for
|
|
14
|
+
* deletion, not blessed ā the one spelling is to THROW a `RuleFailError` carrying `Option[]`
|
|
15
|
+
* cures, so this reporter renders it for the build-time audience. Removing the shim means
|
|
16
|
+
* `RuleRun.run` returning `Promise<void>` and `ExecutorResult` deleted (`code-validator.ts`);
|
|
17
|
+
* it waits only on the ~22 validators under `src/validate-*.ts` still returning the boolean.
|
|
13
18
|
*/
|
|
14
19
|
runValidators(runs: readonly RuleRun[]): Promise<ExecutorResult>;
|
|
15
20
|
private reportRuleFail;
|
package/src/rule-reporter.js
CHANGED
|
@@ -13,8 +13,13 @@ let RuleReporter = class RuleReporter {
|
|
|
13
13
|
* expected failure) OR a plain `Error` (a bug) ā is caught, reported, and marks the whole run
|
|
14
14
|
* failed, but the remaining runs STILL execute. One validator can no longer abort the CI run.
|
|
15
15
|
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
16
|
+
* LEGACY, and still a back-compat shim: a run that reports its own failure by returning
|
|
17
|
+
* `{ success: false }` (usually after `console.error`-ing its own banner) still flips the
|
|
18
|
+
* aggregate. That is a SECOND spelling of "this validator failed" and it is scheduled for
|
|
19
|
+
* deletion, not blessed ā the one spelling is to THROW a `RuleFailError` carrying `Option[]`
|
|
20
|
+
* cures, so this reporter renders it for the build-time audience. Removing the shim means
|
|
21
|
+
* `RuleRun.run` returning `Promise<void>` and `ExecutorResult` deleted (`code-validator.ts`);
|
|
22
|
+
* it waits only on the ~22 validators under `src/validate-*.ts` still returning the boolean.
|
|
18
23
|
*/
|
|
19
24
|
async runValidators(runs) {
|
|
20
25
|
let anyFailed = false;
|
|
@@ -46,8 +51,10 @@ let RuleReporter = class RuleReporter {
|
|
|
46
51
|
if (err.line !== undefined) {
|
|
47
52
|
console.error(` L${String(err.line)}: ${err.snippet ?? ''}`);
|
|
48
53
|
}
|
|
49
|
-
|
|
50
|
-
|
|
54
|
+
// The "Fix Option N:"/"(preferred)" labels are framework-owned ā same renderer the edit-time
|
|
55
|
+
// report uses ā so a validator never hand-numbers its cures inside its message string.
|
|
56
|
+
for (const line of (0, rules_config_1.formatFixOptions)(err.fixOptions, ' ')) {
|
|
57
|
+
console.error(line);
|
|
51
58
|
}
|
|
52
59
|
console.error('');
|
|
53
60
|
}
|
package/src/rule-reporter.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rule-reporter.js","sourceRoot":"","sources":["../../../../../packages/tooling/code-rules/src/rule-reporter.ts"],"names":[],"mappings":";;;;AAAA,
|
|
1
|
+
{"version":3,"file":"rule-reporter.js","sourceRoot":"","sources":["../../../../../packages/tooling/code-rules/src/rule-reporter.ts"],"names":[],"mappings":";;;;AAAA,0DAAmF;AACnF,yCAA2D;AAI3D;;GAEG;AAEI,IAAM,YAAY,GAAlB,MAAM,YAAY;IACrB;;;;;;;;;;;;OAYG;IACH,KAAK,CAAC,aAAa,CAAC,IAAwB;QACxC,IAAI,SAAS,GAAG,KAAK,CAAC;QACtB,KAAK,MAAM,IAAI,IAAI,IAAI,EAAE,CAAC;YACtB,qHAAqH;YACrH,IAAI,CAAC;gBACD,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,GAAG,EAAE,CAAC;gBAChC,IAAI,CAAC,MAAM,CAAC,OAAO;oBAAE,SAAS,GAAG,IAAI,CAAC;YAC1C,CAAC;YAAC,OAAO,GAAY,EAAE,CAAC;gBACpB,MAAM,KAAK,GAAG,IAAA,sBAAO,EAAC,GAAG,CAAC,CAAC;gBAC3B,IAAI,KAAK,YAAY,4BAAa,EAAE,CAAC;oBACjC,IAAI,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC;gBAC/B,CAAC;qBAAM,CAAC;oBACJ,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;gBACvC,CAAC;gBACD,SAAS,GAAG,IAAI,CAAC;YACrB,CAAC;QACL,CAAC;QACD,OAAO,EAAE,OAAO,EAAE,CAAC,SAAS,EAAE,CAAC;IACnC,CAAC;IAED,8FAA8F;IAC9F,iGAAiG;IACzF,cAAc,CAAC,GAAkB;QACrC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;QAClB,OAAO,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,QAAQ,KAAK,GAAG,CAAC,YAAY,EAAE,CAAC,CAAC;QACzD,IAAI,GAAG,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;YACzB,OAAO,CAAC,KAAK,CAAC,OAAO,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,GAAG,CAAC,OAAO,IAAI,EAAE,EAAE,CAAC,CAAC;QACnE,CAAC;QACD,6FAA6F;QAC7F,uFAAuF;QACvF,KAAK,MAAM,IAAI,IAAI,IAAA,+BAAgB,EAAC,GAAG,CAAC,UAAU,EAAE,KAAK,CAAC,EAAE,CAAC;YACzD,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QACxB,CAAC;QACD,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IACtB,CAAC;IAED,kGAAkG;IAClG,+DAA+D;IACvD,WAAW,CAAC,IAAY,EAAE,KAAY;QAC1C,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;QAClB,OAAO,CAAC,KAAK,CAAC,gBAAgB,IAAI,cAAc,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;QACjE,OAAO,CAAC,KAAK,CAAC,8DAA8D,CAAC,CAAC;QAC9E,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IACtB,CAAC;CACJ,CAAA;AA1DY,oCAAY;uBAAZ,YAAY;IADxB,IAAA,sBAAU,EAAC,8BAAkB,CAAC,SAAS,CAAC;GAC5B,YAAY,CA0DxB","sourcesContent":["import { RuleFailError, toError, formatFixOptions } from '@webpieces/rules-config';\nimport { injectable, bindingScopeValues } from 'inversify';\n\nimport { RuleRun, ExecutorResult } from './code-validator';\n\n/**\n * Runs the active validators with per-validator isolation and prints failures for humans/CI.\n */\n@injectable(bindingScopeValues.Singleton)\nexport class RuleReporter {\n /**\n * Run every {@link RuleRun} with per-run isolation: a run that throws ā a `RuleFailError` (an\n * expected failure) OR a plain `Error` (a bug) ā is caught, reported, and marks the whole run\n * failed, but the remaining runs STILL execute. One validator can no longer abort the CI run.\n *\n * LEGACY, and still a back-compat shim: a run that reports its own failure by returning\n * `{ success: false }` (usually after `console.error`-ing its own banner) still flips the\n * aggregate. That is a SECOND spelling of \"this validator failed\" and it is scheduled for\n * deletion, not blessed ā the one spelling is to THROW a `RuleFailError` carrying `Option[]`\n * cures, so this reporter renders it for the build-time audience. Removing the shim means\n * `RuleRun.run` returning `Promise<void>` and `ExecutorResult` deleted (`code-validator.ts`);\n * it waits only on the ~22 validators under `src/validate-*.ts` still returning the boolean.\n */\n async runValidators(runs: readonly RuleRun[]): Promise<ExecutorResult> {\n let anyFailed = false;\n for (const item of runs) {\n // webpieces-disable no-unmanaged-exceptions -- per-run isolation chokepoint: one validator must never abort the rest\n try {\n const result = await item.run();\n if (!result.success) anyFailed = true;\n } catch (err: unknown) {\n const error = toError(err);\n if (error instanceof RuleFailError) {\n this.reportRuleFail(error);\n } else {\n this.reportCrash(item.name, error);\n }\n anyFailed = true;\n }\n }\n return { success: !anyFailed };\n }\n\n // Human/CI console block for a validator that threw a RuleFailError. code-rules is developer-\n // facing, so it prints humanMessage (falls back to aiMessage inside RuleFailError when not set).\n private reportRuleFail(err: RuleFailError): void {\n console.error('');\n console.error(`ā [${err.ruleName}] ${err.humanMessage}`);\n if (err.line !== undefined) {\n console.error(` L${String(err.line)}: ${err.snippet ?? ''}`);\n }\n // The \"Fix Option N:\"/\"(preferred)\" labels are framework-owned ā same renderer the edit-time\n // report uses ā so a validator never hand-numbers its cures inside its message string.\n for (const line of formatFixOptions(err.fixOptions, ' ')) {\n console.error(line);\n }\n console.error('');\n }\n\n // A validator that threw a plain Error is a BUG in the validator ā surface it (don't swallow) and\n // keep going so it doesn't hide the other validators' results.\n private reportCrash(name: string, error: Error): void {\n console.error('');\n console.error(`ā Validator '${name}' crashed: ${error.message}`);\n console.error(' (a bug in the validator ā the other validators still ran)');\n console.error('');\n }\n}\n"]}
|
package/src/wp-ci.js
CHANGED
|
@@ -123,7 +123,7 @@ async function main() {
|
|
|
123
123
|
catch (err) {
|
|
124
124
|
const error = (0, rules_config_1.toError)(err);
|
|
125
125
|
if (error instanceof rules_config_1.RuleFailError) {
|
|
126
|
-
console.error(
|
|
126
|
+
console.error((0, rules_config_1.renderRuleFailForHuman)(error));
|
|
127
127
|
}
|
|
128
128
|
else if (err instanceof rules_config_1.InformAiError) {
|
|
129
129
|
console.error(error.message);
|
package/src/wp-ci.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"wp-ci.js","sourceRoot":"","sources":["../../../../../packages/tooling/code-rules/src/wp-ci.ts"],"names":[],"mappings":"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","sourcesContent":["#!/usr/bin/env node\n/**\n * wp-ci ā the universal webpieces CI entrypoint.\n *\n * Works in BOTH an Nx monorepo and a plain (non-Nx) repo, because the detection of\n * \"are we even in Nx?\" cannot live inside an Nx executor (by the time an executor runs,\n * Nx is already running). Dispatch:\n *\n * - no nx.json (non-Nx repo) -> run the standalone code validators, succeed.\n * - nx.json present, plugin NOT in it -> fail with the exact install command.\n * - nx.json present, plugin registered -> run validators (incl. the wiring guard),\n * then `nx affected --target=ci`.\n *\n * Repos reference this as a bin (`\"webpieces:ci\": \"wp-ci\"`) so the logic is versioned in\n * the npm package instead of copy-pasted into each repo's package.json (which drifts).\n *\n * Every nx step goes through NxStepRunner, which spawns it into its own process group and refuses\n * to return until that group has drained ā a step whose workers outlive it holds the CI step's\n * stdout open and hangs the job forever with all work already green. See wp-ci-survivors.ts.\n */\n\nimport * as fs from 'fs';\nimport * as path from 'path';\n\nimport 'reflect-metadata';\nimport { Container } from 'inversify';\nimport { loadAndValidate, InformAiError, RuleFailError, toError, RepoRootFinder, BaseRuleConfig } from '@webpieces/rules-config';\nimport { CodeRulesApp } from './code-rules-app';\nimport { WorkspaceRoot, MatchRulesHolder } from './code-rules-context';\nimport { CONFIG_BINDINGS } from './code-rules-config-table';\nimport { NxStepRunner } from './wp-ci-nx-runner';\nimport {\n GracePeriodResolver,\n ProcessGroupKiller,\n ProcessGroupScanner,\n SurvivorReporter,\n SurvivorWatchdog,\n} from './wp-ci-survivors';\n\n/** How often the watchdog re-runs `ps` while waiting for a finished step's process group to drain. */\nconst SURVIVOR_POLL_INTERVAL_MILLIS = 1000;\n\nconst NX_PLUGIN_NAME = '@webpieces/nx-webpieces-rules';\n\ninterface NxPluginObject {\n plugin?: string;\n}\n\ntype NxPluginEntry = string | NxPluginObject;\n\ninterface RawNxJson {\n plugins?: NxPluginEntry[];\n}\n\nfunction findUp(filename: string, startDir: string): string | null {\n let dir = startDir;\n while (true) {\n const candidate = path.join(dir, filename);\n if (fs.existsSync(candidate)) return candidate;\n const parent = path.dirname(dir);\n if (parent === dir) return null;\n dir = parent;\n }\n}\n\nfunction pluginEntryMatches(entry: NxPluginEntry): boolean {\n if (typeof entry === 'string') return entry === NX_PLUGIN_NAME;\n return entry.plugin === NX_PLUGIN_NAME;\n}\n\nfunction isPluginRegistered(nxJsonPath: string): boolean {\n const raw = fs.readFileSync(nxJsonPath, 'utf8');\n // webpieces-disable no-unmanaged-exceptions -- rethrow as InformAiError so global catch surfaces readable message to AI\n try {\n const parsed = JSON.parse(raw) as RawNxJson;\n const plugins = parsed.plugins ?? [];\n return plugins.some((entry: NxPluginEntry) => pluginEntryMatches(entry));\n } catch (err: unknown) {\n const error = toError(err);\n throw new InformAiError(`nx.json has invalid JSON ā fix the file, then retry.\\nParse error: ${error.message}\\nFile: ${nxJsonPath}`);\n }\n}\n\nasync function runStandalone(cwd: string): Promise<number> {\n const workspaceRoot = new RepoRootFinder().resolveRepoRoot(cwd);\n const loaded = loadAndValidate(workspaceRoot);\n if (loaded.configPath === null) {\n console.log('ā¹ļø Not an Nx repo and no webpieces.config.json found ā nothing to validate.');\n return 0;\n }\n console.log('ā¹ļø Not an Nx repo ā running standalone webpieces code validators.\\n');\n\n // Composition root: bind runtime values, then resolve the app so inversify builds the whole DAG.\n // autobind self-binds every @injectable(Singleton) tooling class (replaces the buildProviderModule registry scan)\n const container = new Container({ autobind: true });\n container.bind(WorkspaceRoot).toConstantValue(new WorkspaceRoot(workspaceRoot));\n container.bind(MatchRulesHolder).toConstantValue(new MatchRulesHolder(loaded.matchRules));\n for (const binding of CONFIG_BINDINGS) {\n const ConfigClass = binding[0];\n const configured = loaded.rulesConfig[binding[1]] as BaseRuleConfig | undefined;\n container.bind(ConfigClass).toConstantValue(configured ?? new ConfigClass());\n }\n\n const app = container.get(CodeRulesApp);\n const result = await app.run();\n return result.success ? 0 : 1;\n}\n\nfunction reportPluginMissing(): void {\n console.error('\\nā This is an Nx monorepo but the webpieces Nx plugin is not installed.\\n');\n console.error(' Install it so the validators run during CI:\\n');\n console.error(` nx add ${NX_PLUGIN_NAME}\\n`);\n console.error(' (or add it manually to the \"plugins\" array in nx.json).\\n');\n}\n\n// webpieces-disable no-unmanaged-exceptions -- global entry point for wp-ci CLI\nasync function main(): Promise<void> {\n try {\n const cwd = process.cwd();\n const passthrough = process.argv.slice(2);\n\n const nxJsonPath = findUp('nx.json', cwd);\n if (!nxJsonPath) {\n const code = await runStandalone(cwd);\n process.exit(code);\n }\n\n const root = path.dirname(nxJsonPath);\n if (!isPluginRegistered(nxJsonPath)) {\n reportPluginMissing();\n process.exit(1);\n }\n\n const gracePeriod = new GracePeriodResolver().resolve(process.env);\n const runner = new NxStepRunner(\n root,\n gracePeriod,\n new SurvivorWatchdog(new ProcessGroupScanner(), SURVIVOR_POLL_INTERVAL_MILLIS),\n new SurvivorReporter(),\n new ProcessGroupKiller(),\n );\n\n // Run the architecture + code validators first (this also runs the wiring guard,\n // which fails loudly if nx.json no longer wires validators into the build).\n if (fs.existsSync(path.join(root, 'architecture'))) {\n const validateCode = await runner.run(['run', 'architecture:validate-complete'], 'architecture:validate-complete');\n if (validateCode !== 0) process.exit(validateCode);\n }\n\n // Then the Gradle-style ci composite (lint + build + test) across affected projects.\n const ciCode = await runner.run(['affected', '--target=ci', ...passthrough], 'nx affected --target=ci');\n process.exit(ciCode);\n } catch (err: unknown) {\n const error = toError(err);\n if (error instanceof RuleFailError) {\n console.error(error.humanMessage);\n } else if (err instanceof InformAiError) {\n console.error(error.message);\n } else {\n console.error(`[wp-ci] unexpected error: ${error.message}`);\n }\n process.exit(1);\n }\n}\n\nvoid main();\n"]}
|
|
1
|
+
{"version":3,"file":"wp-ci.js","sourceRoot":"","sources":["../../../../../packages/tooling/code-rules/src/wp-ci.ts"],"names":[],"mappings":"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","sourcesContent":["#!/usr/bin/env node\n/**\n * wp-ci ā the universal webpieces CI entrypoint.\n *\n * Works in BOTH an Nx monorepo and a plain (non-Nx) repo, because the detection of\n * \"are we even in Nx?\" cannot live inside an Nx executor (by the time an executor runs,\n * Nx is already running). Dispatch:\n *\n * - no nx.json (non-Nx repo) -> run the standalone code validators, succeed.\n * - nx.json present, plugin NOT in it -> fail with the exact install command.\n * - nx.json present, plugin registered -> run validators (incl. the wiring guard),\n * then `nx affected --target=ci`.\n *\n * Repos reference this as a bin (`\"webpieces:ci\": \"wp-ci\"`) so the logic is versioned in\n * the npm package instead of copy-pasted into each repo's package.json (which drifts).\n *\n * Every nx step goes through NxStepRunner, which spawns it into its own process group and refuses\n * to return until that group has drained ā a step whose workers outlive it holds the CI step's\n * stdout open and hangs the job forever with all work already green. See wp-ci-survivors.ts.\n */\n\nimport * as fs from 'fs';\nimport * as path from 'path';\n\nimport 'reflect-metadata';\nimport { Container } from 'inversify';\nimport { loadAndValidate, InformAiError, RuleFailError, renderRuleFailForHuman, toError, RepoRootFinder, BaseRuleConfig } from '@webpieces/rules-config';\nimport { CodeRulesApp } from './code-rules-app';\nimport { WorkspaceRoot, MatchRulesHolder } from './code-rules-context';\nimport { CONFIG_BINDINGS } from './code-rules-config-table';\nimport { NxStepRunner } from './wp-ci-nx-runner';\nimport {\n GracePeriodResolver,\n ProcessGroupKiller,\n ProcessGroupScanner,\n SurvivorReporter,\n SurvivorWatchdog,\n} from './wp-ci-survivors';\n\n/** How often the watchdog re-runs `ps` while waiting for a finished step's process group to drain. */\nconst SURVIVOR_POLL_INTERVAL_MILLIS = 1000;\n\nconst NX_PLUGIN_NAME = '@webpieces/nx-webpieces-rules';\n\ninterface NxPluginObject {\n plugin?: string;\n}\n\ntype NxPluginEntry = string | NxPluginObject;\n\ninterface RawNxJson {\n plugins?: NxPluginEntry[];\n}\n\nfunction findUp(filename: string, startDir: string): string | null {\n let dir = startDir;\n while (true) {\n const candidate = path.join(dir, filename);\n if (fs.existsSync(candidate)) return candidate;\n const parent = path.dirname(dir);\n if (parent === dir) return null;\n dir = parent;\n }\n}\n\nfunction pluginEntryMatches(entry: NxPluginEntry): boolean {\n if (typeof entry === 'string') return entry === NX_PLUGIN_NAME;\n return entry.plugin === NX_PLUGIN_NAME;\n}\n\nfunction isPluginRegistered(nxJsonPath: string): boolean {\n const raw = fs.readFileSync(nxJsonPath, 'utf8');\n // webpieces-disable no-unmanaged-exceptions -- rethrow as InformAiError so global catch surfaces readable message to AI\n try {\n const parsed = JSON.parse(raw) as RawNxJson;\n const plugins = parsed.plugins ?? [];\n return plugins.some((entry: NxPluginEntry) => pluginEntryMatches(entry));\n } catch (err: unknown) {\n const error = toError(err);\n throw new InformAiError(`nx.json has invalid JSON ā fix the file, then retry.\\nParse error: ${error.message}\\nFile: ${nxJsonPath}`);\n }\n}\n\nasync function runStandalone(cwd: string): Promise<number> {\n const workspaceRoot = new RepoRootFinder().resolveRepoRoot(cwd);\n const loaded = loadAndValidate(workspaceRoot);\n if (loaded.configPath === null) {\n console.log('ā¹ļø Not an Nx repo and no webpieces.config.json found ā nothing to validate.');\n return 0;\n }\n console.log('ā¹ļø Not an Nx repo ā running standalone webpieces code validators.\\n');\n\n // Composition root: bind runtime values, then resolve the app so inversify builds the whole DAG.\n // autobind self-binds every @injectable(Singleton) tooling class (replaces the buildProviderModule registry scan)\n const container = new Container({ autobind: true });\n container.bind(WorkspaceRoot).toConstantValue(new WorkspaceRoot(workspaceRoot));\n container.bind(MatchRulesHolder).toConstantValue(new MatchRulesHolder(loaded.matchRules));\n for (const binding of CONFIG_BINDINGS) {\n const ConfigClass = binding[0];\n const configured = loaded.rulesConfig[binding[1]] as BaseRuleConfig | undefined;\n container.bind(ConfigClass).toConstantValue(configured ?? new ConfigClass());\n }\n\n const app = container.get(CodeRulesApp);\n const result = await app.run();\n return result.success ? 0 : 1;\n}\n\nfunction reportPluginMissing(): void {\n console.error('\\nā This is an Nx monorepo but the webpieces Nx plugin is not installed.\\n');\n console.error(' Install it so the validators run during CI:\\n');\n console.error(` nx add ${NX_PLUGIN_NAME}\\n`);\n console.error(' (or add it manually to the \"plugins\" array in nx.json).\\n');\n}\n\n// webpieces-disable no-unmanaged-exceptions -- global entry point for wp-ci CLI\nasync function main(): Promise<void> {\n try {\n const cwd = process.cwd();\n const passthrough = process.argv.slice(2);\n\n const nxJsonPath = findUp('nx.json', cwd);\n if (!nxJsonPath) {\n const code = await runStandalone(cwd);\n process.exit(code);\n }\n\n const root = path.dirname(nxJsonPath);\n if (!isPluginRegistered(nxJsonPath)) {\n reportPluginMissing();\n process.exit(1);\n }\n\n const gracePeriod = new GracePeriodResolver().resolve(process.env);\n const runner = new NxStepRunner(\n root,\n gracePeriod,\n new SurvivorWatchdog(new ProcessGroupScanner(), SURVIVOR_POLL_INTERVAL_MILLIS),\n new SurvivorReporter(),\n new ProcessGroupKiller(),\n );\n\n // Run the architecture + code validators first (this also runs the wiring guard,\n // which fails loudly if nx.json no longer wires validators into the build).\n if (fs.existsSync(path.join(root, 'architecture'))) {\n const validateCode = await runner.run(['run', 'architecture:validate-complete'], 'architecture:validate-complete');\n if (validateCode !== 0) process.exit(validateCode);\n }\n\n // Then the Gradle-style ci composite (lint + build + test) across affected projects.\n const ciCode = await runner.run(['affected', '--target=ci', ...passthrough], 'nx affected --target=ci');\n process.exit(ciCode);\n } catch (err: unknown) {\n const error = toError(err);\n if (error instanceof RuleFailError) {\n console.error(renderRuleFailForHuman(error));\n } else if (err instanceof InformAiError) {\n console.error(error.message);\n } else {\n console.error(`[wp-ci] unexpected error: ${error.message}`);\n }\n process.exit(1);\n }\n}\n\nvoid main();\n"]}
|