@webpieces/code-rules 0.4.749 → 0.4.751
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/index.d.ts +1 -0
- package/src/index.js +3 -1
- package/src/index.js.map +1 -1
- package/src/react-native-compatibility.d.ts +12 -0
- package/src/react-native-compatibility.js +124 -0
- package/src/react-native-compatibility.js.map +1 -0
- package/src/validate-framework-tag.js +1 -1
- package/src/validate-framework-tag.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.751",
|
|
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.751",
|
|
20
20
|
"@inversifyjs/binding-decorators": "1.1.5",
|
|
21
21
|
"inversify": "7.10.4",
|
|
22
22
|
"reflect-metadata": "0.2.2"
|
package/src/index.d.ts
CHANGED
|
@@ -22,3 +22,4 @@ export { RoleTagValidator } from './validate-role-tag';
|
|
|
22
22
|
export { PrismaValidateDtosValidator } from './validate-dtos';
|
|
23
23
|
export { PrismaConverterValidator } from './validate-prisma-converters';
|
|
24
24
|
export { default as validateCode } from './validate-code';
|
|
25
|
+
export { ReactNativeCompatibility } from './react-native-compatibility';
|
package/src/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.validateCode = exports.PrismaConverterValidator = exports.PrismaValidateDtosValidator = exports.RoleTagValidator = exports.FrameworkTagValidator = exports.findRedundantInjectInSource = exports.InjectAnnotationNotNeededForConcreteClassValidator = exports.NoFunctionOutsideClassValidator = exports.NoProcessExitOutsideMainValidator = exports.ProjectRoleResolver = exports.StatePathViolation = exports.StatePathHit = exports.NoStatePathsInTemplatesValidator = exports.NoClientCreationOutsideServerOrClientValidator = exports.NoSymbolDiTokensValidator = exports.NoDirectApiResolverValidator = exports.NoDestructureValidator = exports.NoUnmanagedExceptionsValidator = exports.CatchErrorPatternValidator = exports.NoInlineTypeLiteralsValidator = exports.RequireReturnTypeValidator = exports.MaxFileLinesValidator = exports.runNewMethods = exports.runModifiedMethods = exports.MaxMethodLinesValidator = exports.NoImplicitAnyValidator = exports.NoAnyUnknownValidator = exports.CodeValidator = void 0;
|
|
3
|
+
exports.ReactNativeCompatibility = exports.validateCode = exports.PrismaConverterValidator = exports.PrismaValidateDtosValidator = exports.RoleTagValidator = exports.FrameworkTagValidator = exports.findRedundantInjectInSource = exports.InjectAnnotationNotNeededForConcreteClassValidator = exports.NoFunctionOutsideClassValidator = exports.NoProcessExitOutsideMainValidator = exports.ProjectRoleResolver = exports.StatePathViolation = exports.StatePathHit = exports.NoStatePathsInTemplatesValidator = exports.NoClientCreationOutsideServerOrClientValidator = exports.NoSymbolDiTokensValidator = exports.NoDirectApiResolverValidator = exports.NoDestructureValidator = exports.NoUnmanagedExceptionsValidator = exports.CatchErrorPatternValidator = exports.NoInlineTypeLiteralsValidator = exports.RequireReturnTypeValidator = exports.MaxFileLinesValidator = exports.runNewMethods = exports.runModifiedMethods = exports.MaxMethodLinesValidator = exports.NoImplicitAnyValidator = exports.NoAnyUnknownValidator = exports.CodeValidator = void 0;
|
|
4
4
|
const tslib_1 = require("tslib");
|
|
5
5
|
var code_validator_1 = require("./code-validator");
|
|
6
6
|
Object.defineProperty(exports, "CodeValidator", { enumerable: true, get: function () { return code_validator_1.CodeValidator; } });
|
|
@@ -54,4 +54,6 @@ var validate_prisma_converters_1 = require("./validate-prisma-converters");
|
|
|
54
54
|
Object.defineProperty(exports, "PrismaConverterValidator", { enumerable: true, get: function () { return validate_prisma_converters_1.PrismaConverterValidator; } });
|
|
55
55
|
var validate_code_1 = require("./validate-code");
|
|
56
56
|
Object.defineProperty(exports, "validateCode", { enumerable: true, get: function () { return tslib_1.__importDefault(validate_code_1).default; } });
|
|
57
|
+
var react_native_compatibility_1 = require("./react-native-compatibility");
|
|
58
|
+
Object.defineProperty(exports, "ReactNativeCompatibility", { enumerable: true, get: function () { return react_native_compatibility_1.ReactNativeCompatibility; } });
|
|
57
59
|
//# sourceMappingURL=index.js.map
|
package/src/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../packages/tooling/code-rules/src/index.ts"],"names":[],"mappings":";;;;AAAA,mDAAiE;AAAxD,+GAAA,aAAa,OAAA;AAEtB,qEAAkE;AAAzD,gIAAA,qBAAqB,OAAA;AAC9B,uEAAoE;AAA3D,kIAAA,sBAAsB,OAAA;AAC/B,yEAA0F;AAAjF,oIAAA,uBAAuB,OAAA;AAAE,+HAAA,kBAAkB,OAAA;AACpD,+DAAuD;AAA9C,qHAAA,aAAa,OAAA;AACtB,qEAAkE;AAAzD,gIAAA,qBAAqB,OAAA;AAC9B,iEAAqE;AAA5D,mIAAA,0BAA0B,OAAA;AACnC,uEAA2E;AAAlE,yIAAA,6BAA6B,OAAA;AACtC,+EAA4E;AAAnE,0IAAA,0BAA0B,OAAA;AACnC,uFAAoF;AAA3E,kJAAA,8BAA8B,OAAA;AACvC,qEAAmE;AAA1D,iIAAA,sBAAsB,OAAA;AAC/B,qFAAiF;AAAxE,+IAAA,4BAA4B,OAAA;AACrC,+EAA2E;AAAlE,yIAAA,yBAAyB,OAAA;AAClC,+HAAwH;AAA/G,sLAAA,8CAA8C,OAAA;AACvD,+FAA4H;AAAnH,wJAAA,gCAAgC,OAAA;AAAE,oIAAA,YAAY,OAAA;AAAE,0IAAA,kBAAkB,OAAA;AAC3E,iEAA8D;AAArD,4HAAA,mBAAmB,OAAA;AAC5B,iGAA4F;AAAnF,0JAAA,iCAAiC,OAAA;AAC1C,2FAAuF;AAA9E,qJAAA,+BAA+B,OAAA;AACxC,uIAA6J;AAApJ,8LAAA,kDAAkD,OAAA;AAAE,uKAAA,2BAA2B,OAAA;AACxF,mEAAiE;AAAxD,+HAAA,qBAAqB,OAAA;AAC9B,yDAAuD;AAA9C,qHAAA,gBAAgB,OAAA;AACzB,iDAA8D;AAArD,4HAAA,2BAA2B,OAAA;AACpC,2EAAwE;AAA/D,sIAAA,wBAAwB,OAAA;AACjC,iDAA0D;AAAjD,sIAAA,OAAO,OAAgB","sourcesContent":["export { CodeValidator, ExecutorResult } from './code-validator';\n\nexport { NoAnyUnknownValidator } from './validate-no-any-unknown';\nexport { NoImplicitAnyValidator } from './validate-no-implicit-any';\nexport { MaxMethodLinesValidator, runModifiedMethods } from './validate-modified-methods';\nexport { runNewMethods } from './validate-new-methods';\nexport { MaxFileLinesValidator } from './validate-modified-files';\nexport { RequireReturnTypeValidator } from './validate-return-types';\nexport { NoInlineTypeLiteralsValidator } from './validate-no-inline-types';\nexport { CatchErrorPatternValidator } from './validate-catch-error-pattern';\nexport { NoUnmanagedExceptionsValidator } from './validate-no-unmanaged-exceptions';\nexport { NoDestructureValidator } from './validate-no-destructure';\nexport { NoDirectApiResolverValidator } from './validate-no-direct-api-resolver';\nexport { NoSymbolDiTokensValidator } from './validate-no-symbol-di-tokens';\nexport { NoClientCreationOutsideServerOrClientValidator } from './validate-no-client-creation-outside-server-or-client';\nexport { NoStatePathsInTemplatesValidator, StatePathHit, StatePathViolation } from './validate-no-state-paths-in-templates';\nexport { ProjectRoleResolver } from './project-role-resolver';\nexport { NoProcessExitOutsideMainValidator } from './validate-no-process-exit-outside-main';\nexport { NoFunctionOutsideClassValidator } from './validate-no-function-outside-class';\nexport { InjectAnnotationNotNeededForConcreteClassValidator, findRedundantInjectInSource } from './validate-inject-annotation-not-needed-for-concrete-class';\nexport { FrameworkTagValidator } from './validate-framework-tag';\nexport { RoleTagValidator } from './validate-role-tag';\nexport { PrismaValidateDtosValidator } from './validate-dtos';\nexport { PrismaConverterValidator } from './validate-prisma-converters';\nexport { default as validateCode } from './validate-code';\n"]}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../packages/tooling/code-rules/src/index.ts"],"names":[],"mappings":";;;;AAAA,mDAAiE;AAAxD,+GAAA,aAAa,OAAA;AAEtB,qEAAkE;AAAzD,gIAAA,qBAAqB,OAAA;AAC9B,uEAAoE;AAA3D,kIAAA,sBAAsB,OAAA;AAC/B,yEAA0F;AAAjF,oIAAA,uBAAuB,OAAA;AAAE,+HAAA,kBAAkB,OAAA;AACpD,+DAAuD;AAA9C,qHAAA,aAAa,OAAA;AACtB,qEAAkE;AAAzD,gIAAA,qBAAqB,OAAA;AAC9B,iEAAqE;AAA5D,mIAAA,0BAA0B,OAAA;AACnC,uEAA2E;AAAlE,yIAAA,6BAA6B,OAAA;AACtC,+EAA4E;AAAnE,0IAAA,0BAA0B,OAAA;AACnC,uFAAoF;AAA3E,kJAAA,8BAA8B,OAAA;AACvC,qEAAmE;AAA1D,iIAAA,sBAAsB,OAAA;AAC/B,qFAAiF;AAAxE,+IAAA,4BAA4B,OAAA;AACrC,+EAA2E;AAAlE,yIAAA,yBAAyB,OAAA;AAClC,+HAAwH;AAA/G,sLAAA,8CAA8C,OAAA;AACvD,+FAA4H;AAAnH,wJAAA,gCAAgC,OAAA;AAAE,oIAAA,YAAY,OAAA;AAAE,0IAAA,kBAAkB,OAAA;AAC3E,iEAA8D;AAArD,4HAAA,mBAAmB,OAAA;AAC5B,iGAA4F;AAAnF,0JAAA,iCAAiC,OAAA;AAC1C,2FAAuF;AAA9E,qJAAA,+BAA+B,OAAA;AACxC,uIAA6J;AAApJ,8LAAA,kDAAkD,OAAA;AAAE,uKAAA,2BAA2B,OAAA;AACxF,mEAAiE;AAAxD,+HAAA,qBAAqB,OAAA;AAC9B,yDAAuD;AAA9C,qHAAA,gBAAgB,OAAA;AACzB,iDAA8D;AAArD,4HAAA,2BAA2B,OAAA;AACpC,2EAAwE;AAA/D,sIAAA,wBAAwB,OAAA;AACjC,iDAA0D;AAAjD,sIAAA,OAAO,OAAgB;AAEhC,2EAAwE;AAA/D,sIAAA,wBAAwB,OAAA","sourcesContent":["export { CodeValidator, ExecutorResult } from './code-validator';\n\nexport { NoAnyUnknownValidator } from './validate-no-any-unknown';\nexport { NoImplicitAnyValidator } from './validate-no-implicit-any';\nexport { MaxMethodLinesValidator, runModifiedMethods } from './validate-modified-methods';\nexport { runNewMethods } from './validate-new-methods';\nexport { MaxFileLinesValidator } from './validate-modified-files';\nexport { RequireReturnTypeValidator } from './validate-return-types';\nexport { NoInlineTypeLiteralsValidator } from './validate-no-inline-types';\nexport { CatchErrorPatternValidator } from './validate-catch-error-pattern';\nexport { NoUnmanagedExceptionsValidator } from './validate-no-unmanaged-exceptions';\nexport { NoDestructureValidator } from './validate-no-destructure';\nexport { NoDirectApiResolverValidator } from './validate-no-direct-api-resolver';\nexport { NoSymbolDiTokensValidator } from './validate-no-symbol-di-tokens';\nexport { NoClientCreationOutsideServerOrClientValidator } from './validate-no-client-creation-outside-server-or-client';\nexport { NoStatePathsInTemplatesValidator, StatePathHit, StatePathViolation } from './validate-no-state-paths-in-templates';\nexport { ProjectRoleResolver } from './project-role-resolver';\nexport { NoProcessExitOutsideMainValidator } from './validate-no-process-exit-outside-main';\nexport { NoFunctionOutsideClassValidator } from './validate-no-function-outside-class';\nexport { InjectAnnotationNotNeededForConcreteClassValidator, findRedundantInjectInSource } from './validate-inject-annotation-not-needed-for-concrete-class';\nexport { FrameworkTagValidator } from './validate-framework-tag';\nexport { RoleTagValidator } from './validate-role-tag';\nexport { PrismaValidateDtosValidator } from './validate-dtos';\nexport { PrismaConverterValidator } from './validate-prisma-converters';\nexport { default as validateCode } from './validate-code';\n\nexport { ReactNativeCompatibility } from './react-native-compatibility';\n"]}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import * as ts from 'typescript';
|
|
2
|
+
/** Checks the complete runtime import closure, including dependencies, without Node/DOM ambient types. */
|
|
3
|
+
export declare class ReactNativeCompatibility {
|
|
4
|
+
private readonly builtins;
|
|
5
|
+
private readonly forbidden;
|
|
6
|
+
/** Return actionable violations; callers must fail their build on any entry. */
|
|
7
|
+
inspect(entrypoints: string[], options: ts.CompilerOptions): string[];
|
|
8
|
+
/** A property named process is not a process-global access. globalThis.process IS. */
|
|
9
|
+
private isReference;
|
|
10
|
+
/** Tags are a checked promise, not an alternative to a runnable compatibility target. */
|
|
11
|
+
validateTarget(projectFile: string): string[];
|
|
12
|
+
}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ReactNativeCompatibility = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const fs = tslib_1.__importStar(require("node:fs"));
|
|
6
|
+
const path = tslib_1.__importStar(require("node:path"));
|
|
7
|
+
const node_module_1 = require("node:module");
|
|
8
|
+
const ts = tslib_1.__importStar(require("typescript"));
|
|
9
|
+
/** Checks the complete runtime import closure, including dependencies, without Node/DOM ambient types. */
|
|
10
|
+
class ReactNativeCompatibility {
|
|
11
|
+
builtins = new Set(node_module_1.builtinModules.map((name) => name.replace(/^node:/, '')));
|
|
12
|
+
forbidden = new Set([
|
|
13
|
+
'window',
|
|
14
|
+
'document',
|
|
15
|
+
'localStorage',
|
|
16
|
+
'sessionStorage',
|
|
17
|
+
'Buffer',
|
|
18
|
+
'process',
|
|
19
|
+
'require',
|
|
20
|
+
'__dirname',
|
|
21
|
+
'__filename',
|
|
22
|
+
'TextEncoder',
|
|
23
|
+
'TextDecoder',
|
|
24
|
+
]);
|
|
25
|
+
/** Return actionable violations; callers must fail their build on any entry. */
|
|
26
|
+
inspect(entrypoints, options) {
|
|
27
|
+
const problems = [];
|
|
28
|
+
const seen = new Set();
|
|
29
|
+
const visitFile = (filename) => {
|
|
30
|
+
const absolute = path.resolve(filename);
|
|
31
|
+
if (seen.has(absolute))
|
|
32
|
+
return;
|
|
33
|
+
seen.add(absolute);
|
|
34
|
+
if (!fs.existsSync(absolute)) {
|
|
35
|
+
problems.push(`Missing React Native entrypoint: ${absolute}`);
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
const source = ts.createSourceFile(absolute, fs.readFileSync(absolute, 'utf8'), ts.ScriptTarget.Latest, true);
|
|
39
|
+
const imports = [];
|
|
40
|
+
const walk = (node) => {
|
|
41
|
+
if ((ts.isImportDeclaration(node) || ts.isExportDeclaration(node)) &&
|
|
42
|
+
node.moduleSpecifier &&
|
|
43
|
+
ts.isStringLiteral(node.moduleSpecifier)) {
|
|
44
|
+
imports.push(node.moduleSpecifier.text);
|
|
45
|
+
}
|
|
46
|
+
if (ts.isCallExpression(node) &&
|
|
47
|
+
(node.expression.kind === ts.SyntaxKind.ImportKeyword ||
|
|
48
|
+
(ts.isIdentifier(node.expression) && node.expression.text === 'require'))) {
|
|
49
|
+
const arg = node.arguments[0];
|
|
50
|
+
if (!arg || !ts.isStringLiteral(arg))
|
|
51
|
+
problems.push(`${absolute}: dynamic module loading is not portable`);
|
|
52
|
+
else
|
|
53
|
+
imports.push(arg.text);
|
|
54
|
+
}
|
|
55
|
+
if (ts.isIdentifier(node) &&
|
|
56
|
+
this.forbidden.has(node.text) &&
|
|
57
|
+
this.isReference(node)) {
|
|
58
|
+
problems.push(`${absolute}: unsupported React Native global ${node.text}; use a portable implementation or an explicit platform adapter`);
|
|
59
|
+
}
|
|
60
|
+
ts.forEachChild(node, walk);
|
|
61
|
+
};
|
|
62
|
+
walk(source);
|
|
63
|
+
for (const specifier of imports) {
|
|
64
|
+
if (specifier.startsWith('node:') || this.builtins.has(specifier)) {
|
|
65
|
+
problems.push(`${absolute}: Node module ${specifier} is not React Native compatible`);
|
|
66
|
+
continue;
|
|
67
|
+
}
|
|
68
|
+
const resolved = ts.resolveModuleName(specifier, absolute, options, ts.sys).resolvedModule;
|
|
69
|
+
if (!resolved)
|
|
70
|
+
problems.push(`${absolute}: cannot resolve ${specifier} for React Native`);
|
|
71
|
+
else {
|
|
72
|
+
visitFile(resolved.resolvedFileName);
|
|
73
|
+
// Declarations can conceal a Node-only runtime dependency. Inspect its real JS too.
|
|
74
|
+
if (resolved.isExternalLibraryImport &&
|
|
75
|
+
resolved.resolvedFileName.endsWith('.d.ts')) {
|
|
76
|
+
visitFile((0, node_module_1.createRequire)(absolute).resolve(specifier));
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
};
|
|
81
|
+
entrypoints.forEach(visitFile);
|
|
82
|
+
return [...new Set(problems)];
|
|
83
|
+
}
|
|
84
|
+
/** A property named process is not a process-global access. globalThis.process IS. */
|
|
85
|
+
isReference(node) {
|
|
86
|
+
const parent = node.parent;
|
|
87
|
+
if (node.text === 'require' && ts.isCallExpression(parent) && parent.expression === node)
|
|
88
|
+
return false;
|
|
89
|
+
if (ts.isPropertyAccessExpression(parent) && parent.name === node) {
|
|
90
|
+
return (ts.isIdentifier(parent.expression) &&
|
|
91
|
+
['globalThis', 'global'].includes(parent.expression.text));
|
|
92
|
+
}
|
|
93
|
+
if ((ts.isPropertyDeclaration(parent) ||
|
|
94
|
+
ts.isPropertySignature(parent) ||
|
|
95
|
+
ts.isMethodDeclaration(parent) ||
|
|
96
|
+
ts.isMethodSignature(parent) ||
|
|
97
|
+
ts.isPropertyAssignment(parent)) &&
|
|
98
|
+
parent.name === node)
|
|
99
|
+
return false;
|
|
100
|
+
if (ts.isImportSpecifier(parent) || ts.isExportSpecifier(parent))
|
|
101
|
+
return false;
|
|
102
|
+
return true;
|
|
103
|
+
}
|
|
104
|
+
/** Tags are a checked promise, not an alternative to a runnable compatibility target. */
|
|
105
|
+
validateTarget(projectFile) {
|
|
106
|
+
const project = JSON.parse(fs.readFileSync(projectFile, 'utf8'));
|
|
107
|
+
if (!project.tags?.includes('framework:react-native'))
|
|
108
|
+
return [];
|
|
109
|
+
const target = project.targets?.['react-native-compat'];
|
|
110
|
+
if (!target?.options?.command || !target.dependsOn?.includes('build')) {
|
|
111
|
+
return [
|
|
112
|
+
`${projectFile}: framework:react-native requires a react-native-compat target depending on build`,
|
|
113
|
+
];
|
|
114
|
+
}
|
|
115
|
+
if (!project.targets?.ci?.dependsOn?.includes('react-native-compat')) {
|
|
116
|
+
return [
|
|
117
|
+
`${projectFile}: ci must depend on react-native-compat; an optional target does not certify React Native support`,
|
|
118
|
+
];
|
|
119
|
+
}
|
|
120
|
+
return [];
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
exports.ReactNativeCompatibility = ReactNativeCompatibility;
|
|
124
|
+
//# sourceMappingURL=react-native-compatibility.js.map
|
|
@@ -0,0 +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"]}
|
|
@@ -41,7 +41,7 @@ const code_validator_1 = require("./code-validator");
|
|
|
41
41
|
const inversify_1 = require("inversify");
|
|
42
42
|
const tag_rule_1 = require("./tag-rule");
|
|
43
43
|
const FRAMEWORK_TAG_PREFIX = 'framework:';
|
|
44
|
-
const DEFAULT_KNOWN_TYPES = ['browser', 'react', 'angular', 'node', 'express'];
|
|
44
|
+
const DEFAULT_KNOWN_TYPES = ['browser', 'react', 'angular', 'node', 'express', 'react-native'];
|
|
45
45
|
/** The removed legacy libType, kept only to emit a targeted migration message. */
|
|
46
46
|
const REMOVED_ALL_VALUE = 'all';
|
|
47
47
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validate-framework-tag.js","sourceRoot":"","sources":["../../../../../packages/tooling/code-rules/src/validate-framework-tag.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;;;AAuBH,oDAEC;;AAvBD,0DAA0E;AAC1E,qDAAiE;AACjE,yCAA2D;AAC3D,yCAMoB;AAEpB,MAAM,oBAAoB,GAAG,YAAY,CAAC;AAC1C,MAAM,mBAAmB,GAAG,CAAC,SAAS,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,CAAC,CAAC;AAE/
|
|
1
|
+
{"version":3,"file":"validate-framework-tag.js","sourceRoot":"","sources":["../../../../../packages/tooling/code-rules/src/validate-framework-tag.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Validate Framework Tag Executor\n *\n * Every project that a changed source file belongs to must carry at least one\n * `framework:<value>` nx tag in its project.json. Those tags are the project's\n * \"libType\" — the SET of runtime environments it is validated to run in, drawn\n * from the atomic values:\n *\n * framework:browser | framework:react | framework:angular\n * framework:node | framework:express\n *\n * A project lists EVERY environment it promises to run in (e.g.\n * `framework:browser` + `framework:node`). This env set is the source of truth\n * for the `framework` field written into architecture/dependencies.json and for\n * the `library-types-match-client` rule, which uses the compatibility lattice\n * (react/angular→browser, express→node) to keep an express project from\n * depending on a browser-only library (and vice-versa).\n *\n * The legacy single-value `framework:all` \"usable by any side\" bucket is\n * REMOVED — it is a hard error, and the author must declare the actual env set.\n *\n * The project-walking + diff-scoping + mode logic is shared with the `role-tag`\n * rule in `tag-rule.ts`; this file supplies only the framework-specific prefix,\n * known values, and violation messages. Unlike role-tag, framework-tag ALSO\n * validates tag VALUES (allowing multiple) via {@link TagRuleSpec.validateValues}.\n *\n * ============================================================================\n * MODES (PROJECT-LEVEL)\n * ============================================================================\n * - OFF: Skip validation entirely.\n * - MODIFIED_PROJECTS: Require >=1 valid framework tag on every project that\n * owns ANY changed file (not just .ts, and not line-scoped).\n */\n\nimport { ProjectMode, FrameworkTagConfig } from '@webpieces/rules-config';\nimport { CodeValidator, ExecutorResult } from './code-validator';\nimport { injectable, bindingScopeValues } from 'inversify';\nimport {\n InvalidTagProject,\n MissingTagProject,\n TagRuleSpec,\n findProjectsMissingTag,\n runTagValidator,\n} from './tag-rule';\n\nconst FRAMEWORK_TAG_PREFIX = 'framework:';\nconst DEFAULT_KNOWN_TYPES = ['browser', 'react', 'angular', 'node', 'express', 'react-native'];\n\n/** The removed legacy libType, kept only to emit a targeted migration message. */\nconst REMOVED_ALL_VALUE = 'all';\n\n/**\n * Back-compat export used by tests: the framework-tag flavor of the shared\n * missing-tag scan.\n */\nexport function findUntaggedProjects(workspaceRoot: string, changedFiles: string[]): MissingTagProject[] {\n return findProjectsMissingTag(workspaceRoot, changedFiles, FRAMEWORK_TAG_PREFIX);\n}\n\nfunction reportViolations(untagged: MissingTagProject[], knownTypes: string[], mode: ProjectMode): void {\n const suggestion = knownTypes.map((t: string) => `${FRAMEWORK_TAG_PREFIX}${t}`).join(' | ');\n console.error('');\n console.error('❌ Every modified project must declare the env set it runs in (>=1 framework tag)!');\n console.error('');\n console.error(` Add ONE OR MORE of these to the project's project.json \"tags\" array: ${suggestion}`);\n console.error(' (react/angular specialize browser; express specializes node. A project that runs in');\n console.error(' both the browser and node declares BOTH, e.g. framework:browser + framework:node.)');\n console.error(' This libType drives architecture/dependencies.json and the library-types-match-client rule.');\n console.error('');\n\n for (const project of untagged) {\n console.error(` ❌ ${project.name} — ${project.projectJsonPath}`);\n console.error(` add e.g. \"tags\": [\"${FRAMEWORK_TAG_PREFIX}browser\", \"${FRAMEWORK_TAG_PREFIX}node\"]`);\n }\n console.error('');\n console.error(` Current mode: ${mode}`);\n console.error('');\n}\n\nfunction reportInvalidValues(invalid: InvalidTagProject[], knownTypes: string[], mode: ProjectMode): void {\n const known = knownTypes.map((t: string) => `${FRAMEWORK_TAG_PREFIX}${t}`).join(' | ');\n console.error('');\n console.error('❌ Some modified projects carry an unknown framework tag value!');\n console.error('');\n console.error(` Allowed values: ${known}`);\n console.error('');\n\n for (const project of invalid) {\n console.error(` ❌ ${project.name} — ${project.projectJsonPath}`);\n for (const bad of project.badValues) {\n if (bad === REMOVED_ALL_VALUE) {\n console.error(\n ` framework:all is removed — declare the actual env set, ` +\n `e.g. framework:browser + framework:node`\n );\n } else {\n console.error(` unknown value \"${FRAMEWORK_TAG_PREFIX}${bad}\" — use one of: ${known}`);\n }\n }\n }\n console.error('');\n console.error(` Current mode: ${mode}`);\n console.error('');\n}\n\nconst FRAMEWORK_TAG_SPEC = new TagRuleSpec(\n FRAMEWORK_TAG_PREFIX,\n 'framework-tag',\n 'Framework Tag',\n DEFAULT_KNOWN_TYPES,\n reportViolations,\n true,\n reportInvalidValues\n);\n\n@injectable(bindingScopeValues.Singleton)\nexport class FrameworkTagValidator extends CodeValidator<FrameworkTagConfig> {\n constructor(config: FrameworkTagConfig) {\n super(config, 'framework-tag', 'framework-tag');\n }\n\n async run(workspaceRoot: string): Promise<ExecutorResult> {\n return runTagValidator(this.config, workspaceRoot, FRAMEWORK_TAG_SPEC);\n }\n}\n"]}
|