@webpieces/code-rules 0.4.752 → 0.4.753

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.752",
3
+ "version": "0.4.753",
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.752",
19
+ "@webpieces/rules-config": "0.4.753",
20
20
  "@inversifyjs/binding-decorators": "1.1.5",
21
21
  "inversify": "7.10.4",
22
22
  "reflect-metadata": "0.2.2"
@@ -5,6 +5,11 @@ export declare class ReactNativeCompatibility {
5
5
  private readonly forbidden;
6
6
  /** Return actionable violations; callers must fail their build on any entry. */
7
7
  inspect(entrypoints: string[], options: ts.CompilerOptions): string[];
8
+ private abortSignalProblem;
9
+ /** React Native's abort-controller 3 surface has aborted/addEventListener, but not these DOM additions. */
10
+ private isNonPortableAbortSignalExtension;
11
+ private isSignalExpression;
12
+ private hasAbortSignalDeclaration;
8
13
  /** A property named process is not a process-global access. globalThis.process IS. */
9
14
  private isReference;
10
15
  /** Tags are a checked promise, not an alternative to a runnable compatibility target. */
@@ -57,6 +57,9 @@ class ReactNativeCompatibility {
57
57
  this.isReference(node)) {
58
58
  problems.push(`${absolute}: unsupported React Native global ${node.text}; use a portable implementation or an explicit platform adapter`);
59
59
  }
60
+ const abortProblem = this.abortSignalProblem(absolute, node);
61
+ if (abortProblem)
62
+ problems.push(abortProblem);
60
63
  ts.forEachChild(node, walk);
61
64
  };
62
65
  walk(source);
@@ -81,6 +84,42 @@ class ReactNativeCompatibility {
81
84
  entrypoints.forEach(visitFile);
82
85
  return [...new Set(problems)];
83
86
  }
87
+ abortSignalProblem(absolute, node) {
88
+ if (!ts.isPropertyAccessExpression(node) || !this.isNonPortableAbortSignalExtension(node))
89
+ return undefined;
90
+ return `${absolute}: AbortSignal.${node.name.text} is not React Native compatible; use CallDeadline.throwIfAborted(signal)`;
91
+ }
92
+ /** React Native's abort-controller 3 surface has aborted/addEventListener, but not these DOM additions. */
93
+ isNonPortableAbortSignalExtension(node) {
94
+ if (!['throwIfAborted', 'reason'].includes(node.name.text))
95
+ return false;
96
+ return this.isSignalExpression(node.expression);
97
+ }
98
+ isSignalExpression(expression) {
99
+ if (ts.isIdentifier(expression)) {
100
+ if (/signal$/i.test(expression.text))
101
+ return true;
102
+ return this.hasAbortSignalDeclaration(expression);
103
+ }
104
+ return ts.isPropertyAccessExpression(expression) && expression.name.text === 'signal';
105
+ }
106
+ hasAbortSignalDeclaration(identifier) {
107
+ let found = false;
108
+ const inspect = (node) => {
109
+ if (found)
110
+ return;
111
+ if ((ts.isParameter(node) || ts.isVariableDeclaration(node)) &&
112
+ ts.isIdentifier(node.name) &&
113
+ node.name.text === identifier.text &&
114
+ node.type?.getText() === 'AbortSignal') {
115
+ found = true;
116
+ return;
117
+ }
118
+ ts.forEachChild(node, inspect);
119
+ };
120
+ inspect(identifier.getSourceFile());
121
+ return found;
122
+ }
84
123
  /** A property named process is not a process-global access. globalThis.process IS. */
