errorLookup()

in src/parsers/manifestjson.js [262:413]


  errorLookup(error) {
    // This is the default message.
    let baseObject = messages.JSON_INVALID;

    // This is the default from webextension-manifest-schema, but it's not a
    // super helpful error. We'll tidy it up a bit:
    if (error && error.message) {
      const lowerCaseMessage = error.message.toLowerCase();
      if (lowerCaseMessage === 'must match a schema in anyof') {
        // eslint-disable-next-line no-param-reassign
        error.message = 'is not a valid key or has invalid extra properties';
      }
    }

    const overrides = {
      message: `"${error.instancePath || '/'}" ${error.message}`,
      instancePath: error.instancePath,
    };

    if (error.keyword === SCHEMA_KEYWORDS.REQUIRED) {
      baseObject = messages.MANIFEST_FIELD_REQUIRED;
    } else if (error.keyword === SCHEMA_KEYWORDS.DEPRECATED) {
      if (
        Object.prototype.hasOwnProperty.call(
          DEPRECATED_MANIFEST_PROPERTIES,
          error.instancePath
        )
      ) {
        baseObject =
          messages[DEPRECATED_MANIFEST_PROPERTIES[error.instancePath]];

        if (baseObject === null) {
          baseObject = messages.MANIFEST_FIELD_DEPRECATED;
        }

        let errorDescription = baseObject.description;

        if (errorDescription === null) {
          errorDescription = error.message;
        }

        // Set the description to the actual message from the schema
        overrides.message = baseObject.message;
        overrides.description = errorDescription;
      }
      // TODO(#2462): add a messages.MANIFEST_FIELD_DEPRECATED and ensure that deprecated
      // properties are handled properly (e.g. we should also detect when the deprecated
      // keyword is actually used to warn the developer of additional properties not
      // explicitly defined in the schemas).
    } else if (
      error.keyword === SCHEMA_KEYWORDS.MIN_MANIFEST_VERSION ||
      error.keyword === SCHEMA_KEYWORDS.MAX_MANIFEST_VERSION
    ) {
      // Choose a different message for permissions unsupported with the
      // add-on manifest_version.
      if (PERMS_DATAPATH_REGEX.test(error.instancePath)) {
        baseObject = messages.manifestPermissionUnsupported(error.data, error);
      } else if (error.instancePath === '/applications') {
        baseObject = messages.APPLICATIONS_INVALID;
      } else {
        baseObject = messages.manifestFieldUnsupported(
          error.instancePath,
          error
        );
      }

      // Set the message and description from the one generated by the
      // choosen message.
      overrides.message = baseObject.message;
      overrides.description = baseObject.description;
    } else if (
      error.instancePath.startsWith('/permissions') &&
      error.keyword === SCHEMA_KEYWORDS.VALIDATE_PRIVILEGED_PERMISSIONS &&
      error.params.privilegedPermissions
    ) {
      if (this.isPrivilegedAddon) {
        baseObject = error.params.privilegedPermissions.length
          ? messages.mozillaAddonsPermissionRequired(error)
          : messages.privilegedFeaturesRequired(error);
      } else {
        baseObject = messages.manifestPermissionsPrivileged(error);
      }
      overrides.message = baseObject.message;
      overrides.description = baseObject.description;
    } else if (
      error.instancePath.startsWith('/permissions') &&
      typeof error.data !== 'undefined' &&
      typeof error.data !== 'string'
    ) {
      baseObject = messages.MANIFEST_BAD_PERMISSION;
      overrides.message = `Permissions ${error.message}.`;
    } else if (
      error.instancePath.startsWith('/optional_permissions') &&
      typeof error.data !== 'undefined' &&
      typeof error.data !== 'string'
    ) {
      baseObject = messages.MANIFEST_BAD_OPTIONAL_PERMISSION;
      overrides.message = `Permissions ${error.message}.`;
    } else if (
      error.instancePath.startsWith('/host_permissions') &&
      typeof error.data !== 'undefined' &&
      typeof error.data !== 'string'
    ) {
      baseObject = messages.MANIFEST_BAD_HOST_PERMISSION;
      overrides.message = `Permissions ${error.message}.`;
    } else if (error.keyword === SCHEMA_KEYWORDS.TYPE) {
      baseObject = messages.MANIFEST_FIELD_INVALID;
    } else if (error.keyword === SCHEMA_KEYWORDS.PRIVILEGED) {
      baseObject = this.isPrivilegedAddon
        ? messages.mozillaAddonsPermissionRequired(error)
        : messages.manifestFieldPrivileged(error);
      overrides.message = baseObject.message;
      overrides.description = baseObject.description;
    }

    // Arrays can be extremely verbose, this tries to make them a little
    // more sane. Using a regex because there will likely be more as we
    // expand the schema.
    // Note that this works because the 2 regexps use similar patterns. We'll
    // want to adjust this if they start to differ.
    const match =
      error.instancePath.match(PERMS_DATAPATH_REGEX) ||
      error.instancePath.match(INSTALL_ORIGINS_DATAPATH_REGEX);

    if (
      match &&
      baseObject.code !== messages.MANIFEST_BAD_PERMISSION.code &&
      baseObject.code !== messages.MANIFEST_BAD_OPTIONAL_PERMISSION.code &&
      baseObject.code !== messages.MANIFEST_BAD_HOST_PERMISSION.code &&
      baseObject.code !== messages.MANIFEST_PERMISSION_UNSUPPORTED
    ) {
      baseObject = messages[`MANIFEST_${match[1].toUpperCase()}`];
      overrides.message = oneLine`/${match[1]}: Invalid ${match[1]}
          "${error.data}" at ${match[2]}.`;
    }

    // Make sure we filter out warnings and errors code that should never be reported
    // on manifest version 2 extensions.
    const ignoredOnMV2 = [
      messages.MANIFEST_HOST_PERMISSIONS.code,
      messages.MANIFEST_BAD_HOST_PERMISSION.code,
    ];

    if (
      this.parsedJSON.manifest_version === 2 &&
      ignoredOnMV2.includes(baseObject.code)
    ) {
      return null;
    }

    return { ...baseObject, ...overrides };
  }