Area restrita - Questionario

This commit is contained in:
2026-06-08 23:50:59 -03:00
parent f2e2400637
commit ef968f10ae
6972 changed files with 23454 additions and 2267883 deletions
+235 -19
View File
@@ -6,6 +6,7 @@ const {
types: t$1,
template: template
} = _babel.default || _babel;
const PossibleGlobalObjects = new Set(["global", "globalThis", "self", "window"]);
function intersection(a, b) {
const result = new Set();
a.forEach(v => b.has(v) && result.add(v));
@@ -14,18 +15,18 @@ function intersection(a, b) {
function has$1(object, key) {
return Object.prototype.hasOwnProperty.call(object, key);
}
function resolve$1(path, resolved = new Set()) {
if (resolved.has(path)) return;
resolved.add(path);
function resolve$1(path, seen = new Set()) {
if (seen.has(path)) return;
seen.add(path);
if (path.isVariableDeclarator()) {
if (path.get("id").isIdentifier()) {
return resolve$1(path.get("init"), resolved);
return resolve$1(path.get("init"), seen);
}
} else if (path.isReferencedIdentifier()) {
const binding = path.scope.getBinding(path.node.name);
if (!binding) return path;
if (!binding.constant) return;
return resolve$1(binding.path, resolved);
return resolve$1(binding.path, seen);
}
return path;
}
@@ -33,6 +34,17 @@ function resolveId(path) {
if (path.isIdentifier() && !path.scope.hasBinding(path.node.name, /* noGlobals */true)) {
return path.node.name;
}
// globalThis.Object / window.Array / self.Map / global.Set -> resolve to
// the property name, because accessing a built-in through a global object
// reference is equivalent to accessing it directly.
if (path.isMemberExpression() && !path.node.computed) {
const object = path.get("object");
const property = path.get("property");
if (object.isIdentifier() && !object.scope.hasBinding(object.node.name, /* noGlobals */true) && PossibleGlobalObjects.has(object.node.name) && property.isIdentifier()) {
return property.node.name;
}
}
const resolved = resolve$1(path);
if (resolved != null && resolved.isIdentifier()) {
return resolved.node.name;
@@ -60,7 +72,18 @@ function resolveKey(path, computed = false) {
if (typeof value === "string") return value;
}
}
function resolveSource(obj) {
function resolveInstance(obj, seen) {
const source = resolveSource(obj, seen);
return source.placement === "prototype" ? source.id : null;
}
function resolveSource(obj, seen) {
if (seen.has(obj)) {
return {
id: null,
placement: null
};
}
seen.add(obj);
if (obj.isMemberExpression() && obj.get("property").isIdentifier({
name: "prototype"
})) {
@@ -85,22 +108,23 @@ function resolveSource(obj) {
}
const path = resolve$1(obj);
switch (path == null ? void 0 : path.type) {
case "NullLiteral":
return {
id: null,
placement: null
};
case "RegExpLiteral":
return {
id: "RegExp",
placement: "prototype"
};
case "FunctionExpression":
return {
id: "Function",
placement: "prototype"
};
case "StringLiteral":
case "TemplateLiteral":
return {
id: "String",
placement: "prototype"
};
case "NumberLiteral":
case "NumericLiteral":
return {
id: "Number",
placement: "prototype"
@@ -110,6 +134,11 @@ function resolveSource(obj) {
id: "Boolean",
placement: "prototype"
};
case "BigIntLiteral":
return {
id: "BigInt",
placement: "prototype"
};
case "ObjectExpression":
return {
id: "Object",
@@ -120,6 +149,192 @@ function resolveSource(obj) {
id: "Array",
placement: "prototype"
};
case "FunctionExpression":
case "ArrowFunctionExpression":
case "ClassExpression":
return {
id: "Function",
placement: "prototype"
};
// new Constructor() -> resolve the constructor name
case "NewExpression":
{
const calleeId = resolveId(path.get("callee"));
if (calleeId) return {
id: calleeId,
placement: "prototype"
};
return {
id: null,
placement: null
};
}
// Unary expressions -> result type depends on operator
case "UnaryExpression":
{
const {
operator
} = path.node;
if (operator === "typeof") return {
id: "String",
placement: "prototype"
};
if (operator === "!" || operator === "delete") return {
id: "Boolean",
placement: "prototype"
};
// Unary + always produces Number (throws on BigInt)
if (operator === "+") return {
id: "Number",
placement: "prototype"
};
// Unary - and ~ can produce Number or BigInt depending on operand
if (operator === "-" || operator === "~") {
const arg = resolveInstance(path.get("argument"), seen);
if (arg === "BigInt") return {
id: "BigInt",
placement: "prototype"
};
if (arg !== null) return {
id: "Number",
placement: "prototype"
};
return {
id: null,
placement: null
};
}
return {
id: null,
placement: null
};
}
// ++i, i++ produce Number or BigInt depending on the argument
case "UpdateExpression":
{
const arg = resolveInstance(path.get("argument"), seen);
if (arg === "BigInt") return {
id: "BigInt",
placement: "prototype"
};
if (arg !== null) return {
id: "Number",
placement: "prototype"
};
return {
id: null,
placement: null
};
}
// Binary expressions -> result type depends on operator
case "BinaryExpression":
{
const {
operator
} = path.node;
if (operator === "==" || operator === "!=" || operator === "===" || operator === "!==" || operator === "<" || operator === ">" || operator === "<=" || operator === ">=" || operator === "instanceof" || operator === "in") {
return {
id: "Boolean",
placement: "prototype"
};
}
// >>> always produces Number
if (operator === ">>>") {
return {
id: "Number",
placement: "prototype"
};
}
// Arithmetic and bitwise operators can produce Number or BigInt
if (operator === "-" || operator === "*" || operator === "/" || operator === "%" || operator === "**" || operator === "&" || operator === "|" || operator === "^" || operator === "<<" || operator === ">>") {
const left = resolveInstance(path.get("left"), seen);
const right = resolveInstance(path.get("right"), seen);
if (left === "BigInt" && right === "BigInt") {
return {
id: "BigInt",
placement: "prototype"
};
}
if (left !== null && right !== null) {
return {
id: "Number",
placement: "prototype"
};
}
return {
id: null,
placement: null
};
}
// + depends on operand types: string wins, otherwise number or bigint
if (operator === "+") {
const left = resolveInstance(path.get("left"), seen);
const right = resolveInstance(path.get("right"), seen);
if (left === "String" || right === "String") {
return {
id: "String",
placement: "prototype"
};
}
if (left === "Number" && right === "Number") {
return {
id: "Number",
placement: "prototype"
};
}
if (left === "BigInt" && right === "BigInt") {
return {
id: "BigInt",
placement: "prototype"
};
}
}
return {
id: null,
placement: null
};
}
// (a, b, c) -> the result is the last expression
case "SequenceExpression":
{
const expressions = path.get("expressions");
return resolveSource(expressions[expressions.length - 1], seen);
}
// a = b -> the result is the right side
case "AssignmentExpression":
{
if (path.node.operator === "=") {
return resolveSource(path.get("right"), seen);
}
return {
id: null,
placement: null
};
}
// a ? b : c -> if both branches resolve to the same type, use it
case "ConditionalExpression":
{
const consequent = resolveSource(path.get("consequent"), seen);
const alternate = resolveSource(path.get("alternate"), seen);
if (consequent.id && consequent.id === alternate.id) {
return consequent;
}
return {
id: null,
placement: null
};
}
// (expr) -> unwrap parenthesized expressions
case "ParenthesizedExpression":
return resolveSource(path.get("expression"), seen);
// TypeScript / Flow type wrappers -> unwrap to the inner expression
case "TSAsExpression":
case "TSSatisfiesExpression":
case "TSNonNullExpression":
case "TSInstantiationExpression":
case "TSTypeAssertion":
case "TypeCastExpression":
return resolveSource(path.get("expression"), seen);
}
return {
id: null,
@@ -419,10 +634,12 @@ var usage = callProvider => {
objectIsGlobalIdentifier = false;
}
}
const source = resolveSource(object);
let skipObject = property(source.id, key, source.placement, path);
skipObject || (skipObject = !objectIsGlobalIdentifier || path.shouldSkip || object.shouldSkip || isRemoved(object));
if (!skipObject) handleReferencedIdentifier(object);
const source = resolveSource(object, new Set());
const skipObject = property(source.id, key, source.placement, path);
const canHandleObject = objectIsGlobalIdentifier && !path.shouldSkip && !object.shouldSkip && !isRemoved(object);
if (canHandleObject && (!skipObject || PossibleGlobalObjects.has(source.id))) {
handleReferencedIdentifier(object);
}
},
ObjectPattern(path) {
const {
@@ -452,7 +669,7 @@ var usage = callProvider => {
if (obj) ({
id,
placement
} = resolveSource(obj));
} = resolveSource(obj, new Set()));
for (const prop of path.get("properties")) {
if (prop.isObjectProperty()) {
const key = resolveKey(prop.get("key"));
@@ -462,7 +679,7 @@ var usage = callProvider => {
},
BinaryExpression(path) {
if (path.node.operator !== "in") return;
const source = resolveSource(path.get("right"));
const source = resolveSource(path.get("right"), new Set());
const key = resolveKey(path.get("left"), true);
if (!key) return;
callProvider({
@@ -512,7 +729,6 @@ function logMissing(missingDeps) {}
// eslint-disable-next-line @typescript-eslint/no-unused-vars
function laterLogMissing(missingDeps) {}
const PossibleGlobalObjects = new Set(["global", "globalThis", "self", "window"]);
function createMetaResolver(polyfills) {
const {
static: staticP,
File diff suppressed because one or more lines are too long
+235 -19
View File
@@ -10,6 +10,7 @@ const {
types: t$1,
template: template
} = _babel.default || _babel;
const PossibleGlobalObjects = new Set(["global", "globalThis", "self", "window"]);
function intersection(a, b) {
const result = new Set();
a.forEach(v => b.has(v) && result.add(v));
@@ -18,18 +19,18 @@ function intersection(a, b) {
function has$1(object, key) {
return Object.prototype.hasOwnProperty.call(object, key);
}
function resolve$1(path, resolved = new Set()) {
if (resolved.has(path)) return;
resolved.add(path);
function resolve$1(path, seen = new Set()) {
if (seen.has(path)) return;
seen.add(path);
if (path.isVariableDeclarator()) {
if (path.get("id").isIdentifier()) {
return resolve$1(path.get("init"), resolved);
return resolve$1(path.get("init"), seen);
}
} else if (path.isReferencedIdentifier()) {
const binding = path.scope.getBinding(path.node.name);
if (!binding) return path;
if (!binding.constant) return;
return resolve$1(binding.path, resolved);
return resolve$1(binding.path, seen);
}
return path;
}
@@ -37,6 +38,17 @@ function resolveId(path) {
if (path.isIdentifier() && !path.scope.hasBinding(path.node.name, /* noGlobals */true)) {
return path.node.name;
}
// globalThis.Object / window.Array / self.Map / global.Set -> resolve to
// the property name, because accessing a built-in through a global object
// reference is equivalent to accessing it directly.
if (path.isMemberExpression() && !path.node.computed) {
const object = path.get("object");
const property = path.get("property");
if (object.isIdentifier() && !object.scope.hasBinding(object.node.name, /* noGlobals */true) && PossibleGlobalObjects.has(object.node.name) && property.isIdentifier()) {
return property.node.name;
}
}
const resolved = resolve$1(path);
if (resolved != null && resolved.isIdentifier()) {
return resolved.node.name;
@@ -64,7 +76,18 @@ function resolveKey(path, computed = false) {
if (typeof value === "string") return value;
}
}
function resolveSource(obj) {
function resolveInstance(obj, seen) {
const source = resolveSource(obj, seen);
return source.placement === "prototype" ? source.id : null;
}
function resolveSource(obj, seen) {
if (seen.has(obj)) {
return {
id: null,
placement: null
};
}
seen.add(obj);
if (obj.isMemberExpression() && obj.get("property").isIdentifier({
name: "prototype"
})) {
@@ -89,22 +112,23 @@ function resolveSource(obj) {
}
const path = resolve$1(obj);
switch (path == null ? void 0 : path.type) {
case "NullLiteral":
return {
id: null,
placement: null
};
case "RegExpLiteral":
return {
id: "RegExp",
placement: "prototype"
};
case "FunctionExpression":
return {
id: "Function",
placement: "prototype"
};
case "StringLiteral":
case "TemplateLiteral":
return {
id: "String",
placement: "prototype"
};
case "NumberLiteral":
case "NumericLiteral":
return {
id: "Number",
placement: "prototype"
@@ -114,6 +138,11 @@ function resolveSource(obj) {
id: "Boolean",
placement: "prototype"
};
case "BigIntLiteral":
return {
id: "BigInt",
placement: "prototype"
};
case "ObjectExpression":
return {
id: "Object",
@@ -124,6 +153,192 @@ function resolveSource(obj) {
id: "Array",
placement: "prototype"
};
case "FunctionExpression":
case "ArrowFunctionExpression":
case "ClassExpression":
return {
id: "Function",
placement: "prototype"
};
// new Constructor() -> resolve the constructor name
case "NewExpression":
{
const calleeId = resolveId(path.get("callee"));
if (calleeId) return {
id: calleeId,
placement: "prototype"
};
return {
id: null,
placement: null
};
}
// Unary expressions -> result type depends on operator
case "UnaryExpression":
{
const {
operator
} = path.node;
if (operator === "typeof") return {
id: "String",
placement: "prototype"
};
if (operator === "!" || operator === "delete") return {
id: "Boolean",
placement: "prototype"
};
// Unary + always produces Number (throws on BigInt)
if (operator === "+") return {
id: "Number",
placement: "prototype"
};
// Unary - and ~ can produce Number or BigInt depending on operand
if (operator === "-" || operator === "~") {
const arg = resolveInstance(path.get("argument"), seen);
if (arg === "BigInt") return {
id: "BigInt",
placement: "prototype"
};
if (arg !== null) return {
id: "Number",
placement: "prototype"
};
return {
id: null,
placement: null
};
}
return {
id: null,
placement: null
};
}
// ++i, i++ produce Number or BigInt depending on the argument
case "UpdateExpression":
{
const arg = resolveInstance(path.get("argument"), seen);
if (arg === "BigInt") return {
id: "BigInt",
placement: "prototype"
};
if (arg !== null) return {
id: "Number",
placement: "prototype"
};
return {
id: null,
placement: null
};
}
// Binary expressions -> result type depends on operator
case "BinaryExpression":
{
const {
operator
} = path.node;
if (operator === "==" || operator === "!=" || operator === "===" || operator === "!==" || operator === "<" || operator === ">" || operator === "<=" || operator === ">=" || operator === "instanceof" || operator === "in") {
return {
id: "Boolean",
placement: "prototype"
};
}
// >>> always produces Number
if (operator === ">>>") {
return {
id: "Number",
placement: "prototype"
};
}
// Arithmetic and bitwise operators can produce Number or BigInt
if (operator === "-" || operator === "*" || operator === "/" || operator === "%" || operator === "**" || operator === "&" || operator === "|" || operator === "^" || operator === "<<" || operator === ">>") {
const left = resolveInstance(path.get("left"), seen);
const right = resolveInstance(path.get("right"), seen);
if (left === "BigInt" && right === "BigInt") {
return {
id: "BigInt",
placement: "prototype"
};
}
if (left !== null && right !== null) {
return {
id: "Number",
placement: "prototype"
};
}
return {
id: null,
placement: null
};
}
// + depends on operand types: string wins, otherwise number or bigint
if (operator === "+") {
const left = resolveInstance(path.get("left"), seen);
const right = resolveInstance(path.get("right"), seen);
if (left === "String" || right === "String") {
return {
id: "String",
placement: "prototype"
};
}
if (left === "Number" && right === "Number") {
return {
id: "Number",
placement: "prototype"
};
}
if (left === "BigInt" && right === "BigInt") {
return {
id: "BigInt",
placement: "prototype"
};
}
}
return {
id: null,
placement: null
};
}
// (a, b, c) -> the result is the last expression
case "SequenceExpression":
{
const expressions = path.get("expressions");
return resolveSource(expressions[expressions.length - 1], seen);
}
// a = b -> the result is the right side
case "AssignmentExpression":
{
if (path.node.operator === "=") {
return resolveSource(path.get("right"), seen);
}
return {
id: null,
placement: null
};
}
// a ? b : c -> if both branches resolve to the same type, use it
case "ConditionalExpression":
{
const consequent = resolveSource(path.get("consequent"), seen);
const alternate = resolveSource(path.get("alternate"), seen);
if (consequent.id && consequent.id === alternate.id) {
return consequent;
}
return {
id: null,
placement: null
};
}
// (expr) -> unwrap parenthesized expressions
case "ParenthesizedExpression":
return resolveSource(path.get("expression"), seen);
// TypeScript / Flow type wrappers -> unwrap to the inner expression
case "TSAsExpression":
case "TSSatisfiesExpression":
case "TSNonNullExpression":
case "TSInstantiationExpression":
case "TSTypeAssertion":
case "TypeCastExpression":
return resolveSource(path.get("expression"), seen);
}
return {
id: null,
@@ -423,10 +638,12 @@ var usage = callProvider => {
objectIsGlobalIdentifier = false;
}
}
const source = resolveSource(object);
let skipObject = property(source.id, key, source.placement, path);
skipObject || (skipObject = !objectIsGlobalIdentifier || path.shouldSkip || object.shouldSkip || isRemoved(object));
if (!skipObject) handleReferencedIdentifier(object);
const source = resolveSource(object, new Set());
const skipObject = property(source.id, key, source.placement, path);
const canHandleObject = objectIsGlobalIdentifier && !path.shouldSkip && !object.shouldSkip && !isRemoved(object);
if (canHandleObject && (!skipObject || PossibleGlobalObjects.has(source.id))) {
handleReferencedIdentifier(object);
}
},
ObjectPattern(path) {
const {
@@ -456,7 +673,7 @@ var usage = callProvider => {
if (obj) ({
id,
placement
} = resolveSource(obj));
} = resolveSource(obj, new Set()));
for (const prop of path.get("properties")) {
if (prop.isObjectProperty()) {
const key = resolveKey(prop.get("key"));
@@ -466,7 +683,7 @@ var usage = callProvider => {
},
BinaryExpression(path) {
if (path.node.operator !== "in") return;
const source = resolveSource(path.get("right"));
const source = resolveSource(path.get("right"), new Set());
const key = resolveKey(path.get("left"), true);
if (!key) return;
callProvider({
@@ -556,7 +773,6 @@ function laterLogMissing(missingDeps) {
laterLogMissingDependencies();
}
const PossibleGlobalObjects = new Set(["global", "globalThis", "self", "window"]);
function createMetaResolver(polyfills) {
const {
static: staticP,
File diff suppressed because one or more lines are too long