85
124
  isReference(node) {
86
125
  const parent = node.parent;
@@ -1 +1 @@
1
- {"version":3,"file":"react-native-compatibility.js","sourceRoot":"","sources":["../../../../../packages/tooling/code-rules/src/react-native-compatibility.ts"],"names":[],"mappings":"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","sourcesContent":["import * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport { builtinModules, createRequire } from 'node:module';\nimport * as ts from 'typescript';\n\n/** Checks the complete runtime import closure, including dependencies, without Node/DOM ambient types. */\nexport class ReactNativeCompatibility {\n private readonly builtins = new Set(\n builtinModules.map((name: string): string => name.replace(/^node:/, '')),\n );\n private readonly forbidden = new Set([\n 'window',\n 'document',\n 'localStorage',\n 'sessionStorage',\n 'Buffer',\n 'process',\n 'require',\n '__dirname',\n '__filename',\n 'TextEncoder',\n 'TextDecoder',\n ]);\n\n /** Return actionable violations; callers must fail their build on any entry. */\n inspect(entrypoints: string[], options: ts.CompilerOptions): string[] {\n const problems: string[] = [];\n const seen = new Set<string>();\n const visitFile = (filename: string): void => {\n const absolute = path.resolve(filename);\n if (seen.has(absolute)) return;\n seen.add(absolute);\n if (!fs.existsSync(absolute)) {\n problems.push(`Missing React Native entrypoint: ${absolute}`);\n return;\n }\n const source = ts.createSourceFile(\n absolute,\n fs.readFileSync(absolute, 'utf8'),\n ts.ScriptTarget.Latest,\n true,\n );\n const imports: string[] = [];\n const walk = (node: ts.Node): void => {\n if (\n (ts.isImportDeclaration(node) || ts.isExportDeclaration(node)) &&\n node.moduleSpecifier &&\n ts.isStringLiteral(node.moduleSpecifier)\n ) {\n imports.push(node.moduleSpecifier.text);\n }\n if (\n ts.isCallExpression(node) &&\n (node.expression.kind === ts.SyntaxKind.ImportKeyword ||\n (ts.isIdentifier(node.expression) && node.expression.text === 'require'))\n ) {\n const arg = node.arguments[0];\n if (!arg || !ts.isStringLiteral(arg))\n problems.push(`${absolute}: dynamic module loading is not portable`);\n else imports.push(arg.text);\n }\n if (\n ts.isIdentifier(node) &&\n this.forbidden.has(node.text) &&\n this.isReference(node)\n ) {\n problems.push(\n `${absolute}: unsupported React Native global ${node.text}; use a portable implementation or an explicit platform adapter`,\n );\n }\n ts.forEachChild(node, walk);\n };\n walk(source);\n for (const specifier of imports) {\n if (specifier.startsWith('node:') || this.builtins.has(specifier)) {\n problems.push(\n `${absolute}: Node module ${specifier} is not React Native compatible`,\n );\n continue;\n }\n const resolved = ts.resolveModuleName(\n specifier,\n absolute,\n options,\n ts.sys,\n ).resolvedModule;\n if (!resolved)\n problems.push(`${absolute}: cannot resolve ${specifier} for React Native`);\n else {\n visitFile(resolved.resolvedFileName);\n // Declarations can conceal a Node-only runtime dependency. Inspect its real JS too.\n if (\n resolved.isExternalLibraryImport &&\n resolved.resolvedFileName.endsWith('.d.ts')\n ) {\n visitFile(createRequire(absolute).resolve(specifier));\n }\n }\n }\n };\n entrypoints.forEach(visitFile);\n return [...new Set(problems)];\n }\n\n /** A property named process is not a process-global access. globalThis.process IS. */\n private isReference(node: ts.Identifier): boolean {\n const parent = node.parent;\n if (node.text === 'require' && ts.isCallExpression(parent) && parent.expression === node)\n return false;\n if (ts.isPropertyAccessExpression(parent) && parent.name === node) {\n return (\n ts.isIdentifier(parent.expression) &&\n ['globalThis', 'global'].includes(parent.expression.text)\n );\n }\n if (\n (ts.isPropertyDeclaration(parent) ||\n ts.isPropertySignature(parent) ||\n ts.isMethodDeclaration(parent) ||\n ts.isMethodSignature(parent) ||\n ts.isPropertyAssignment(parent)) &&\n parent.name === node\n )\n return false;\n if (ts.isImportSpecifier(parent) || ts.isExportSpecifier(parent)) return false;\n return true;\n }\n\n /** Tags are a checked promise, not an alternative to a runnable compatibility target. */\n validateTarget(projectFile: string): string[] {\n const project = JSON.parse(fs.readFileSync(projectFile, 'utf8'));\n if (!project.tags?.includes('framework:react-native')) return [];\n const target = project.targets?.['react-native-compat'];\n if (!target?.options?.command || !target.dependsOn?.includes('build')) {\n return [\n `${projectFile}: framework:react-native requires a react-native-compat target depending on build`,\n ];\n }\n if (!project.targets?.ci?.dependsOn?.includes('react-native-compat')) {\n return [\n `${projectFile}: ci must depend on react-native-compat; an optional target does not certify React Native support`,\n ];\n }\n return [];\n }\n}\n"]}
1
+ {"version":3,"file":"react-native-compatibility.js","sourceRoot":"","sources":["../../../../../packages/tooling/code-rules/src/react-native-compatibility.ts"],"names":[],"mappings":"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","sourcesContent":["import * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport { builtinModules, createRequire } from 'node:module';\nimport * as ts from 'typescript';\n\n/** Checks the complete runtime import closure, including dependencies, without Node/DOM ambient types. */\nexport class ReactNativeCompatibility {\n private readonly builtins = new Set(\n builtinModules.map((name: string): string => name.replace(/^node:/, '')),\n );\n private readonly forbidden = new Set([\n 'window',\n 'document',\n 'localStorage',\n 'sessionStorage',\n 'Buffer',\n 'process',\n 'require',\n '__dirname',\n '__filename',\n 'TextEncoder',\n 'TextDecoder',\n ]);\n\n /** Return actionable violations; callers must fail their build on any entry. */\n inspect(entrypoints: string[], options: ts.CompilerOptions): string[] {\n const problems: string[] = [];\n const seen = new Set<string>();\n const visitFile = (filename: string): void => {\n const absolute = path.resolve(filename);\n if (seen.has(absolute)) return;\n seen.add(absolute);\n if (!fs.existsSync(absolute)) {\n problems.push(`Missing React Native entrypoint: ${absolute}`);\n return;\n }\n const source = ts.createSourceFile(\n absolute,\n fs.readFileSync(absolute, 'utf8'),\n ts.ScriptTarget.Latest,\n true,\n );\n const imports: string[] = [];\n const walk = (node: ts.Node): void => {\n if (\n (ts.isImportDeclaration(node) || ts.isExportDeclaration(node)) &&\n node.moduleSpecifier &&\n ts.isStringLiteral(node.moduleSpecifier)\n ) {\n imports.push(node.moduleSpecifier.text);\n }\n if (\n ts.isCallExpression(node) &&\n (node.expression.kind === ts.SyntaxKind.ImportKeyword ||\n (ts.isIdentifier(node.expression) && node.expression.text === 'require'))\n ) {\n const arg = node.arguments[0];\n if (!arg || !ts.isStringLiteral(arg))\n problems.push(`${absolute}: dynamic module loading is not portable`);\n else imports.push(arg.text);\n }\n if (\n ts.isIdentifier(node) &&\n this.forbidden.has(node.text) &&\n this.isReference(node)\n ) {\n problems.push(\n `${absolute}: unsupported React Native global ${node.text}; use a portable implementation or an explicit platform adapter`,\n );\n }\n const abortProblem = this.abortSignalProblem(absolute, node);\n if (abortProblem) problems.push(abortProblem);\n ts.forEachChild(node, walk);\n };\n walk(source);\n for (const specifier of imports) {\n if (specifier.startsWith('node:') || this.builtins.has(specifier)) {\n problems.push(\n `${absolute}: Node module ${specifier} is not React Native compatible`,\n );\n continue;\n }\n const resolved = ts.resolveModuleName(\n specifier,\n absolute,\n options,\n ts.sys,\n ).resolvedModule;\n if (!resolved)\n problems.push(`${absolute}: cannot resolve ${specifier} for React Native`);\n else {\n visitFile(resolved.resolvedFileName);\n // Declarations can conceal a Node-only runtime dependency. Inspect its real JS too.\n if (\n resolved.isExternalLibraryImport &&\n resolved.resolvedFileName.endsWith('.d.ts')\n ) {\n visitFile(createRequire(absolute).resolve(specifier));\n }\n }\n }\n };\n entrypoints.forEach(visitFile);\n return [...new Set(problems)];\n }\n\n private abortSignalProblem(absolute: string, node: ts.Node): string | undefined {\n if (!ts.isPropertyAccessExpression(node) || !this.isNonPortableAbortSignalExtension(node))\n return undefined;\n return `${absolute}: AbortSignal.${node.name.text} is not React Native compatible; use CallDeadline.throwIfAborted(signal)`;\n }\n\n /** React Native's abort-controller 3 surface has aborted/addEventListener, but not these DOM additions. */\n private isNonPortableAbortSignalExtension(node: ts.PropertyAccessExpression): boolean {\n if (!['throwIfAborted', 'reason'].includes(node.name.text)) return false;\n return this.isSignalExpression(node.expression);\n }\n\n private isSignalExpression(expression: ts.Expression): boolean {\n if (ts.isIdentifier(expression)) {\n if (/signal$/i.test(expression.text)) return true;\n return this.hasAbortSignalDeclaration(expression);\n }\n return ts.isPropertyAccessExpression(expression) && expression.name.text === 'signal';\n }\n\n private hasAbortSignalDeclaration(identifier: ts.Identifier): boolean {\n let found = false;\n const inspect = (node: ts.Node): void => {\n if (found) return;\n if (\n (ts.isParameter(node) || ts.isVariableDeclaration(node)) &&\n ts.isIdentifier(node.name) &&\n node.name.text === identifier.text &&\n node.type?.getText() === 'AbortSignal'\n ) {\n found = true;\n return;\n }\n ts.forEachChild(node, inspect);\n };\n inspect(identifier.getSourceFile());\n return found;\n }\n\n /** A property named process is not a process-global access. globalThis.process IS. */\n private isReference(node: ts.Identifier): boolean {\n const parent = node.parent;\n if (node.text === 'require' && ts.isCallExpression(parent) && parent.expression === node)\n return false;\n if (ts.isPropertyAccessExpression(parent) && parent.name === node) {\n return (\n ts.isIdentifier(parent.expression) &&\n ['globalThis', 'global'].includes(parent.expression.text)\n );\n }\n if (\n (ts.isPropertyDeclaration(parent) ||\n ts.isPropertySignature(parent) ||\n ts.isMethodDeclaration(parent) ||\n ts.isMethodSignature(parent) ||\n ts.isPropertyAssignment(parent)) &&\n parent.name === node\n )\n return false;\n if (ts.isImportSpecifier(parent) || ts.isExportSpecifier(parent)) return false;\n return true;\n }\n\n /** Tags are a checked promise, not an alternative to a runnable compatibility target. */\n validateTarget(projectFile: string): string[] {\n const project = JSON.parse(fs.readFileSync(projectFile, 'utf8'));\n if (!project.tags?.includes('framework:react-native')) return [];\n const target = project.targets?.['react-native-compat'];\n if (!target?.options?.command || !target.dependsOn?.includes('build')) {\n return [\n `${projectFile}: framework:react-native requires a react-native-compat target depending on build`,\n ];\n }\n if (!project.targets?.ci?.dependsOn?.includes('react-native-compat')) {\n return [\n `${projectFile}: ci must depend on react-native-compat; an optional target does not certify React Native support`,\n ];\n }\n return [];\n }\n}\n"]}