layer checker: follow parent symbols

This commit is contained in:
João Moreno 2022-04-04 15:04:29 +02:00
parent 56e31e2996
commit d06e16b59a
No known key found for this signature in database
GPG key ID: 896B853774D1A575
2 changed files with 79 additions and 118 deletions

View file

@ -29,30 +29,13 @@ const CORE_TYPES = [
'setInterval',
'clearInterval',
'console',
'log',
'info',
'warn',
'error',
'trace',
'group',
'groupEnd',
'table',
'assert',
'Console',
'Error',
'ErrorConstructor',
'String',
'throws',
'stack',
'captureStackTrace',
'stackTraceLimit',
'TextDecoder',
'TextEncoder',
'encode',
'decode',
'self',
'trimStart',
'trimEnd',
'trimLeft',
'trimRight',
'queueMicrotask',
'Array',
'Uint8Array',
@ -71,16 +54,8 @@ const CORE_TYPES = [
'AbortSignal',
'MessageChannel',
'MessagePort',
'URLSearchParams',
'URL',
'protocol',
'hostname',
'port',
'pathname',
'search',
'username',
'password',
'origin'
'URLSearchParams'
];
// Types that are defined in a common layer but are known to be only
// available in native environments should not be allowed in browser
@ -104,7 +79,6 @@ const RULES = [
...CORE_TYPES,
// Safe access to postMessage() and friends
'MessageEvent',
'data'
],
disallowedTypes: NATIVE_TYPES,
disallowedDefinitions: [
@ -190,9 +164,7 @@ const RULES = [
// node.js
{
target: '**/vs/**/node/**',
allowedTypes: [
...CORE_TYPES
],
allowedTypes: CORE_TYPES,
disallowedDefinitions: [
'lib.dom.d.ts' // no DOM
]
@ -232,43 +204,49 @@ function checkFile(program, sourceFile, rule) {
if (node.kind !== ts.SyntaxKind.Identifier) {
return ts.forEachChild(node, checkNode); // recurse down
}
const text = node.getText(sourceFile);
const checker = program.getTypeChecker();
const symbol = checker.getSymbolAtLocation(node);
if (!symbol) {
return;
}
let _parentSymbol = symbol;
while (_parentSymbol.parent) {
_parentSymbol = _parentSymbol.parent;
}
const parentSymbol = _parentSymbol;
const text = parentSymbol.getName();
if (rule.allowedTypes?.some(allowed => allowed === text)) {
return; // override
}
if (rule.disallowedTypes?.some(disallowed => disallowed === text)) {
const { line, character } = sourceFile.getLineAndCharacterOfPosition(node.getStart());
console.log(`[build/lib/layersChecker.ts]: Reference to '${text}' violates layer '${rule.target}' (${sourceFile.fileName} (${line + 1},${character + 1})`);
console.log(`[build/lib/layersChecker.ts]: Reference to type '${text}' violates layer '${rule.target}' (${sourceFile.fileName} (${line + 1},${character + 1})`);
hasErrors = true;
return;
}
const checker = program.getTypeChecker();
const symbol = checker.getSymbolAtLocation(node);
if (symbol) {
const declarations = symbol.declarations;
if (Array.isArray(declarations)) {
DeclarationLoop: for (const declaration of declarations) {
if (declaration) {
const parent = declaration.parent;
if (parent) {
const parentSourceFile = parent.getSourceFile();
if (parentSourceFile) {
const definitionFileName = parentSourceFile.fileName;
if (rule.allowedDefinitions) {
for (const allowedDefinition of rule.allowedDefinitions) {
if (definitionFileName.indexOf(allowedDefinition) >= 0) {
continue DeclarationLoop;
}
const declarations = symbol.declarations;
if (Array.isArray(declarations)) {
DeclarationLoop: for (const declaration of declarations) {
if (declaration) {
const parent = declaration.parent;
if (parent) {
const parentSourceFile = parent.getSourceFile();
if (parentSourceFile) {
const definitionFileName = parentSourceFile.fileName;
if (rule.allowedDefinitions) {
for (const allowedDefinition of rule.allowedDefinitions) {
if (definitionFileName.indexOf(allowedDefinition) >= 0) {
continue DeclarationLoop;
}
}
if (rule.disallowedDefinitions) {
for (const disallowedDefinition of rule.disallowedDefinitions) {
if (definitionFileName.indexOf(disallowedDefinition) >= 0) {
const { line, character } = sourceFile.getLineAndCharacterOfPosition(node.getStart());
console.log(`[build/lib/layersChecker.ts]: Reference to '${text}' from '${disallowedDefinition}' violates layer '${rule.target}' (${sourceFile.fileName} (${line + 1},${character + 1})`);
hasErrors = true;
return;
}
}
if (rule.disallowedDefinitions) {
for (const disallowedDefinition of rule.disallowedDefinitions) {
if (definitionFileName.indexOf(disallowedDefinition) >= 0) {
const { line, character } = sourceFile.getLineAndCharacterOfPosition(node.getStart());
console.log(`[build/lib/layersChecker.ts]: Reference to symbol '${text}' from '${disallowedDefinition}' violates layer '${rule.target}' (${sourceFile.fileName} (${line + 1},${character + 1})`);
hasErrors = true;
return;
}
}
}

View file

@ -30,30 +30,13 @@ const CORE_TYPES = [
'setInterval',
'clearInterval',
'console',
'log',
'info',
'warn',
'error',
'trace',
'group',
'groupEnd',
'table',
'assert',
'Console',
'Error',
'ErrorConstructor',
'String',
'throws',
'stack',
'captureStackTrace',
'stackTraceLimit',
'TextDecoder',
'TextEncoder',
'encode',
'decode',
'self',
'trimStart',
'trimEnd',
'trimLeft',
'trimRight',
'queueMicrotask',
'Array',
'Uint8Array',
@ -72,16 +55,8 @@ const CORE_TYPES = [
'AbortSignal',
'MessageChannel',
'MessagePort',
'URLSearchParams',
'URL',
'protocol',
'hostname',
'port',
'pathname',
'search',
'username',
'password',
'origin'
'URLSearchParams'
];
// Types that are defined in a common layer but are known to be only
@ -110,7 +85,6 @@ const RULES = [
// Safe access to postMessage() and friends
'MessageEvent',
'data'
],
disallowedTypes: NATIVE_TYPES,
disallowedDefinitions: [
@ -205,9 +179,7 @@ const RULES = [
// node.js
{
target: '**/vs/**/node/**',
allowedTypes: [
...CORE_TYPES
],
allowedTypes: CORE_TYPES,
disallowedDefinitions: [
'lib.dom.d.ts' // no DOM
]
@ -265,7 +237,21 @@ function checkFile(program: ts.Program, sourceFile: ts.SourceFile, rule: IRule)
return ts.forEachChild(node, checkNode); // recurse down
}
const text = node.getText(sourceFile);
const checker = program.getTypeChecker();
const symbol = checker.getSymbolAtLocation(node);
if (!symbol) {
return;
}
let _parentSymbol: any = symbol;
while (_parentSymbol.parent) {
_parentSymbol = _parentSymbol.parent;
}
const parentSymbol = _parentSymbol as ts.Symbol;
const text = parentSymbol.getName();
if (rule.allowedTypes?.some(allowed => allowed === text)) {
return; // override
@ -273,40 +259,37 @@ function checkFile(program: ts.Program, sourceFile: ts.SourceFile, rule: IRule)
if (rule.disallowedTypes?.some(disallowed => disallowed === text)) {
const { line, character } = sourceFile.getLineAndCharacterOfPosition(node.getStart());
console.log(`[build/lib/layersChecker.ts]: Reference to '${text}' violates layer '${rule.target}' (${sourceFile.fileName} (${line + 1},${character + 1})`);
console.log(`[build/lib/layersChecker.ts]: Reference to type '${text}' violates layer '${rule.target}' (${sourceFile.fileName} (${line + 1},${character + 1})`);
hasErrors = true;
return;
}
const checker = program.getTypeChecker();
const symbol = checker.getSymbolAtLocation(node);
if (symbol) {
const declarations = symbol.declarations;
if (Array.isArray(declarations)) {
DeclarationLoop: for (const declaration of declarations) {
if (declaration) {
const parent = declaration.parent;
if (parent) {
const parentSourceFile = parent.getSourceFile();
if (parentSourceFile) {
const definitionFileName = parentSourceFile.fileName;
if (rule.allowedDefinitions) {
for (const allowedDefinition of rule.allowedDefinitions) {
if (definitionFileName.indexOf(allowedDefinition) >= 0) {
continue DeclarationLoop;
}
const declarations = symbol.declarations;
if (Array.isArray(declarations)) {
DeclarationLoop: for (const declaration of declarations) {
if (declaration) {
const parent = declaration.parent;
if (parent) {
const parentSourceFile = parent.getSourceFile();
if (parentSourceFile) {
const definitionFileName = parentSourceFile.fileName;
if (rule.allowedDefinitions) {
for (const allowedDefinition of rule.allowedDefinitions) {
if (definitionFileName.indexOf(allowedDefinition) >= 0) {
continue DeclarationLoop;
}
}
if (rule.disallowedDefinitions) {
for (const disallowedDefinition of rule.disallowedDefinitions) {
if (definitionFileName.indexOf(disallowedDefinition) >= 0) {
const { line, character } = sourceFile.getLineAndCharacterOfPosition(node.getStart());
console.log(`[build/lib/layersChecker.ts]: Reference to '${text}' from '${disallowedDefinition}' violates layer '${rule.target}' (${sourceFile.fileName} (${line + 1},${character + 1})`);
}
if (rule.disallowedDefinitions) {
for (const disallowedDefinition of rule.disallowedDefinitions) {
if (definitionFileName.indexOf(disallowedDefinition) >= 0) {
const { line, character } = sourceFile.getLineAndCharacterOfPosition(node.getStart());
hasErrors = true;
return;
}
console.log(`[build/lib/layersChecker.ts]: Reference to symbol '${text}' from '${disallowedDefinition}' violates layer '${rule.target}' (${sourceFile.fileName} (${line + 1},${character + 1})`);
hasErrors = true;
return;
}
}
}