@webpieces/code-rules 0.4.698 → 0.4.700
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/code-rules",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.700",
|
|
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.700",
|
|
20
20
|
"@inversifyjs/binding-decorators": "1.1.5",
|
|
21
21
|
"inversify": "7.10.4",
|
|
22
22
|
"reflect-metadata": "0.2.2"
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
* ============================================================================
|
|
20
20
|
* VIOLATIONS (BAD) — flagged when the OWNING project's role is not in allowedRoles:
|
|
21
21
|
* ============================================================================
|
|
22
|
-
* factory.createRpcClient(SomeApi, new ClientConfig('svc'))
|
|
22
|
+
* factory.createRpcClient(SomeApi, new ClientConfig('svc', new DeployedServiceHost()))
|
|
23
23
|
* clientCloudTasksFactory.createPubSubClient(SomeApi, config)
|
|
24
24
|
*
|
|
25
25
|
* ============================================================================
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
* ============================================================================
|
|
21
21
|
* VIOLATIONS (BAD) — flagged when the OWNING project's role is not in allowedRoles:
|
|
22
22
|
* ============================================================================
|
|
23
|
-
* factory.createRpcClient(SomeApi, new ClientConfig('svc'))
|
|
23
|
+
* factory.createRpcClient(SomeApi, new ClientConfig('svc', new DeployedServiceHost()))
|
|
24
24
|
* clientCloudTasksFactory.createPubSubClient(SomeApi, config)
|
|
25
25
|
*
|
|
26
26
|
* ============================================================================
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validate-no-client-creation-outside-server-or-client.js","sourceRoot":"","sources":["../../../../../packages/tooling/code-rules/src/validate-no-client-creation-outside-server-or-client.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Validate No Client Creation Outside Server Or Client\n *\n * Flags a project that CONSTRUCTS an rpc/pubsub transport client when the project's `role:` tag is\n * not one of the runnable/entrypoint roles (`allowedRoles`, default server | client | app).\n *\n * ============================================================================\n * WHY\n * ============================================================================\n * The runtime architecture graph draws a `uses` edge from every client-creation site to the api's\n * implementer. When the site sits in a project with a declared identity (`serviceName`) or target\n * (`callsService`) — a server, a client app, an app — the edge is attributable. When it sits in a\n * `role:lib`, the target can't be attributed, so the graph falls back to a fan-out: one `uses` edge\n * to EVERY implementer of the api, i.e. calls that cannot happen. A company-wide api (warmup,\n * browser-log, auth) then draws every caller to every server — pure fiction. This rule removes the\n * failure mode by construction: a reusable library takes the api INJECTED; the server/app module\n * binds it to a client.\n *\n * ============================================================================\n * VIOLATIONS (BAD) — flagged when the OWNING project's role is not in allowedRoles:\n * ============================================================================\n * factory.createRpcClient(SomeApi, new ClientConfig('svc'))\n * clientCloudTasksFactory.createPubSubClient(SomeApi, config)\n *\n * ============================================================================\n * ALLOWED\n * ============================================================================\n * - Any site in a project whose role IS in allowedRoles (server / client / app).\n * - A project with NO `role:` tag (the role-tag rule owns \"every project must declare a role\").\n * - Merely IMPORTING the api type or its DI token, or injecting the api — only constructing the\n * transport (a `.createRpcClient(` / `.createPubSubClient(` CALL) is a violation.\n * - Files under allowedPaths, test files, and lines carrying the webpieces-disable escape.\n *\n * ============================================================================\n * SEVERITY (WARN first, then error)\n * ============================================================================\n * severity \"warn\" (default) prints the violations + migration but PASSES the build, so an upgrade\n * can't break an un-migrated Angular repo. Flip to \"error\" once libraries are migrated.\n */\n\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport {\n hasDisable,\n RULE_NAMES,\n isPathExcluded,\n NoClientCreationOutsideServerOrClientConfig,\n ClientCreationSeverity,\n ModifiedCodeMode,\n detectBase,\n getChangedFiles,\n getFileDiff,\n getChangedLineNumbers,\n} from '@webpieces/rules-config';\nimport { CodeValidator, ExecutorResult } from './code-validator';\nimport { injectable, bindingScopeValues } from 'inversify';\nimport { shouldSkipRule } from './resolve-mode';\nimport { ProjectRoleResolver } from './project-role-resolver';\n\nconst RULE_NAME = RULE_NAMES.NO_CLIENT_CREATION_OUTSIDE_SERVER_OR_CLIENT;\nconst DEFAULT_ALLOWED_ROLES = ['server', 'client', 'app'];\n// A `.createRpcClient(` / `.createPubSubClient(` method CALL — the leading dot excludes the framework\n// method DEFINITIONS (`createRpcClient<T>(apiPrototype, ...)`, no receiver); the `[(<]` requires a call\n// or a generic call, so a bare property reference isn't matched.\nconst CLIENT_CREATE_REGEX = /\\.(createRpcClient|createPubSubClient)\\s*[(<]/;\n\n/** One client-creation call site found in a file. */\nclass CreationSite {\n constructor(\n public readonly line: number,\n public readonly context: string,\n public readonly hasDisableComment: boolean,\n ) {}\n}\n\n/** A reported violation: a client-creation site in a project whose role is not allowed. */\nclass Violation {\n constructor(\n public readonly file: string,\n public readonly line: number,\n public readonly context: string,\n public readonly role: string,\n ) {}\n}\n\n@injectable(bindingScopeValues.Singleton)\nexport class NoClientCreationOutsideServerOrClientValidator extends CodeValidator<NoClientCreationOutsideServerOrClientConfig> {\n constructor(\n config: NoClientCreationOutsideServerOrClientConfig,\n private readonly roleResolver: ProjectRoleResolver,\n ) {\n super(config, RULE_NAME, RULE_NAME);\n }\n\n async run(workspaceRoot: string): Promise<ExecutorResult> {\n const mode = this.resolveMode(this.config.mode ?? 'OFF');\n if (mode === 'OFF') {\n console.log(`\\n⏭️ Skipping ${RULE_NAME} validation (mode: OFF)`);\n console.log('');\n return { success: true };\n }\n\n const severity: ClientCreationSeverity = this.config.severity ?? 'warn';\n console.log(`\\n📏 Validating No Client Creation Outside Server Or Client\\n`);\n console.log(` Mode: ${mode} · Severity: ${severity}`);\n\n const base = this.resolveBase(workspaceRoot);\n if (base === null) return { success: true };\n const head = process.env['NX_HEAD'];\n\n console.log(` Base: ${base}`);\n console.log(` Head: ${head ?? 'working tree (includes uncommitted changes)'}`);\n console.log('');\n\n const changedFiles = getChangedFiles(workspaceRoot, base, head);\n if (changedFiles.length === 0) {\n console.log('✅ No TypeScript files changed');\n return { success: true };\n }\n\n console.log(`📂 Checking ${changedFiles.length} changed file(s)...`);\n const violations = this.findViolations(workspaceRoot, changedFiles, mode, base, head);\n\n if (violations.length === 0) {\n console.log('✅ No client-creation-in-a-library violations found');\n return { success: true };\n }\n\n this.report(violations, severity);\n // WARN reports but passes; only \"error\" fails the build.\n return { success: severity !== 'error' };\n }\n\n private allowedRoles(): string[] {\n const configured = this.config.allowedRoles;\n return configured && configured.length > 0 ? configured : DEFAULT_ALLOWED_ROLES;\n }\n\n private disableAllowed(): boolean {\n return this.config.disableAllowed ?? true;\n }\n\n private allowedPaths(): string[] {\n return this.config.allowedPaths ?? [];\n }\n\n private resolveMode(normalMode: ModifiedCodeMode): ModifiedCodeMode {\n if (normalMode === 'OFF') return normalMode;\n const skip = shouldSkipRule(this.config.turnOffRuleUntilEpoch, this.config.turnOffRuleWhileOnBranch);\n if (skip.skip) {\n console.log(`\\n⏭️ Skipping ${RULE_NAME} validation (${skip.reason})`);\n console.log('');\n return 'OFF';\n }\n return normalMode;\n }\n\n private resolveBase(workspaceRoot: string): string | null {\n const envBase = process.env['NX_BASE'];\n if (envBase) return envBase;\n const detected = detectBase(workspaceRoot);\n if (!detected) {\n console.log(`\\n⏭️ Skipping ${RULE_NAME} validation (could not detect base branch)`);\n console.log('');\n return null;\n }\n return detected;\n }\n\n /** Violations across changed files: a creation site in a project whose role is not allowed. In\n * NEW_AND_MODIFIED_CODE only sites on changed lines count; in NEW_AND_MODIFIED_FILES every site\n * in a changed file counts. */\n private findViolations(\n workspaceRoot: string,\n changedFiles: string[],\n mode: ModifiedCodeMode,\n base: string,\n head: string | undefined,\n ): Violation[] {\n const allowed = new Set(this.allowedRoles());\n const violations: Violation[] = [];\n for (const file of changedFiles) {\n if (this.isExempt(file)) continue;\n\n const role = this.roleResolver.roleOf(workspaceRoot, file);\n // No role tag → role-tag rule owns it; an allowed role → fine. Either way, skip.\n if (role === null || allowed.has(role)) continue;\n\n const changedLines = mode === 'NEW_AND_MODIFIED_CODE'\n ? getChangedLineNumbers(getFileDiff(workspaceRoot, file, base, head))\n : null;\n if (changedLines !== null && changedLines.size === 0) continue;\n\n for (const site of this.scanFile(workspaceRoot, file)) {\n if (this.disableAllowed() && site.hasDisableComment) continue;\n if (changedLines !== null && !changedLines.has(site.line)) continue;\n violations.push(new Violation(file, site.line, site.context, role));\n }\n }\n return violations;\n }\n\n private isExempt(file: string): boolean {\n return this.isTestFile(file) || isPathExcluded(file, this.allowedPaths());\n }\n\n private isTestFile(filePath: string): boolean {\n return filePath.includes('.spec.ts') || filePath.includes('.test.ts') || filePath.includes('__tests__/');\n }\n\n /** Every client-creation call site in a file, ignoring occurrences inside comments. */\n private scanFile(workspaceRoot: string, relFile: string): CreationSite[] {\n const fullPath = path.join(workspaceRoot, relFile);\n if (!fs.existsSync(fullPath)) return [];\n const lines = fs.readFileSync(fullPath, 'utf-8').split('\\n');\n const code = this.stripComments(lines);\n\n const sites: CreationSite[] = [];\n for (let i = 0; i < code.length; i++) {\n if (!CLIENT_CREATE_REGEX.test(code[i] ?? '')) continue;\n const raw = lines[i] ?? '';\n const prev = i > 0 ? (lines[i - 1] ?? '') : '';\n const disabled = hasDisable(raw, RULE_NAME) || hasDisable(prev, RULE_NAME);\n sites.push(new CreationSite(i + 1, raw.trim(), disabled));\n }\n return sites;\n }\n\n /** The code-only text of each line: block comments (/* … *\\/) and line comments (// …) blanked\n * out, so a `factory.createRpcClient(` in a JSDoc example is never matched. */\n private stripComments(lines: string[]): string[] {\n const out: string[] = [];\n let inBlock = false;\n for (const line of lines) {\n let result = '';\n let i = 0;\n while (i < line.length) {\n if (inBlock) {\n if (line[i] === '*' && line[i + 1] === '/') { inBlock = false; i += 2; } else { i += 1; }\n continue;\n }\n if (line[i] === '/' && line[i + 1] === '*') { inBlock = true; i += 2; continue; }\n if (line[i] === '/' && line[i + 1] === '/') break;\n result += line[i];\n i += 1;\n }\n out.push(result);\n }\n return out;\n }\n\n // webpieces-disable max-lines-new-methods -- console guidance block + violation list\n private report(violations: Violation[], severity: ClientCreationSeverity): void {\n const icon = severity === 'error' ? '❌' : '⚠️';\n console.error('');\n console.error(`${icon} A library (role:lib) must NOT construct an rpc/pubsub client!`);\n console.error('');\n console.error(' Only a runnable entrypoint (role:server / role:client / role:app) has a declared identity');\n console.error(' (serviceName) or target (callsService), so a client built there is attributable in the');\n console.error(' runtime graph. A client built in a library reaches the fan-out fallback — one \"uses\" edge');\n console.error(' to EVERY implementer of the api, i.e. calls that cannot happen.');\n console.error('');\n console.error(' Migrate: the library takes the api INJECTED (constructor(private readonly api: SomeApi)),');\n console.error(' and the server/app DI module constructs the client with factory.createRpcClient(SomeApi, ...).');\n console.error('');\n for (const v of violations) {\n console.error(` ${icon} ${v.file}:${v.line} (role:${v.role})`);\n console.error(` ${v.context}`);\n }\n console.error('');\n if (this.disableAllowed()) {\n console.error(' Escape hatch (use sparingly):');\n console.error(` // webpieces-disable ${RULE_NAME} -- <reason>`);\n } else {\n console.error(' Escape hatch: DISABLED (disableAllowed: false)');\n }\n console.error('');\n if (severity !== 'error') {\n console.error(' Severity: WARN — reported but NOT failing the build. Migrate, then set');\n console.error(` \"severity\": \"error\" on ${RULE_NAME} to enforce.`);\n console.error('');\n }\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"validate-no-client-creation-outside-server-or-client.js","sourceRoot":"","sources":["../../../../../packages/tooling/code-rules/src/validate-no-client-creation-outside-server-or-client.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Validate No Client Creation Outside Server Or Client\n *\n * Flags a project that CONSTRUCTS an rpc/pubsub transport client when the project's `role:` tag is\n * not one of the runnable/entrypoint roles (`allowedRoles`, default server | client | app).\n *\n * ============================================================================\n * WHY\n * ============================================================================\n * The runtime architecture graph draws a `uses` edge from every client-creation site to the api's\n * implementer. When the site sits in a project with a declared identity (`serviceName`) or target\n * (`callsService`) — a server, a client app, an app — the edge is attributable. When it sits in a\n * `role:lib`, the target can't be attributed, so the graph falls back to a fan-out: one `uses` edge\n * to EVERY implementer of the api, i.e. calls that cannot happen. A company-wide api (warmup,\n * browser-log, auth) then draws every caller to every server — pure fiction. This rule removes the\n * failure mode by construction: a reusable library takes the api INJECTED; the server/app module\n * binds it to a client.\n *\n * ============================================================================\n * VIOLATIONS (BAD) — flagged when the OWNING project's role is not in allowedRoles:\n * ============================================================================\n * factory.createRpcClient(SomeApi, new ClientConfig('svc', new DeployedServiceHost()))\n * clientCloudTasksFactory.createPubSubClient(SomeApi, config)\n *\n * ============================================================================\n * ALLOWED\n * ============================================================================\n * - Any site in a project whose role IS in allowedRoles (server / client / app).\n * - A project with NO `role:` tag (the role-tag rule owns \"every project must declare a role\").\n * - Merely IMPORTING the api type or its DI token, or injecting the api — only constructing the\n * transport (a `.createRpcClient(` / `.createPubSubClient(` CALL) is a violation.\n * - Files under allowedPaths, test files, and lines carrying the webpieces-disable escape.\n *\n * ============================================================================\n * SEVERITY (WARN first, then error)\n * ============================================================================\n * severity \"warn\" (default) prints the violations + migration but PASSES the build, so an upgrade\n * can't break an un-migrated Angular repo. Flip to \"error\" once libraries are migrated.\n */\n\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport {\n hasDisable,\n RULE_NAMES,\n isPathExcluded,\n NoClientCreationOutsideServerOrClientConfig,\n ClientCreationSeverity,\n ModifiedCodeMode,\n detectBase,\n getChangedFiles,\n getFileDiff,\n getChangedLineNumbers,\n} from '@webpieces/rules-config';\nimport { CodeValidator, ExecutorResult } from './code-validator';\nimport { injectable, bindingScopeValues } from 'inversify';\nimport { shouldSkipRule } from './resolve-mode';\nimport { ProjectRoleResolver } from './project-role-resolver';\n\nconst RULE_NAME = RULE_NAMES.NO_CLIENT_CREATION_OUTSIDE_SERVER_OR_CLIENT;\nconst DEFAULT_ALLOWED_ROLES = ['server', 'client', 'app'];\n// A `.createRpcClient(` / `.createPubSubClient(` method CALL — the leading dot excludes the framework\n// method DEFINITIONS (`createRpcClient<T>(apiPrototype, ...)`, no receiver); the `[(<]` requires a call\n// or a generic call, so a bare property reference isn't matched.\nconst CLIENT_CREATE_REGEX = /\\.(createRpcClient|createPubSubClient)\\s*[(<]/;\n\n/** One client-creation call site found in a file. */\nclass CreationSite {\n constructor(\n public readonly line: number,\n public readonly context: string,\n public readonly hasDisableComment: boolean,\n ) {}\n}\n\n/** A reported violation: a client-creation site in a project whose role is not allowed. */\nclass Violation {\n constructor(\n public readonly file: string,\n public readonly line: number,\n public readonly context: string,\n public readonly role: string,\n ) {}\n}\n\n@injectable(bindingScopeValues.Singleton)\nexport class NoClientCreationOutsideServerOrClientValidator extends CodeValidator<NoClientCreationOutsideServerOrClientConfig> {\n constructor(\n config: NoClientCreationOutsideServerOrClientConfig,\n private readonly roleResolver: ProjectRoleResolver,\n ) {\n super(config, RULE_NAME, RULE_NAME);\n }\n\n async run(workspaceRoot: string): Promise<ExecutorResult> {\n const mode = this.resolveMode(this.config.mode ?? 'OFF');\n if (mode === 'OFF') {\n console.log(`\\n⏭️ Skipping ${RULE_NAME} validation (mode: OFF)`);\n console.log('');\n return { success: true };\n }\n\n const severity: ClientCreationSeverity = this.config.severity ?? 'warn';\n console.log(`\\n📏 Validating No Client Creation Outside Server Or Client\\n`);\n console.log(` Mode: ${mode} · Severity: ${severity}`);\n\n const base = this.resolveBase(workspaceRoot);\n if (base === null) return { success: true };\n const head = process.env['NX_HEAD'];\n\n console.log(` Base: ${base}`);\n console.log(` Head: ${head ?? 'working tree (includes uncommitted changes)'}`);\n console.log('');\n\n const changedFiles = getChangedFiles(workspaceRoot, base, head);\n if (changedFiles.length === 0) {\n console.log('✅ No TypeScript files changed');\n return { success: true };\n }\n\n console.log(`📂 Checking ${changedFiles.length} changed file(s)...`);\n const violations = this.findViolations(workspaceRoot, changedFiles, mode, base, head);\n\n if (violations.length === 0) {\n console.log('✅ No client-creation-in-a-library violations found');\n return { success: true };\n }\n\n this.report(violations, severity);\n // WARN reports but passes; only \"error\" fails the build.\n return { success: severity !== 'error' };\n }\n\n private allowedRoles(): string[] {\n const configured = this.config.allowedRoles;\n return configured && configured.length > 0 ? configured : DEFAULT_ALLOWED_ROLES;\n }\n\n private disableAllowed(): boolean {\n return this.config.disableAllowed ?? true;\n }\n\n private allowedPaths(): string[] {\n return this.config.allowedPaths ?? [];\n }\n\n private resolveMode(normalMode: ModifiedCodeMode): ModifiedCodeMode {\n if (normalMode === 'OFF') return normalMode;\n const skip = shouldSkipRule(this.config.turnOffRuleUntilEpoch, this.config.turnOffRuleWhileOnBranch);\n if (skip.skip) {\n console.log(`\\n⏭️ Skipping ${RULE_NAME} validation (${skip.reason})`);\n console.log('');\n return 'OFF';\n }\n return normalMode;\n }\n\n private resolveBase(workspaceRoot: string): string | null {\n const envBase = process.env['NX_BASE'];\n if (envBase) return envBase;\n const detected = detectBase(workspaceRoot);\n if (!detected) {\n console.log(`\\n⏭️ Skipping ${RULE_NAME} validation (could not detect base branch)`);\n console.log('');\n return null;\n }\n return detected;\n }\n\n /** Violations across changed files: a creation site in a project whose role is not allowed. In\n * NEW_AND_MODIFIED_CODE only sites on changed lines count; in NEW_AND_MODIFIED_FILES every site\n * in a changed file counts. */\n private findViolations(\n workspaceRoot: string,\n changedFiles: string[],\n mode: ModifiedCodeMode,\n base: string,\n head: string | undefined,\n ): Violation[] {\n const allowed = new Set(this.allowedRoles());\n const violations: Violation[] = [];\n for (const file of changedFiles) {\n if (this.isExempt(file)) continue;\n\n const role = this.roleResolver.roleOf(workspaceRoot, file);\n // No role tag → role-tag rule owns it; an allowed role → fine. Either way, skip.\n if (role === null || allowed.has(role)) continue;\n\n const changedLines = mode === 'NEW_AND_MODIFIED_CODE'\n ? getChangedLineNumbers(getFileDiff(workspaceRoot, file, base, head))\n : null;\n if (changedLines !== null && changedLines.size === 0) continue;\n\n for (const site of this.scanFile(workspaceRoot, file)) {\n if (this.disableAllowed() && site.hasDisableComment) continue;\n if (changedLines !== null && !changedLines.has(site.line)) continue;\n violations.push(new Violation(file, site.line, site.context, role));\n }\n }\n return violations;\n }\n\n private isExempt(file: string): boolean {\n return this.isTestFile(file) || isPathExcluded(file, this.allowedPaths());\n }\n\n private isTestFile(filePath: string): boolean {\n return filePath.includes('.spec.ts') || filePath.includes('.test.ts') || filePath.includes('__tests__/');\n }\n\n /** Every client-creation call site in a file, ignoring occurrences inside comments. */\n private scanFile(workspaceRoot: string, relFile: string): CreationSite[] {\n const fullPath = path.join(workspaceRoot, relFile);\n if (!fs.existsSync(fullPath)) return [];\n const lines = fs.readFileSync(fullPath, 'utf-8').split('\\n');\n const code = this.stripComments(lines);\n\n const sites: CreationSite[] = [];\n for (let i = 0; i < code.length; i++) {\n if (!CLIENT_CREATE_REGEX.test(code[i] ?? '')) continue;\n const raw = lines[i] ?? '';\n const prev = i > 0 ? (lines[i - 1] ?? '') : '';\n const disabled = hasDisable(raw, RULE_NAME) || hasDisable(prev, RULE_NAME);\n sites.push(new CreationSite(i + 1, raw.trim(), disabled));\n }\n return sites;\n }\n\n /** The code-only text of each line: block comments (/* … *\\/) and line comments (// …) blanked\n * out, so a `factory.createRpcClient(` in a JSDoc example is never matched. */\n private stripComments(lines: string[]): string[] {\n const out: string[] = [];\n let inBlock = false;\n for (const line of lines) {\n let result = '';\n let i = 0;\n while (i < line.length) {\n if (inBlock) {\n if (line[i] === '*' && line[i + 1] === '/') { inBlock = false; i += 2; } else { i += 1; }\n continue;\n }\n if (line[i] === '/' && line[i + 1] === '*') { inBlock = true; i += 2; continue; }\n if (line[i] === '/' && line[i + 1] === '/') break;\n result += line[i];\n i += 1;\n }\n out.push(result);\n }\n return out;\n }\n\n // webpieces-disable max-lines-new-methods -- console guidance block + violation list\n private report(violations: Violation[], severity: ClientCreationSeverity): void {\n const icon = severity === 'error' ? '❌' : '⚠️';\n console.error('');\n console.error(`${icon} A library (role:lib) must NOT construct an rpc/pubsub client!`);\n console.error('');\n console.error(' Only a runnable entrypoint (role:server / role:client / role:app) has a declared identity');\n console.error(' (serviceName) or target (callsService), so a client built there is attributable in the');\n console.error(' runtime graph. A client built in a library reaches the fan-out fallback — one \"uses\" edge');\n console.error(' to EVERY implementer of the api, i.e. calls that cannot happen.');\n console.error('');\n console.error(' Migrate: the library takes the api INJECTED (constructor(private readonly api: SomeApi)),');\n console.error(' and the server/app DI module constructs the client with factory.createRpcClient(SomeApi, ...).');\n console.error('');\n for (const v of violations) {\n console.error(` ${icon} ${v.file}:${v.line} (role:${v.role})`);\n console.error(` ${v.context}`);\n }\n console.error('');\n if (this.disableAllowed()) {\n console.error(' Escape hatch (use sparingly):');\n console.error(` // webpieces-disable ${RULE_NAME} -- <reason>`);\n } else {\n console.error(' Escape hatch: DISABLED (disableAllowed: false)');\n }\n console.error('');\n if (severity !== 'error') {\n console.error(' Severity: WARN — reported but NOT failing the build. Migrate, then set');\n console.error(` \"severity\": \"error\" on ${RULE_NAME} to enforce.`);\n console.error('');\n }\n }\n}\n"]}
|