build/lib/layersChecker.ts/checkFile
function checkFile(program: ts.Program, sourceFile: ts.SourceFile, rule: IRule) {
	checkNode(sourceFile);

	function checkNode(node: ts.Node): void {
		if (node.kind !== ts.SyntaxKind.Identifier) {
			return ts.forEachChild(node, checkNode); // recurse down
		}

		const text = node.getText(sourceFile);

		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})`);

			hasErrors = true;
			return;
		}

		const checker = program.getTypeChecker();
		const symbol = checker.getSymbolAtLocation(node);
		if (symbol) {
			const declarations = symbol.declarations;
			if (Array.isArray(declarations)) {
				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.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;
										}
									}
								}
							}
						}
					}
				}
			}
		}
	}
}