parse()

in src/parsers/json.js [26:94]


  parse(RelaxedJSON = RJSON) {
    try {
      this.parsedJSON = JSON.parse(this._jsonString);
    } catch (originalError) {
      // First we'll try to remove comments with esprima;
      // WebExtension manifests can contain comments, so we'll strip
      // them out and see if we can parse the JSON.
      // If not it's just garbage JSON and we error.
      //
      // Originally from https://github.com/abarreir/crx2ff/blob/d2b882056f902d751ad05e329efda7eddcb9d268/libs/ext-converter.js#L19-L37
      const manifestString = `var o = ${this._jsonString}`;
      try {
        // This converts the JSON into a real JS object, and removes any
        // comments from the JS code.
        // This has some drawbacks because JSON and JS are not _100%_
        // compatible. This is largely to do with Unicode characters we
        // wouldn't expect to see in manifests anyway, and it should simply be
        // a JSON parse error anyway.
        // See:
        // http://stackoverflow.com/questions/23752156/are-all-json-objects-also-valid-javascript-objects/23753148#23753148
        // https://github.com/judofyr/timeless/issues/57#issuecomment-31872462
        const tokens = esprima
          .tokenize(manifestString, { comment: true })
          .slice(3);
        this._jsonString = tokens.reduce((json, token) => {
          // Ignore line comments (`// comments`) and just return the existing
          // json we've built.
          if (token.type === 'LineComment') {
            return json;
          }

          // Block comments are not allowed, so this is an error.
          if (token.type === 'BlockComment') {
            this.collector.addError(messages.JSON_BLOCK_COMMENTS);
            this.isValid = false;
          }

          return `${json}${token.value}`;
        }, '');

        // We found block-level comments, so this manifest is not valid.
        // Don't bother parsing it again.
        if (this.isValid === false) {
          return;
        }

        this.parsedJSON = JSON.parse(this._jsonString);
      } catch (error) {
        // There was still an error, so looks like this manifest is actually
        // invalid.
        const errorData = {
          ...messages.JSON_INVALID,
          file: this.filename,
          description: error.message,
        };
        this.collector.addError(errorData);
        this.isValid = false;
        return;
      }
    }

    // Check for duplicate keys, which renders the manifest invalid.
    this._checkForDuplicateKeys(RelaxedJSON);

    // If never marked as invalid, this is a valid JSON file.
    if (this.isValid !== false) {
      this.isValid = true;
    }
  }