UNPKG

@bazel/typescript

Version:
60 lines (59 loc) 2.4 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); // TODO: Export the matched node kinds here. /** * This class matches a property access node, based on a property holder type * (through its name), i.e. a class, and a property name. * * The logic is voluntarily simple: if a matcher for `a.b` tests a `x.y` node, * it will return true if: * - `x` is of type `a` either directly (name-based) or through inheritance * (ditto), * - and, textually, `y` === `b`. * * Note that the logic is different from TS's type system: this matcher doesn't * have any knowledge of structural typing. */ class PropertyMatcher { constructor(bannedType, bannedProperty) { this.bannedType = bannedType; this.bannedProperty = bannedProperty; } static fromSpec(spec) { if (spec.indexOf('.prototype.') === -1) { throw new Error(`BANNED_PROPERTY expects a .prototype in your query.`); } const requestParser = /^([\w\d_.-]+)\.prototype\.([\w\d_.-]+)$/; const matches = requestParser.exec(spec); if (!matches) { throw new Error('Cannot understand the BannedProperty spec' + spec); } const [bannedType, bannedProperty] = matches.slice(1); return new PropertyMatcher(bannedType, bannedProperty); } /** * @param n The PropertyAccessExpression we're looking at. */ matches(n, tc) { return n.name.text === this.bannedProperty && this.typeMatches(tc.getTypeAtLocation(n.expression)); } exactTypeMatches(inspectedType) { const typeSymbol = inspectedType.getSymbol() || false; return typeSymbol && typeSymbol.getName() === this.bannedType; } // TODO: Account for unknown types/ '?', and 'loose type matches', i.e. if the // actual type is a supertype of the prohibited type. typeMatches(inspectedType) { if (this.exactTypeMatches(inspectedType)) { return true; } // If the type is an intersection/union, check if any of the component matches if (inspectedType.isUnionOrIntersection()) { return inspectedType.types.some(comp => this.typeMatches(comp)); } const baseTypes = inspectedType.getBaseTypes() || []; return baseTypes.some(base => this.typeMatches(base)); } } exports.PropertyMatcher = PropertyMatcher;