<commit_before>
/**
 * TODO: The PvManager will actually do following
 * 1. make REST API calls to get PVs for the input attribute
 * 2. Cache the PVs so that frequent calls are not needed
 */
angular.module('openspecimen')
  .factory('PvManager', function($http, $q, $translate, ApiUrls, ApiUtil, Site, Util) {
    var url = ApiUrls.getBaseUrl() + 'permissible-values';

    var anatomicSites = [
      'DIGESTIVE ORGANS',
      'SKIN',
      'MALE GENITAL ORGANS',
      'UNKNOWN PRIMARY SITE',
      'PERIPHERAL NERVES AND AUTONOMIC NERVOUS SYSTEM',
      'FEMALE GENITAL ORGANS',
      'OTHER AND ILL-DEFINED SITES',
      'HEMATOPOIETIC AND RETICULOENDOTHELIAL SYSTEMS',
      'RETROPERITONEUM AND PERITONEUM',
      'RESPIRATORY SYSTEM AND INTRATHORACIC ORGANS',
      'BONES, JOINTS AND ARTICULAR CARTILAGE',
      'THYROID AND OTHER ENDOCRINE GLANDS',
      'MENINGES',
      'CONNECTIVE, SUBCUTANEOUS AND OTHER SOFT TISSUES',
      'BREAST',
      'LIP, ORAL CAVITY AND PHARYNX',
      'LYMPH NODES',
      'URINARY TRACT',
      'BRAIN',
      'SPINAL CORD, CRANIAL NERVES, AND OTHER PARTS OF CENTRAL NERVOUS SYSTEM',
      'EYE, BRAIN AND OTHER PARTS OF CENTRAL NERVOUS SYSTEM',
      'Not Specified'
    ];

    var positionLabelingSchemes = [
      'Numbers',
      'Alphabets Upper Case',
      'Alphabets Lower Case',
      'Roman Upper Case',
      'Roman Lower Case'
    ];

    /** We need to have i18n keys for these as well **/
    var storageTypes = [
      'Manual',
      'Virtual'
    ];

    var visitStatuses = [
      'Complete',
      'Pending',
      'Missed Collection'
    ];

    var specimenStatuses = [
      'Collected',
      'Missed Collection',
      'Pending'
    ];

    var activityStatuses = [
      'Active',
      'Pending',
      'Disabled',
      'Closed'
    ];

    var qualityStatuses = [
      'Acceptable',
      'Unacceptable'
    ];

    var visitNamePrintModes = [
      {name: 'PRE_PRINT', displayKey:'cp.visit_name_print_modes.PRE_PRINT'},
      {name: 'ON_COMPLETION', displayKey:'cp.visit_name_print_modes.ON_COMPLETION'},
      {name: 'NONE', displayKey:'cp.visit_name_print_modes.NONE'}
    ];

    var spmnLabelPrePrintModes = [
      {name: 'ON_VISIT', displayKey:'cp.spmn_label_pre_print_modes.ON_VISIT'},
      {name: 'NONE', displayKey:'cp.spmn_label_pre_print_modes.NONE'}
    ];

    var spmnLabelAutoPrintModes = [
      {name: 'PRE_PRINT', displayKey:'srs.spmn_label_auto_print_modes.PRE_PRINT'},
      {name: 'ON_COLLECTION', displayKey:'srs.spmn_label_auto_print_modes.ON_COLLECTION'},
      {name: 'NONE', displayKey:'srs.spmn_label_auto_print_modes.NONE'}
    ];

    var pvMap = {
      anatomicSite: anatomicSites,
      'storage-type': storageTypes,
      'visit-status': visitStatuses,
      'specimen-status': specimenStatuses,
      'container-position-labeling-schemes': positionLabelingSchemes,
      'activity-status': activityStatuses,
      'quality-status': qualityStatuses,
      'visit-name-print-modes': visitNamePrintModes,
      'specimen-label-pre-print-modes': spmnLabelPrePrintModes,
      'specimen-label-auto-print-modes': spmnLabelAutoPrintModes
    };

    var pvIdMap = {
      'clinical-status'     : 'clinical_status',
      'gender'              : 'gender',
      'specimen-class'      : 'specimen_type',
      'laterality'          : 'laterality',
      'pathology-status'    : 'pathology_status',
      'collection-procedure': 'collection_procedure',
      'collection-container': 'collection_container',
      'vital-status'        : 'vital_status',
      'received-quality'    : 'received_quality',
      'ethnicity'           : 'ethnicity',
      'race'                : 'race',
      'anatomic-site'       : 'anatomic_site',
      'site-type'           : 'site_type',
      'clinical-diagnosis'  : 'clinical_diagnosis',
      'specimen-biohazard'  : 'specimen_biohazard',
      'consent_response'    : 'consent_response',
      'missed-visit-reason' : 'missed_visit_reason',
      'cohort'              : 'cohort'
    };

    function valueOf(input) {
      return input.value;
    };

    function parentAndValue(input) {
      return {parent: input.parentValue, value: input.value};
    };

    function transform(pvs, transformfn, incParentVal, result) {
      transformfn = transformfn || (incParentVal ? parentAndValue : valueOf);
      return pvs.map(function(pv) { return transformfn(pv); });
    };

    function loadPvs(attr, srchTerm, transformFn, incOnlyLeaf) {
      var pvId = pvIdMap[attr];
      if (!pvId && pvMap[attr]) {
        return _getPvs(attr);
      } else if (!pvId) {
        pvId = attr;
      }

      var params = {
        attribute: pvId,
        searchString: srchTerm,
        includeOnlyLeafValue: incOnlyLeaf,
        maxResults: 100
      };

      return $http.get(url, {params: params}).then(
        function(result) {
          return transform(result.data, transformFn, null);
        }
      );
    };

    function loadPvsByParent(parentAttr, parentVal, incParentVal, transformFn) {
      var pvId = pvIdMap[parentAttr];
      if (!pvId) {
        pvId = parentAttr;
      }

      var params = {
        parentAttribute: pvId,
        parentValue: parentVal,
        includeParentValue: incParentVal,
        maxResults: 100
      };

      return $http.get(url, {params: params}).then(
        function(result) {
          return transform(result.data, transformFn, incParentVal);
        }
      );
    };

    function  _getPvs(attr) {
      var deferred = $q.defer();
      var result = undefined;
      if (pvMap[attr]) {
        result = pvMap[attr];
        if (hasI18nKey(result) && !isDisplayNameInitialized(result)) {
          initDisplayNames(result);
        }
      } else {
        result = [];
      }
      deferred.resolve(result);
      return deferred.promise;
    };

    function hasI18nKey(pvs) {
      return !!pvs[0].displayKey;
    }

    function isDisplayNameInitialized(pvs) {
      return !!pvs[0].displayName;
    }

    function initDisplayNames(pvs) {
      $translate('pvs.not_specified').then(
        function() {
          angular.forEach(pvs, function(pv) {
            pv.displayName = $translate.instant(pv.displayKey);
          });
        }
      );
    }

    return {
      getPvs: function(attr, srchTerm, transformFn) {
        var pvs = [];
        loadPvs(attr, srchTerm, transformFn).then(
          function(result) {
            Util.unshiftAll(pvs, result);
          }
        );

        return pvs;
      },

      getLeafPvs: function(attr, srchTerm, transformFn) {
        var pvs = [];
        loadPvs(attr, srchTerm, transformFn, true).then(
          function(result) {
            Util.unshiftAll(pvs, result);
          }
        );

        return pvs;
      },

      loadPvs: loadPvs,

      getPvsByParent: function(parentAttr, parentVal, incParentVal, transformFn) {
        var pvs = [];

        loadPvsByParent(parentAttr, parentVal, incParentVal, transformFn).then(
          function(result) {
            Util.unshiftAll(pvs, result);
          }
        );

        return pvs;
      },

      loadPvsByParent: loadPvsByParent,

      getSites: function(opts) {
        var sites = [];
        Site.list(opts).then(
          function(siteList) {
            Array.prototype.push.apply(sites, siteList);
          }
        );

        return sites;
      },

      notSpecified: function() {
        return $translate.instant('pvs.not_specified');
      }
    };
  });
<commit_msg>OPSMN-3366: Updated the received_quality's public_Id in PV manager map to match with the present in DB   -Cause: Public_id in database "receive_quality" and in pv-manager map "received_quality" (not matching with database value). Hence its not loading pvs.<commit_after>
/**
 * TODO: The PvManager will actually do following
 * 1. make REST API calls to get PVs for the input attribute
 * 2. Cache the PVs so that frequent calls are not needed
 */
angular.module('openspecimen')
  .factory('PvManager', function($http, $q, $translate, ApiUrls, ApiUtil, Site, Util) {
    var url = ApiUrls.getBaseUrl() + 'permissible-values';

    var anatomicSites = [
      'DIGESTIVE ORGANS',
      'SKIN',
      'MALE GENITAL ORGANS',
      'UNKNOWN PRIMARY SITE',
      'PERIPHERAL NERVES AND AUTONOMIC NERVOUS SYSTEM',
      'FEMALE GENITAL ORGANS',
      'OTHER AND ILL-DEFINED SITES',
      'HEMATOPOIETIC AND RETICULOENDOTHELIAL SYSTEMS',
      'RETROPERITONEUM AND PERITONEUM',
      'RESPIRATORY SYSTEM AND INTRATHORACIC ORGANS',
      'BONES, JOINTS AND ARTICULAR CARTILAGE',
      'THYROID AND OTHER ENDOCRINE GLANDS',
      'MENINGES',
      'CONNECTIVE, SUBCUTANEOUS AND OTHER SOFT TISSUES',
      'BREAST',
      'LIP, ORAL CAVITY AND PHARYNX',
      'LYMPH NODES',
      'URINARY TRACT',
      'BRAIN',
      'SPINAL CORD, CRANIAL NERVES, AND OTHER PARTS OF CENTRAL NERVOUS SYSTEM',
      'EYE, BRAIN AND OTHER PARTS OF CENTRAL NERVOUS SYSTEM',
      'Not Specified'
    ];

    var positionLabelingSchemes = [
      'Numbers',
      'Alphabets Upper Case',
      'Alphabets Lower Case',
      'Roman Upper Case',
      'Roman Lower Case'
    ];

    /** We need to have i18n keys for these as well **/
    var storageTypes = [
      'Manual',
      'Virtual'
    ];

    var visitStatuses = [
      'Complete',
      'Pending',
      'Missed Collection'
    ];

    var specimenStatuses = [
      'Collected',
      'Missed Collection',
      'Pending'
    ];

    var activityStatuses = [
      'Active',
      'Pending',
      'Disabled',
      'Closed'
    ];

    var qualityStatuses = [
      'Acceptable',
      'Unacceptable'
    ];

    var visitNamePrintModes = [
      {name: 'PRE_PRINT', displayKey:'cp.visit_name_print_modes.PRE_PRINT'},
      {name: 'ON_COMPLETION', displayKey:'cp.visit_name_print_modes.ON_COMPLETION'},
      {name: 'NONE', displayKey:'cp.visit_name_print_modes.NONE'}
    ];

    var spmnLabelPrePrintModes = [
      {name: 'ON_VISIT', displayKey:'cp.spmn_label_pre_print_modes.ON_VISIT'},
      {name: 'NONE', displayKey:'cp.spmn_label_pre_print_modes.NONE'}
    ];

    var spmnLabelAutoPrintModes = [
      {name: 'PRE_PRINT', displayKey:'srs.spmn_label_auto_print_modes.PRE_PRINT'},
      {name: 'ON_COLLECTION', displayKey:'srs.spmn_label_auto_print_modes.ON_COLLECTION'},
      {name: 'NONE', displayKey:'srs.spmn_label_auto_print_modes.NONE'}
    ];

    var pvMap = {
      anatomicSite: anatomicSites,
      'storage-type': storageTypes,
      'visit-status': visitStatuses,
      'specimen-status': specimenStatuses,
      'container-position-labeling-schemes': positionLabelingSchemes,
      'activity-status': activityStatuses,
      'quality-status': qualityStatuses,
      'visit-name-print-modes': visitNamePrintModes,
      'specimen-label-pre-print-modes': spmnLabelPrePrintModes,
      'specimen-label-auto-print-modes': spmnLabelAutoPrintModes
    };

    var pvIdMap = {
      'clinical-status'     : 'clinical_status',
      'gender'              : 'gender',
      'specimen-class'      : 'specimen_type',
      'laterality'          : 'laterality',
      'pathology-status'    : 'pathology_status',
      'collection-procedure': 'collection_procedure',
      'collection-container': 'collection_container',
      'vital-status'        : 'vital_status',
      'received-quality'    : 'receive_quality',
      'ethnicity'           : 'ethnicity',
      'race'                : 'race',
      'anatomic-site'       : 'anatomic_site',
      'site-type'           : 'site_type',
      'clinical-diagnosis'  : 'clinical_diagnosis',
      'specimen-biohazard'  : 'specimen_biohazard',
      'consent_response'    : 'consent_response',
      'missed-visit-reason' : 'missed_visit_reason',
      'cohort'              : 'cohort'
    };

    function valueOf(input) {
      return input.value;
    };

    function parentAndValue(input) {
      return {parent: input.parentValue, value: input.value};
    };

    function transform(pvs, transformfn, incParentVal, result) {
      transformfn = transformfn || (incParentVal ? parentAndValue : valueOf);
      return pvs.map(function(pv) { return transformfn(pv); });
    };

    function loadPvs(attr, srchTerm, transformFn, incOnlyLeaf) {
      var pvId = pvIdMap[attr];
      if (!pvId && pvMap[attr]) {
        return _getPvs(attr);
      } else if (!pvId) {
        pvId = attr;
      }

      var params = {
        attribute: pvId,
        searchString: srchTerm,
        includeOnlyLeafValue: incOnlyLeaf,
        maxResults: 100
      };

      return $http.get(url, {params: params}).then(
        function(result) {
          return transform(result.data, transformFn, null);
        }
      );
    };

    function loadPvsByParent(parentAttr, parentVal, incParentVal, transformFn) {
      var pvId = pvIdMap[parentAttr];
      if (!pvId) {
        pvId = parentAttr;
      }

      var params = {
        parentAttribute: pvId,
        parentValue: parentVal,
        includeParentValue: incParentVal,
        maxResults: 100
      };

      return $http.get(url, {params: params}).then(
        function(result) {
          return transform(result.data, transformFn, incParentVal);
        }
      );
    };

    function  _getPvs(attr) {
      var deferred = $q.defer();
      var result = undefined;
      if (pvMap[attr]) {
        result = pvMap[attr];
        if (hasI18nKey(result) && !isDisplayNameInitialized(result)) {
          initDisplayNames(result);
        }
      } else {
        result = [];
      }
      deferred.resolve(result);
      return deferred.promise;
    };

    function hasI18nKey(pvs) {
      return !!pvs[0].displayKey;
    }

    function isDisplayNameInitialized(pvs) {
      return !!pvs[0].displayName;
    }

    function initDisplayNames(pvs) {
      $translate('pvs.not_specified').then(
        function() {
          angular.forEach(pvs, function(pv) {
            pv.displayName = $translate.instant(pv.displayKey);
          });
        }
      );
    }

    return {
      getPvs: function(attr, srchTerm, transformFn) {
        var pvs = [];
        loadPvs(attr, srchTerm, transformFn).then(
          function(result) {
            Util.unshiftAll(pvs, result);
          }
        );

        return pvs;
      },

      getLeafPvs: function(attr, srchTerm, transformFn) {
        var pvs = [];
        loadPvs(attr, srchTerm, transformFn, true).then(
          function(result) {
            Util.unshiftAll(pvs, result);
          }
        );

        return pvs;
      },

      loadPvs: loadPvs,

      getPvsByParent: function(parentAttr, parentVal, incParentVal, transformFn) {
        var pvs = [];

        loadPvsByParent(parentAttr, parentVal, incParentVal, transformFn).then(
          function(result) {
            Util.unshiftAll(pvs, result);
          }
        );

        return pvs;
      },

      loadPvsByParent: loadPvsByParent,

      getSites: function(opts) {
        var sites = [];
        Site.list(opts).then(
          function(siteList) {
            Array.prototype.push.apply(sites, siteList);
          }
        );

        return sites;
      },

      notSpecified: function() {
        return $translate.instant('pvs.not_specified');
      }
    };
  });
<|endoftext|>


<commit_before>module.exports = function (grunt) {
  // * Read command-line switches
  // - Read in --browsers CLI option; split it on commas into an array if it's a string, otherwise ignore it
  var browsers = typeof grunt.option('browsers') == 'string' ? grunt.option('browsers').split(',') : undefined;

  grunt.initConfig({
    pkg: grunt.file.readJSON('package.json'),
    library: grunt.file.readJSON('bower.json'),
    concat: {
      options: {
        separator: ''
      },
      library: {
        src: [
          'src/**/*.js'
        ],
        dest: 'dest/<%= library.name %>.js'
      }
    },
    uglify: {
      options: {
        banner: '/*! <%= pkg.name %> <%= grunt.template.today("dd-mm-yyyy") %> */\n'
      },
      jid: {
        files: {
          'dest/<%= library.name %>.min.js': ['<%= concat.library.dest %>']
        }
      }
    },
    jshint: {
      beforeConcat: {
        src: ['gruntfile.js', '<%= library.name %>/**/*.js']
      },
      afterConcat: {
        src: [
          '<%= concat.library.dest %>'
        ]
      },
      options: {
        // options here to override JSHint defaults
        globals: {
          jQuery: true,
          console: true,
          module: true,
          document: true,
          angular: true
        },
        globalstrict: false
      }
    },
    testFiles: {
      karmaUnit: 'karma.conf.js'
    },
    karma: {
      unit: {
        options: {
          configFile: '<%= testFiles.karmaUnit %>',
          autoWatch: false,
          singleRun: true,
          browsers: browsers || ['Chrome']
        }
      }
    },
    watch: {
      options: {
        livereload: true
      },
      files: [
        'Gruntfile.js',
        'src/**/*'
      ],
      tasks: ['default']
    }
  });

  // Load grunt-karma task plugin
  grunt.loadNpmTasks('grunt-karma');

  grunt.loadNpmTasks('grunt-contrib-uglify');
  grunt.loadNpmTasks('grunt-contrib-jshint');
  grunt.loadNpmTasks('grunt-contrib-concat');
  grunt.loadNpmTasks('grunt-contrib-watch');

  grunt.registerTask('test', ['jshint', 'karma:unit']);
  grunt.registerTask('default', ['jshint:beforeConcat', 'concat', 'jshint:afterConcat', 'uglify']);
  grunt.registerTask('livereload', ['default', 'watch']);

};<commit_msg>chore(grunt): add grunt-contrib-connect server<commit_after>module.exports = function (grunt) {
  // * Read command-line switches
  // - Read in --browsers CLI option; split it on commas into an array if it's a string, otherwise ignore it
  var browsers = typeof grunt.option('browsers') == 'string' ? grunt.option('browsers').split(',') : undefined;

  grunt.initConfig({
    pkg: grunt.file.readJSON('package.json'),
    library: grunt.file.readJSON('bower.json'),
    concat: {
      options: {
        separator: ''
      },
      library: {
        src: [
          'src/**/*.js'
        ],
        dest: 'dest/<%= library.name %>.js'
      }
    },
    uglify: {
      options: {
        banner: '/*! <%= pkg.name %> <%= grunt.template.today("dd-mm-yyyy") %> */\n'
      },
      jid: {
        files: {
          'dest/<%= library.name %>.min.js': ['<%= concat.library.dest %>']
        }
      }
    },
    jshint: {
      beforeConcat: {
        src: ['gruntfile.js', '<%= library.name %>/**/*.js']
      },
      afterConcat: {
        src: [
          '<%= concat.library.dest %>'
        ]
      },
      options: {
        // options here to override JSHint defaults
        globals: {
          jQuery: true,
          console: true,
          module: true,
          document: true,
          angular: true
        },
        globalstrict: false
      }
    },
    testFiles: {
      karmaUnit: 'karma.conf.js'
    },
    karma: {
      unit: {
        options: {
          configFile: '<%= testFiles.karmaUnit %>',
          autoWatch: false,
          singleRun: true,
          browsers: browsers || ['Chrome']
        }
      }
    },
    watch: {
      options: {
        livereload: true
      },
      files: [
        'Gruntfile.js',
        'src/**/*'
      ],
      tasks: ['build']
    },
    connect: {
      server: {
        options: {
          hostname: '*'
        }
      }
    }
  });

  // Load grunt-karma task plugin
  grunt.loadNpmTasks('grunt-karma');

  grunt.loadNpmTasks('grunt-contrib-uglify');
  grunt.loadNpmTasks('grunt-contrib-jshint');
  grunt.loadNpmTasks('grunt-contrib-concat');
  grunt.loadNpmTasks('grunt-contrib-watch');
  grunt.loadNpmTasks('grunt-contrib-connect');

  grunt.registerTask('test', ['jshint', 'karma:unit']);
  grunt.registerTask('build', ['jshint:beforeConcat', 'concat', 'jshint:afterConcat', 'uglify']);
  grunt.registerTask('default', ['build', 'connect:server', 'watch']);

};
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2008 Apple Inc. All Rights Reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

import * as Common from '../common/common.js';
import * as ProtocolClient from '../protocol_client/protocol_client.js';  // eslint-disable-line no-unused-vars
import * as TextUtils from '../text_utils/text_utils.js';

import {DebuggerModel, Location} from './DebuggerModel.js';  // eslint-disable-line no-unused-vars
import {ResourceTreeModel} from './ResourceTreeModel.js';
import {ExecutionContext} from './RuntimeModel.js';  // eslint-disable-line no-unused-vars

/**
 * @implements {TextUtils.ContentProvider.ContentProvider}
 * @unrestricted
 */
export class Script {
  /**
   * @param {!DebuggerModel} debuggerModel
   * @param {string} scriptId
   * @param {string} sourceURL
   * @param {number} startLine
   * @param {number} startColumn
   * @param {number} endLine
   * @param {number} endColumn
   * @param {!Protocol.Runtime.ExecutionContextId} executionContextId
   * @param {string} hash
   * @param {boolean} isContentScript
   * @param {boolean} isLiveEdit
   * @param {string|undefined} sourceMapURL
   * @param {boolean} hasSourceURL
   * @param {number} length
   * @param {?Protocol.Runtime.StackTrace} originStackTrace
   * @param {?number} codeOffset
   * @param {?string} scriptLanguage
   */
  constructor(
      debuggerModel, scriptId, sourceURL, startLine, startColumn, endLine, endColumn, executionContextId, hash,
      isContentScript, isLiveEdit, sourceMapURL, hasSourceURL, length, originStackTrace, codeOffset, scriptLanguage) {
    /** @type {string} */
    this._source;

    this.debuggerModel = debuggerModel;
    this.scriptId = scriptId;
    this.sourceURL = sourceURL;
    this.lineOffset = startLine;
    this.columnOffset = startColumn;
    this.endLine = endLine;
    this.endColumn = endColumn;

    this.executionContextId = executionContextId;
    this.hash = hash;
    this._isContentScript = isContentScript;
    this._isLiveEdit = isLiveEdit;
    this.sourceMapURL = sourceMapURL;
    this.hasSourceURL = hasSourceURL;
    this.contentLength = length;
    this._originalContentProvider = null;
    this._originalSource = null;
    this.originStackTrace = originStackTrace;
    this._codeOffset = codeOffset;
    this._language = scriptLanguage;
    this._lineMap = null;
    this._functionBodyOffsets = null;
  }

  /**
   * @param {string} source
   * @return {string}
   */
  static _trimSourceURLComment(source) {
    let sourceURLIndex = source.lastIndexOf('//# sourceURL=');
    if (sourceURLIndex === -1) {
      sourceURLIndex = source.lastIndexOf('//@ sourceURL=');
      if (sourceURLIndex === -1) {
        return source;
      }
    }
    const sourceURLLineIndex = source.lastIndexOf('\n', sourceURLIndex);
    if (sourceURLLineIndex === -1) {
      return source;
    }
    const sourceURLLine = source.substr(sourceURLLineIndex + 1);
    if (!sourceURLLine.match(sourceURLRegex)) {
      return source;
    }
    return source.substr(0, sourceURLLineIndex);
  }

  /**
   * @return {boolean}
   */
  isContentScript() {
    return this._isContentScript;
  }

  /**
   * @return {?number}
   */
  codeOffset() {
    return this._codeOffset;
  }

  /**
   * @return {boolean}
   */
  isWasm() {
    return this._language === Protocol.Debugger.ScriptLanguage.WebAssembly;
  }

  /**
   * @return {boolean}
   */
  hasWasmDisassembly() {
    return !!this._lineMap && !this.sourceMapURL;
  }

  /**
   * @return {?ExecutionContext}
   */
  executionContext() {
    return this.debuggerModel.runtimeModel().executionContext(this.executionContextId);
  }

  /**
   * @return {boolean}
   */
  isLiveEdit() {
    return this._isLiveEdit;
  }

  /**
   * @override
   * @return {string}
   */
  contentURL() {
    return this.sourceURL;
  }

  /**
   * @override
   * @return {!Common.ResourceType.ResourceType}
   */
  contentType() {
    return Common.ResourceType.resourceTypes.Script;
  }

  /**
   * @override
   * @return {!Promise<boolean>}
   */
  contentEncoded() {
    return Promise.resolve(false);
  }

  /**
   * @override
   * @return {!Promise<!TextUtils.ContentProvider.DeferredContent>}
   */
  async requestContent() {
    if (this._source) {
      return {content: this._source, isEncoded: false};
    }
    if (!this.scriptId) {
      return {error: ls`Script removed or deleted.`, isEncoded: false};
    }

    try {
      const sourceOrBytecode =
          await this.debuggerModel.target().debuggerAgent().invoke_getScriptSource({scriptId: this.scriptId});
      const source = sourceOrBytecode.scriptSource;
      if (source) {
        if (this.hasSourceURL) {
          this._source = Script._trimSourceURLComment(source);
        } else {
          this._source = source;
        }
      } else {
        this._source = '';
        if (sourceOrBytecode.bytecode) {
          const worker = new Common.Worker.WorkerWrapper('wasmparser_worker_entrypoint');
          /** @type {!Promise<!MessageEvent>} */
          const promise = new Promise(function(resolve, reject) {
            worker.onmessage = resolve;
            worker.onerror = reject;
          });
          worker.postMessage({method: 'disassemble', params: {content: sourceOrBytecode.bytecode}});

          /** @type {{source: string, offsets: ?Array<number>, functionBodyOffsets: ?Array<{start: number, end: number}>}} */
          const data = (await promise).data;
          this._source = data.source;
          this._lineMap = data.offsets;
          this._functionBodyOffsets = data.functionBodyOffsets;
          this.endLine = (this._lineMap && this._lineMap.length) || 0;
        }
      }

      if (this._originalSource === null) {
        this._originalSource = this._source;
      }
      return {content: this._source, isEncoded: false};
    } catch (err) {
      return {error: ls`Unable to fetch script source.`, isEncoded: false};
    }
  }

  /**
   * @return {!Promise<!ArrayBuffer>}
   */
  async getWasmBytecode() {
    const base64 = await this.debuggerModel.target().debuggerAgent().invoke_getWasmBytecode({scriptId: this.scriptId});
    const response = await fetch(`data:application/wasm;base64,${base64}`);
    return response.arrayBuffer();
  }

  /**
   * @return {!TextUtils.ContentProvider.ContentProvider}
   */
  originalContentProvider() {
    if (!this._originalContentProvider) {
      const lazyContent = () => this.requestContent().then(() => {
        return {
          content: this._originalSource || '',
          isEncoded: false,
        };
      });
      this._originalContentProvider =
          new TextUtils.StaticContentProvider.StaticContentProvider(this.contentURL(), this.contentType(), lazyContent);
    }
    return this._originalContentProvider;
  }

  /**
   * @override
   * @param {string} query
   * @param {boolean} caseSensitive
   * @param {boolean} isRegex
   * @return {!Promise<!Array<!TextUtils.ContentProvider.SearchMatch>>}
   */
  async searchInContent(query, caseSensitive, isRegex) {
    if (!this.scriptId) {
      return [];
    }

    const matches = await this.debuggerModel.target().debuggerAgent().invoke_searchInContent(
        {scriptId: this.scriptId, query, caseSensitive, isRegex});
    return (matches.result || [])
        .map(match => new TextUtils.ContentProvider.SearchMatch(match.lineNumber, match.lineContent));
  }

  /**
   * @param {string} source
   * @return {string}
   */
  _appendSourceURLCommentIfNeeded(source) {
    if (!this.hasSourceURL) {
      return source;
    }
    return source + '\n //# sourceURL=' + this.sourceURL;
  }

  /**
   * @param {string} newSource
   * @param {function(?ProtocolClient.InspectorBackend.ProtocolError, !Protocol.Runtime.ExceptionDetails=, !Array.<!Protocol.Debugger.CallFrame>=, !Protocol.Runtime.StackTrace=, !Protocol.Runtime.StackTraceId=, boolean=):void} callback
   */
  async editSource(newSource, callback) {
    newSource = Script._trimSourceURLComment(newSource);
    // We append correct sourceURL to script for consistency only. It's not actually needed for things to work correctly.
    newSource = this._appendSourceURLCommentIfNeeded(newSource);

    if (!this.scriptId) {
      callback('Script failed to parse');
      return;
    }

    await this.requestContent();
    if (this._source === newSource) {
      callback(null);
      return;
    }
    const response = await this.debuggerModel.target().debuggerAgent().invoke_setScriptSource(
        {scriptId: this.scriptId, scriptSource: newSource});

    if (!response.getError() && !response.exceptionDetails) {
      this._source = newSource;
    }

    const needsStepIn = !!response.stackChanged;
    callback(
        response.getError() || null, response.exceptionDetails, response.callFrames, response.asyncStackTrace,
        response.asyncStackTraceId, needsStepIn);
  }

  /**
   * @param {number} lineNumber
   * @param {number} columnNumber
   * @return {?Location}
   */
  rawLocation(lineNumber, columnNumber) {
    if (this.containsLocation(lineNumber, columnNumber)) {
      return new Location(this.debuggerModel, this.scriptId, lineNumber, columnNumber);
    }
    return null;
  }

  /**
   * @param {number} lineNumber
   * @return {?Location}
   */
  wasmByteLocation(lineNumber) {
    if (this._lineMap && lineNumber < this._lineMap.length) {
      return new Location(this.debuggerModel, this.scriptId, 0, this._lineMap[lineNumber]);
    }
    return null;
  }

  /**
   * @param {number} byteOffset
   * @return {number}
   */
  wasmDisassemblyLine(byteOffset) {
    let line = 0;
    // TODO: Implement binary search if necessary for large wasm modules
    while (this._lineMap && line < this._lineMap.length && byteOffset > this._lineMap[line]) {
      line++;
    }
    return line;
  }

  /**
   * @param {number} lineNumber
   * @return {boolean}
   */
  isWasmDisassemblyBreakableLine(lineNumber) {
    if (!this._functionBodyOffsets || this._functionBodyOffsets.length === 0) {
      return false;
    }
    const location = this.wasmByteLocation(lineNumber);
    if (!location) {
      return false;
    }
    const byteOffset = location.columnNumber;

    // Here, this._functionBodyOffsets is [{start:s0, end:e0}, {start:s1, end:e1}, ...].
    // Also, we have s0 < e0 < s1 < e1 ... and the breakable lines are defined by the union of [a0,b0), [a1,b1), ...
    let first = 0;
    let last = this._functionBodyOffsets.length - 1;
    // Quick return if it is outside of code section.
    if (byteOffset < this._functionBodyOffsets[first].start || byteOffset >= this._functionBodyOffsets[last].end) {
      return false;
    }
    // Binary search.
    while (first <= last) {
      const mid = (first + last) >> 1;
      const functionBodyOffset = this._functionBodyOffsets[mid];
      if (byteOffset < functionBodyOffset.start) {
        last = mid - 1;
      } else if (byteOffset >= functionBodyOffset.end) {
        first = mid + 1;
      } else {
        return true;
      }
    }

    return false;
  }

  /**
   *
   * @param {!Location} location
   * @return {!Array.<number>}
   */
  toRelativeLocation(location) {
    console.assert(
        location.scriptId === this.scriptId, '`toRelativeLocation` must be used with location of the same script');
    const relativeLineNumber = location.lineNumber - this.lineOffset;
    const relativeColumnNumber = (location.columnNumber || 0) - (relativeLineNumber === 0 ? this.columnOffset : 0);
    return [relativeLineNumber, relativeColumnNumber];
  }

  /**
   * @return {boolean}
   */
  isInlineScript() {
    const startsAtZero = !this.lineOffset && !this.columnOffset;
    return !this.isWasm() && !!this.sourceURL && !startsAtZero;
  }

  /**
   * @return {boolean}
   */
  isAnonymousScript() {
    return !this.sourceURL;
  }

  /**
   * @return {boolean}
   */
  isInlineScriptWithSourceURL() {
    return !!this.hasSourceURL && this.isInlineScript();
  }

  /**
   * @param {!Array<!Protocol.Debugger.ScriptPosition>} positions
   * @return {!Promise<boolean>}
   */
  async setBlackboxedRanges(positions) {
    const response = await this.debuggerModel.target().debuggerAgent().invoke_setBlackboxedRanges(
        {scriptId: this.scriptId, positions});
    return !response.getError();
  }

  /**
   * @param {number} lineNumber
   * @param {number} columnNumber
   * @return {boolean}
   */
  containsLocation(lineNumber, columnNumber) {
    const afterStart =
        (lineNumber === this.lineOffset && columnNumber >= this.columnOffset) || lineNumber > this.lineOffset;
    const beforeEnd = lineNumber < this.endLine || (lineNumber === this.endLine && columnNumber <= this.endColumn);
    return afterStart && beforeEnd;
  }

  /**
   * @return {string}
   */
  get frameId() {
    if (typeof this[frameIdSymbol] !== 'string') {
      this[frameIdSymbol] = frameIdForScript(this);
    }
    return this[frameIdSymbol] || '';
  }
}

const frameIdSymbol = Symbol('frameid');

/**
 * @param {!Script} script
 * @return {string}
 */
function frameIdForScript(script) {
  const executionContext = script.executionContext();
  if (executionContext) {
    return executionContext.frameId || '';
  }
  // This is to overcome compilation cache which doesn't get reset.
  const resourceTreeModel = script.debuggerModel.target().model(ResourceTreeModel);
  if (!resourceTreeModel || !resourceTreeModel.mainFrame) {
    return '';
  }
  return resourceTreeModel.mainFrame.id;
}

export const sourceURLRegex = /^[\040\t]*\/\/[@#] sourceURL=\s*(\S*?)\s*$/;
<commit_msg>Fix return type after porting to TypeScript<commit_after>/*
 * Copyright (C) 2008 Apple Inc. All Rights Reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

import * as Common from '../common/common.js';
import * as ProtocolClient from '../protocol_client/protocol_client.js';  // eslint-disable-line no-unused-vars
import * as TextUtils from '../text_utils/text_utils.js';

import {DebuggerModel, Location} from './DebuggerModel.js';  // eslint-disable-line no-unused-vars
import {ResourceTreeModel} from './ResourceTreeModel.js';
import {ExecutionContext} from './RuntimeModel.js';  // eslint-disable-line no-unused-vars

/**
 * @implements {TextUtils.ContentProvider.ContentProvider}
 * @unrestricted
 */
export class Script {
  /**
   * @param {!DebuggerModel} debuggerModel
   * @param {string} scriptId
   * @param {string} sourceURL
   * @param {number} startLine
   * @param {number} startColumn
   * @param {number} endLine
   * @param {number} endColumn
   * @param {!Protocol.Runtime.ExecutionContextId} executionContextId
   * @param {string} hash
   * @param {boolean} isContentScript
   * @param {boolean} isLiveEdit
   * @param {string|undefined} sourceMapURL
   * @param {boolean} hasSourceURL
   * @param {number} length
   * @param {?Protocol.Runtime.StackTrace} originStackTrace
   * @param {?number} codeOffset
   * @param {?string} scriptLanguage
   */
  constructor(
      debuggerModel, scriptId, sourceURL, startLine, startColumn, endLine, endColumn, executionContextId, hash,
      isContentScript, isLiveEdit, sourceMapURL, hasSourceURL, length, originStackTrace, codeOffset, scriptLanguage) {
    /** @type {?string} */
    this._source;

    this.debuggerModel = debuggerModel;
    this.scriptId = scriptId;
    this.sourceURL = sourceURL;
    this.lineOffset = startLine;
    this.columnOffset = startColumn;
    this.endLine = endLine;
    this.endColumn = endColumn;

    this.executionContextId = executionContextId;
    this.hash = hash;
    this._isContentScript = isContentScript;
    this._isLiveEdit = isLiveEdit;
    this.sourceMapURL = sourceMapURL;
    this.hasSourceURL = hasSourceURL;
    this.contentLength = length;
    this._originalContentProvider = null;
    this._originalSource = null;
    this.originStackTrace = originStackTrace;
    this._codeOffset = codeOffset;
    this._language = scriptLanguage;
    this._lineMap = null;
    this._functionBodyOffsets = null;
  }

  /**
   * @param {string} source
   * @return {string}
   */
  static _trimSourceURLComment(source) {
    let sourceURLIndex = source.lastIndexOf('//# sourceURL=');
    if (sourceURLIndex === -1) {
      sourceURLIndex = source.lastIndexOf('//@ sourceURL=');
      if (sourceURLIndex === -1) {
        return source;
      }
    }
    const sourceURLLineIndex = source.lastIndexOf('\n', sourceURLIndex);
    if (sourceURLLineIndex === -1) {
      return source;
    }
    const sourceURLLine = source.substr(sourceURLLineIndex + 1);
    if (!sourceURLLine.match(sourceURLRegex)) {
      return source;
    }
    return source.substr(0, sourceURLLineIndex);
  }

  /**
   * @return {boolean}
   */
  isContentScript() {
    return this._isContentScript;
  }

  /**
   * @return {?number}
   */
  codeOffset() {
    return this._codeOffset;
  }

  /**
   * @return {boolean}
   */
  isWasm() {
    return this._language === Protocol.Debugger.ScriptLanguage.WebAssembly;
  }

  /**
   * @return {boolean}
   */
  hasWasmDisassembly() {
    return !!this._lineMap && !this.sourceMapURL;
  }

  /**
   * @return {?ExecutionContext}
   */
  executionContext() {
    return this.debuggerModel.runtimeModel().executionContext(this.executionContextId);
  }

  /**
   * @return {boolean}
   */
  isLiveEdit() {
    return this._isLiveEdit;
  }

  /**
   * @override
   * @return {string}
   */
  contentURL() {
    return this.sourceURL;
  }

  /**
   * @override
   * @return {!Common.ResourceType.ResourceType}
   */
  contentType() {
    return Common.ResourceType.resourceTypes.Script;
  }

  /**
   * @override
   * @return {!Promise<boolean>}
   */
  contentEncoded() {
    return Promise.resolve(false);
  }

  /**
   * @override
   * @return {!Promise<!TextUtils.ContentProvider.DeferredContent>}
   */
  async requestContent() {
    if (this._source) {
      return {content: this._source, isEncoded: false};
    }
    if (!this.scriptId) {
      return {error: ls`Script removed or deleted.`, isEncoded: false};
    }

    try {
      const sourceOrBytecode =
          await this.debuggerModel.target().debuggerAgent().invoke_getScriptSource({scriptId: this.scriptId});
      const source = sourceOrBytecode.scriptSource;
      if (source) {
        if (this.hasSourceURL) {
          this._source = Script._trimSourceURLComment(source);
        } else {
          this._source = source;
        }
      } else {
        this._source = '';
        if (sourceOrBytecode.bytecode) {
          const worker = new Common.Worker.WorkerWrapper('wasmparser_worker_entrypoint');
          /** @type {!Promise<!MessageEvent>} */
          const promise = new Promise(function(resolve, reject) {
            worker.onmessage = resolve;
            worker.onerror = reject;
          });
          worker.postMessage({method: 'disassemble', params: {content: sourceOrBytecode.bytecode}});

          /** @type {{source: string, offsets: ?Array<number>, functionBodyOffsets: ?Array<{start: number, end: number}>}} */
          const data = (await promise).data;
          this._source = data.source;
          this._lineMap = data.offsets;
          this._functionBodyOffsets = data.functionBodyOffsets;
          this.endLine = (this._lineMap && this._lineMap.length) || 0;
        }
      }

      if (this._originalSource === null) {
        this._originalSource = this._source;
      }
      return {content: this._source, isEncoded: false};
    } catch (err) {
      return {error: ls`Unable to fetch script source.`, isEncoded: false};
    }
  }

  /**
   * @return {!Promise<!ArrayBuffer>}
   */
  async getWasmBytecode() {
    const base64 = await this.debuggerModel.target().debuggerAgent().invoke_getWasmBytecode({scriptId: this.scriptId});
    const response = await fetch(`data:application/wasm;base64,${base64.bytecode}`);
    return response.arrayBuffer();
  }

  /**
   * @return {!TextUtils.ContentProvider.ContentProvider}
   */
  originalContentProvider() {
    if (!this._originalContentProvider) {
      const lazyContent = () => this.requestContent().then(() => {
        return {
          content: this._originalSource || '',
          isEncoded: false,
        };
      });
      this._originalContentProvider =
          new TextUtils.StaticContentProvider.StaticContentProvider(this.contentURL(), this.contentType(), lazyContent);
    }
    return this._originalContentProvider;
  }

  /**
   * @override
   * @param {string} query
   * @param {boolean} caseSensitive
   * @param {boolean} isRegex
   * @return {!Promise<!Array<!TextUtils.ContentProvider.SearchMatch>>}
   */
  async searchInContent(query, caseSensitive, isRegex) {
    if (!this.scriptId) {
      return [];
    }

    const matches = await this.debuggerModel.target().debuggerAgent().invoke_searchInContent(
        {scriptId: this.scriptId, query, caseSensitive, isRegex});
    return (matches.result || [])
        .map(match => new TextUtils.ContentProvider.SearchMatch(match.lineNumber, match.lineContent));
  }

  /**
   * @param {string} source
   * @return {string}
   */
  _appendSourceURLCommentIfNeeded(source) {
    if (!this.hasSourceURL) {
      return source;
    }
    return source + '\n //# sourceURL=' + this.sourceURL;
  }

  /**
   * @param {string} newSource
   * @param {function(?ProtocolClient.InspectorBackend.ProtocolError, !Protocol.Runtime.ExceptionDetails=, !Array.<!Protocol.Debugger.CallFrame>=, !Protocol.Runtime.StackTrace=, !Protocol.Runtime.StackTraceId=, boolean=):void} callback
   */
  async editSource(newSource, callback) {
    newSource = Script._trimSourceURLComment(newSource);
    // We append correct sourceURL to script for consistency only. It's not actually needed for things to work correctly.
    newSource = this._appendSourceURLCommentIfNeeded(newSource);

    if (!this.scriptId) {
      callback('Script failed to parse');
      return;
    }

    await this.requestContent();
    if (this._source === newSource) {
      callback(null);
      return;
    }
    const response = await this.debuggerModel.target().debuggerAgent().invoke_setScriptSource(
        {scriptId: this.scriptId, scriptSource: newSource});

    if (!response.getError() && !response.exceptionDetails) {
      this._source = newSource;
    }

    const needsStepIn = !!response.stackChanged;
    callback(
        response.getError() || null, response.exceptionDetails, response.callFrames, response.asyncStackTrace,
        response.asyncStackTraceId, needsStepIn);
  }

  /**
   * @param {number} lineNumber
   * @param {number} columnNumber
   * @return {?Location}
   */
  rawLocation(lineNumber, columnNumber) {
    if (this.containsLocation(lineNumber, columnNumber)) {
      return new Location(this.debuggerModel, this.scriptId, lineNumber, columnNumber);
    }
    return null;
  }

  /**
   * @param {number} lineNumber
   * @return {?Location}
   */
  wasmByteLocation(lineNumber) {
    if (this._lineMap && lineNumber < this._lineMap.length) {
      return new Location(this.debuggerModel, this.scriptId, 0, this._lineMap[lineNumber]);
    }
    return null;
  }

  /**
   * @param {number} byteOffset
   * @return {number}
   */
  wasmDisassemblyLine(byteOffset) {
    let line = 0;
    // TODO: Implement binary search if necessary for large wasm modules
    while (this._lineMap && line < this._lineMap.length && byteOffset > this._lineMap[line]) {
      line++;
    }
    return line;
  }

  /**
   * @param {number} lineNumber
   * @return {boolean}
   */
  isWasmDisassemblyBreakableLine(lineNumber) {
    if (!this._functionBodyOffsets || this._functionBodyOffsets.length === 0) {
      return false;
    }
    const location = this.wasmByteLocation(lineNumber);
    if (!location) {
      return false;
    }
    const byteOffset = location.columnNumber;

    // Here, this._functionBodyOffsets is [{start:s0, end:e0}, {start:s1, end:e1}, ...].
    // Also, we have s0 < e0 < s1 < e1 ... and the breakable lines are defined by the union of [a0,b0), [a1,b1), ...
    let first = 0;
    let last = this._functionBodyOffsets.length - 1;
    // Quick return if it is outside of code section.
    if (byteOffset < this._functionBodyOffsets[first].start || byteOffset >= this._functionBodyOffsets[last].end) {
      return false;
    }
    // Binary search.
    while (first <= last) {
      const mid = (first + last) >> 1;
      const functionBodyOffset = this._functionBodyOffsets[mid];
      if (byteOffset < functionBodyOffset.start) {
        last = mid - 1;
      } else if (byteOffset >= functionBodyOffset.end) {
        first = mid + 1;
      } else {
        return true;
      }
    }

    return false;
  }

  /**
   *
   * @param {!Location} location
   * @return {!Array.<number>}
   */
  toRelativeLocation(location) {
    console.assert(
        location.scriptId === this.scriptId, '`toRelativeLocation` must be used with location of the same script');
    const relativeLineNumber = location.lineNumber - this.lineOffset;
    const relativeColumnNumber = (location.columnNumber || 0) - (relativeLineNumber === 0 ? this.columnOffset : 0);
    return [relativeLineNumber, relativeColumnNumber];
  }

  /**
   * @return {boolean}
   */
  isInlineScript() {
    const startsAtZero = !this.lineOffset && !this.columnOffset;
    return !this.isWasm() && !!this.sourceURL && !startsAtZero;
  }

  /**
   * @return {boolean}
   */
  isAnonymousScript() {
    return !this.sourceURL;
  }

  /**
   * @return {boolean}
   */
  isInlineScriptWithSourceURL() {
    return !!this.hasSourceURL && this.isInlineScript();
  }

  /**
   * @param {!Array<!Protocol.Debugger.ScriptPosition>} positions
   * @return {!Promise<boolean>}
   */
  async setBlackboxedRanges(positions) {
    const response = await this.debuggerModel.target().debuggerAgent().invoke_setBlackboxedRanges(
        {scriptId: this.scriptId, positions});
    return !response.getError();
  }

  /**
   * @param {number} lineNumber
   * @param {number} columnNumber
   * @return {boolean}
   */
  containsLocation(lineNumber, columnNumber) {
    const afterStart =
        (lineNumber === this.lineOffset && columnNumber >= this.columnOffset) || lineNumber > this.lineOffset;
    const beforeEnd = lineNumber < this.endLine || (lineNumber === this.endLine && columnNumber <= this.endColumn);
    return afterStart && beforeEnd;
  }

  /**
   * @return {string}
   */
  get frameId() {
    if (typeof this[frameIdSymbol] !== 'string') {
      this[frameIdSymbol] = frameIdForScript(this);
    }
    return this[frameIdSymbol] || '';
  }
}

const frameIdSymbol = Symbol('frameid');

/**
 * @param {!Script} script
 * @return {string}
 */
function frameIdForScript(script) {
  const executionContext = script.executionContext();
  if (executionContext) {
    return executionContext.frameId || '';
  }
  // This is to overcome compilation cache which doesn't get reset.
  const resourceTreeModel = script.debuggerModel.target().model(ResourceTreeModel);
  if (!resourceTreeModel || !resourceTreeModel.mainFrame) {
    return '';
  }
  return resourceTreeModel.mainFrame.id;
}

export const sourceURLRegex = /^[\040\t]*\/\/[@#] sourceURL=\s*(\S*?)\s*$/;
<|endoftext|>


<commit_before>import expect, { createSpy, spyOn } from 'expect';
import database from '../../index';
import { Storage } from '../../mocks';
import { Graph } from 'graph-crdt';

describe('Database hook', () => {
  let db, storage, hook;

  beforeEach(() => {
    storage = new Storage();
    hook = createSpy().andCall((write) => write);
  });

  describe('"before.write"', () => {
    let write;

    beforeEach(() => {
      write = spyOn(storage, 'write').andCallThrough();
      db = database({
        storage,
        hooks: {
          before: { write: hook },
        },
      });
    });

    afterEach(() => write.restore());

    it('is called before writes', async () => {
      await db.write('users', {});
      expect(hook).toHaveBeenCalled();
    });

    it('is able to override the graph', async () => {
      const graph = new Graph();
      hook.andCall((write) => ({ ...write, graph }));

      await db.write('stuff', {});

      const [{ graph: state }] = write.calls[0].arguments;
      expect(state).toBe(graph);
    });

    it('is able to prevent writes', async () => {
      const testError = new Error('Testing prevented writes');
      hook.andCall();
      hook.andThrow(testError);

      try {
        await db.write('user', { status: 'rejected (hopefully)' });
        throw new Error('Pipeline before.write rejection was ignored.');
      } catch (error) {
        expect(error).toBe(testError);
      }

      expect(write).toNotHaveBeenCalled();
      expect(await db.read('user')).toBe(null);
    });
  });

  describe('"after.write"', () => {
    beforeEach(() => {
      db = database({
        hooks: {
          after: { write: hook },
        },
      });
    });

    it('is called after writes', async () => {
      await db.write('users', {});
      expect(hook).toHaveBeenCalled();
    });

    it('is passed the options', async () => {
      await db.write('beans', {}, {
        cool: true,
      });

      const [write] = hook.calls[0].arguments;
      expect(write).toContain({
        cool: true,
      });
    });
  });

  describe('"before.read.nodes"', () => {
    let read, hook;

    beforeEach(() => {
      read = spyOn(storage, 'read');
      hook = createSpy().andCall((read) => read);
      db = database({
        storage,
        hooks: {
          before: {
            read: { nodes: hook },
          },
        },
      });
    });

    it('calls the hook before reads', async () => {
      expect(hook).toNotHaveBeenCalled();
      await db.read('users');
      expect(hook).toHaveBeenCalled();
    });

    it('passes the key and options', async () => {
      const options = { 'engage hyperdrive': true };
      await db.read('key name', options);
      const [read] = hook.calls[0].arguments;
      expect(read.keys).toEqual(['key name']);
      expect(read).toContain(options);
    });

    it('can override the key', async () => {
      hook.andCall((read) => ({
        ...read,
        key: `prefix/${read.keys[0]}`,
      }));
      await db.read('stuff');
      const [{ key }] = read.calls[0].arguments;
      expect(key).toBe('prefix/stuff');
    });

    it('can override the options', async () => {
      hook.andCall((read) => ({
        ...read,
        overridden: true,
      }));

      await db.read('key', { original: true });
      const [options] = read.calls[0].arguments;
      expect(options).toContain({
        overridden: true,
        original: true,
      });
    });
  });

  describe('"after.read.node"', () => {
    let hook;

    beforeEach(async () => {
      hook = createSpy().andCall((read) => read);
      db = database({
        hooks: {
          after: {
            read: { nodes: hook },
          },
        },
      });

      await db.write('data', {
        existing: true,
      });
    });

    it('is called after reads', async () => {
      await db.read('data');
      expect(hook).toHaveBeenCalled();
    });

    it('is passed the read value and options', async () => {
      const data = await db.read('data', { cool: 'totally' });
      const [read] = hook.calls[0].arguments;

      expect(read.contexts).toEqual([data]);
      expect(read).toContain({ cool: 'totally' });
    });

    it('can override the return node', async () => {
      hook.andCall((read) => ({
        ...read,
        contexts: ['haha, replaced!'],
      }));
      const value = await db.read('data');
      expect(value).toBe('haha, replaced!');
    });
  });

  describe('"before.read.fields"', () => {
    let hook, node, read;

    beforeEach(async () => {
      hook = createSpy().andCall((read) => read);
      db = database({
        storage,
        hooks: {
          before: {
            read: { fields: hook },
          },
        },
      });

      node = await db.write('context hook test', {});
      read = spyOn(storage, 'read').andCallThrough();
    });

    it('is passed the fields, node, and options', async () => {
      await node.read('name', { passed: true });
      expect(hook).toHaveBeenCalled();

      const [read] = hook.calls[0].arguments;

      expect(read.node).toBe(node);
      expect(read.fields).toEqual(['name']);
      expect(read).toContain({ passed: true });
    });

    it('can override the fields', async () => {
      await node.write('replaced', 'resolved');
      hook.andCall((read) => ({
        ...read,
        fields: ['replaced'],
      }));

      const value = await node.read('nothing here');
      expect(value).toBe('resolved');
    });
  });

  describe('"after.read.fields"', () => {
    let hook, node;

    beforeEach(async () => {
      hook = createSpy().andCall((read) => read);
      db = database({
        hooks: {
          after: {
            read: { fields: hook },
          },
        },
      });

      node = await db.write('after.read.fields tests', {});
    });

    it('is given the fields, value, and options', async () => {
      await node.write('level', 5);
      await node.read('level', { opts: true });
      expect(hook).toHaveBeenCalled();

      const [read] = hook.calls[0].arguments;

      expect(read).toContain({
        fields: [5],
        opts: true,
      });
    });

    it('can override the value', async () => {
      hook.andCall((read) => ({
        ...read,
        fields: ['replaced'],
      }));

      const value = await node.read('whatever');

      expect(value).toBe('replaced');
    });

    it('is called after resolving edges', async () => {
      const edge = await db.write('edge', {});
      await node.write('edge', edge);

      hook.andCall((read) => {
        expect(read.fields[0]).toBe(edge);

        return {
          ...read,
          fields: ['replaced value'],
        };
      });

      const value = await node.read('edge');
      expect(value).toBe('replaced value');
    });
  });
});
<commit_msg>Fix lint<commit_after>import expect, { createSpy, spyOn } from 'expect';
import database from '../../index';
import { Storage } from '../../mocks';
import { Graph } from 'graph-crdt';

describe('Database hook', () => {
  let db, storage, hook;

  beforeEach(() => {
    storage = new Storage();
    hook = createSpy().andCall((write) => write);
  });

  describe('"before.write"', () => {
    let write;

    beforeEach(() => {
      write = spyOn(storage, 'write').andCallThrough();
      db = database({
        storage,
        hooks: {
          before: { write: hook },
        },
      });
    });

    afterEach(() => write.restore());

    it('is called before writes', async () => {
      await db.write('users', {});
      expect(hook).toHaveBeenCalled();
    });

    it('is able to override the graph', async () => {
      const graph = new Graph();
      hook.andCall((write) => ({ ...write, graph }));

      await db.write('stuff', {});

      const [{ graph: state }] = write.calls[0].arguments;
      expect(state).toBe(graph);
    });

    it('is able to prevent writes', async () => {
      const testError = new Error('Testing prevented writes');
      hook.andCall();
      hook.andThrow(testError);

      try {
        await db.write('user', { status: 'rejected (hopefully)' });
        throw new Error('Pipeline before.write rejection was ignored.');
      } catch (error) {
        expect(error).toBe(testError);
      }

      expect(write).toNotHaveBeenCalled();
      expect(await db.read('user')).toBe(null);
    });
  });

  describe('"after.write"', () => {
    beforeEach(() => {
      db = database({
        hooks: {
          after: { write: hook },
        },
      });
    });

    it('is called after writes', async () => {
      await db.write('users', {});
      expect(hook).toHaveBeenCalled();
    });

    it('is passed the options', async () => {
      await db.write('beans', {}, {
        cool: true,
      });

      const [write] = hook.calls[0].arguments;
      expect(write).toContain({
        cool: true,
      });
    });
  });

  describe('"before.read.nodes"', () => {
    let read, hook;

    beforeEach(() => {
      read = spyOn(storage, 'read');
      hook = createSpy().andCall((read) => read);
      db = database({
        storage,
        hooks: {
          before: {
            read: { nodes: hook },
          },
        },
      });
    });

    it('calls the hook before reads', async () => {
      expect(hook).toNotHaveBeenCalled();
      await db.read('users');
      expect(hook).toHaveBeenCalled();
    });

    it('passes the key and options', async () => {
      const options = { 'engage hyperdrive': true };
      await db.read('key name', options);
      const [read] = hook.calls[0].arguments;
      expect(read.keys).toEqual(['key name']);
      expect(read).toContain(options);
    });

    it('can override the key', async () => {
      hook.andCall((read) => ({
        ...read,
        key: `prefix/${read.keys[0]}`,
      }));
      await db.read('stuff');
      const [{ key }] = read.calls[0].arguments;
      expect(key).toBe('prefix/stuff');
    });

    it('can override the options', async () => {
      hook.andCall((read) => ({
        ...read,
        overridden: true,
      }));

      await db.read('key', { original: true });
      const [options] = read.calls[0].arguments;
      expect(options).toContain({
        overridden: true,
        original: true,
      });
    });
  });

  describe('"after.read.node"', () => {
    let hook;

    beforeEach(async () => {
      hook = createSpy().andCall((read) => read);
      db = database({
        hooks: {
          after: {
            read: { nodes: hook },
          },
        },
      });

      await db.write('data', {
        existing: true,
      });
    });

    it('is called after reads', async () => {
      await db.read('data');
      expect(hook).toHaveBeenCalled();
    });

    it('is passed the read value and options', async () => {
      const data = await db.read('data', { cool: 'totally' });
      const [read] = hook.calls[0].arguments;

      expect(read.contexts).toEqual([data]);
      expect(read).toContain({ cool: 'totally' });
    });

    it('can override the return node', async () => {
      hook.andCall((read) => ({
        ...read,
        contexts: ['haha, replaced!'],
      }));
      const value = await db.read('data');
      expect(value).toBe('haha, replaced!');
    });
  });

  describe('"before.read.fields"', () => {
    let hook, node;

    beforeEach(async () => {
      hook = createSpy().andCall((read) => read);
      db = database({
        storage,
        hooks: {
          before: {
            read: { fields: hook },
          },
        },
      });

      node = await db.write('context hook test', {});
      spyOn(storage, 'read').andCallThrough();
    });

    it('is passed the fields, node, and options', async () => {
      await node.read('name', { passed: true });
      expect(hook).toHaveBeenCalled();

      const [read] = hook.calls[0].arguments;

      expect(read.node).toBe(node);
      expect(read.fields).toEqual(['name']);
      expect(read).toContain({ passed: true });
    });

    it('can override the fields', async () => {
      await node.write('replaced', 'resolved');
      hook.andCall((read) => ({
        ...read,
        fields: ['replaced'],
      }));

      const value = await node.read('nothing here');
      expect(value).toBe('resolved');
    });
  });

  describe('"after.read.fields"', () => {
    let hook, node;

    beforeEach(async () => {
      hook = createSpy().andCall((read) => read);
      db = database({
        hooks: {
          after: {
            read: { fields: hook },
          },
        },
      });

      node = await db.write('after.read.fields tests', {});
    });

    it('is given the fields, value, and options', async () => {
      await node.write('level', 5);
      await node.read('level', { opts: true });
      expect(hook).toHaveBeenCalled();

      const [read] = hook.calls[0].arguments;

      expect(read).toContain({
        fields: [5],
        opts: true,
      });
    });

    it('can override the value', async () => {
      hook.andCall((read) => ({
        ...read,
        fields: ['replaced'],
      }));

      const value = await node.read('whatever');

      expect(value).toBe('replaced');
    });

    it('is called after resolving edges', async () => {
      const edge = await db.write('edge', {});
      await node.write('edge', edge);

      hook.andCall((read) => {
        expect(read.fields[0]).toBe(edge);

        return {
          ...read,
          fields: ['replaced value'],
        };
      });

      const value = await node.read('edge');
      expect(value).toBe('replaced value');
    });
  });
});
<|endoftext|>


<commit_before>module.exports = function(grunt) {
  "use strict";

  grunt.initConfig({
    pkg: '<json:package.json>',
    jshint: {
      options: {
        curly: true,
        eqeqeq: true,
        immed: true,
        latedef: true,
        newcap: true,
        noarg: true,
        sub: true,
        undef: true,
        boss: true,
        eqnull: true,
        node: true,
        trailing: true,
        globals: {
          exports: true
        }
      },
      files: ['grunt.js', 'tasks/**/*.js']
    }
  });

  grunt.loadNpmTasks('grunt-contrib-jshint');
  grunt.loadTasks('tasks');
  grunt.registerTask('default', ['jshint', 'check-modules']);

};<commit_msg>Lint Gruntfile.js, not grunt.js<commit_after>module.exports = function(grunt) {
  "use strict";

  grunt.initConfig({
    pkg: '<json:package.json>',
    jshint: {
      options: {
        curly: true,
        eqeqeq: true,
        immed: true,
        latedef: true,
        newcap: true,
        noarg: true,
        sub: true,
        undef: true,
        boss: true,
        eqnull: true,
        node: true,
        trailing: true,
        globals: {
          exports: true
        }
      },
      files: ['Gruntfile.js', 'tasks/**/*.js']
    }
  });

  grunt.loadNpmTasks('grunt-contrib-jshint');
  grunt.loadTasks('tasks');
  grunt.registerTask('default', ['jshint', 'check-modules']);

};<|endoftext|>


<commit_before><commit_msg>updates submodules<commit_after><|endoftext|>


<commit_before>/*globals qq, document, setTimeout*/
/*globals clearTimeout*/
qq.UploadHandlerForm = function(o, uploadCompleteCallback, logCallback) {
    "use strict";

    var options = o,
        inputs = [],
        uuids = [],
        detachLoadEvents = {},
        postMessageCallbackTimers = {},
        uploadComplete = uploadCompleteCallback,
        log = logCallback,
        corsMessageReceiver = new qq.WindowReceiveMessage({log: log}),
        onloadCallbacks = {},
        api;

    function detachLoadEvent(id) {
        if (detachLoadEvents[id] !== undefined) {
            detachLoadEvents[id]();
            delete detachLoadEvents[id];
        }
    }

    function registerPostMessageCallback(iframe, callback) {
        var id = iframe.id;

        onloadCallbacks[uuids[id]] = callback;

        detachLoadEvents[id] = qq(iframe).attach('load', function() {
            if (inputs[id]) {
                log("Received iframe load event for CORS upload request (file id " + id + ")");

                postMessageCallbackTimers[id] = setTimeout(function() {
                    var errorMessage = "No valid message received from loaded iframe for file id " + id;
                    log(errorMessage, "error");
                    callback({
                        error: errorMessage
                    });
                }, 1000);
            }
        });

        corsMessageReceiver.receiveMessage(id, function(message) {
            log("Received the following window message: '" + message + "'");
            var response = qq.parseJson(message),
                uuid = response.uuid,
                onloadCallback;

            if (uuid && onloadCallbacks[uuid]) {
                clearTimeout(postMessageCallbackTimers[id]);
                delete postMessageCallbackTimers[id];

                detachLoadEvent(id);

                onloadCallback = onloadCallbacks[uuid];

                delete onloadCallbacks[uuid];
                corsMessageReceiver.stopReceivingMessages(id);
                onloadCallback(response);
            }
            else if (!uuid) {
                log("'" + message + "' does not contain a UUID - ignoring.");
            }
        });
    }

    function attachLoadEvent(iframe, callback) {
        /*jslint eqeq: true*/

        if (options.cors.expected) {
            registerPostMessageCallback(iframe, callback);
        }
        else {
            detachLoadEvents[iframe.id] = qq(iframe).attach('load', function(){
                log('Received response for ' + iframe.id);

                // when we remove iframe from dom
                // the request stops, but in IE load
                // event fires
                if (!iframe.parentNode){
                    return;
                }

                try {
                    // fixing Opera 10.53
                    if (iframe.contentDocument &&
                        iframe.contentDocument.body &&
                        iframe.contentDocument.body.innerHTML == "false"){
                        // In Opera event is fired second time
                        // when body.innerHTML changed from false
                        // to server response approx. after 1 sec
                        // when we upload file with iframe
                        return;
                    }
                }
                catch (error) {
                    //IE may throw an "access is denied" error when attempting to access contentDocument on the iframe in some cases
                    log('Error when attempting to access iframe during handling of upload response (' + error + ")", 'error');
                }

                callback();
            });
        }
    }

    /**
     * Returns json object received by iframe from server.
     */
    function getIframeContentJson(iframe) {
        /*jshint evil: true*/

        var response;

        //IE may throw an "access is denied" error when attempting to access contentDocument on the iframe in some cases
        try {
            // iframe.contentWindow.document - for IE<7
            var doc = iframe.contentDocument || iframe.contentWindow.document,
                innerHTML = doc.body.innerHTML;

            log("converting iframe's innerHTML to JSON");
            log("innerHTML = " + innerHTML);
            //plain text response may be wrapped in <pre> tag
            if (innerHTML && innerHTML.match(/^<pre/i)) {
                innerHTML = doc.body.firstChild.firstChild.nodeValue;
            }

            response = qq.parseJson(innerHTML);
        } catch(error){
            log('Error when attempting to parse form upload response (' + error + ")", 'error');
            response = {success: false};
        }

        return response;
    }

    /**
     * Creates iframe with unique name
     */
    function createIframe(id){
        // We can't use following code as the name attribute
        // won't be properly registered in IE6, and new window
        // on form submit will open
        // var iframe = document.createElement('iframe');
        // iframe.setAttribute('name', id);

        var iframe = qq.toElement('<iframe src="javascript:false;" name="' + id + '" />');

        iframe.setAttribute('id', id);

        iframe.style.display = 'none';
        document.body.appendChild(iframe);

        return iframe;
    }

    /**
     * Creates form, that will be submitted to iframe
     */
    function createForm(id, iframe){
        var params = options.paramsStore.getParams(id),
            protocol = options.demoMode ? "GET" : "POST",
            form = qq.toElement('<form method="' + protocol + '" enctype="multipart/form-data"></form>'),
            endpoint = options.endpointStore.getEndpoint(id),
            url = endpoint;

        params[options.uuidParamName] = uuids[id];

        if (!options.paramsInBody) {
            url = qq.obj2url(params, endpoint);
        }
        else {
            qq.obj2Inputs(params, form);
        }

        form.setAttribute('action', url);
        form.setAttribute('target', iframe.name);
        form.style.display = 'none';
        document.body.appendChild(form);

        return form;
    }

    api = {
        add: function(fileInput) {
            fileInput.setAttribute('name', options.inputName);

            var id = inputs.push(fileInput) - 1;
            uuids[id] = qq.getUniqueId();

            // remove file input from DOM
            if (fileInput.parentNode){
                qq(fileInput).remove();
            }

            return id;
        },
        getName: function(id) {
            /*jslint regexp: true*/

            // get input value and remove path to normalize
            return inputs[id].value.replace(/.*(\/|\\)/, "");
        },
        isValid: function(id) {
            return inputs[id] !== undefined;
        },
        reset: function() {
            qq.UploadHandler.prototype.reset.apply(this, arguments);
            inputs = [];
            uuids = [];
            detachLoadEvents = {};
        },
        getUuid: function(id) {
            return uuids[id];
        },
        cancel: function(id) {
            options.onCancel(id, this.getName(id));

            delete inputs[id];
            delete uuids[id];
            delete detachLoadEvents[id];

            if (options.cors.expected) {
                clearTimeout(postMessageCallbackTimers[id]);
                delete postMessageCallbackTimers[id];
                corsMessageReceiver.stopReceivingMessages(id);
            }

            var iframe = document.getElementById(id);
            if (iframe) {
                // to cancel request set src to something else
                // we use src="javascript:false;" because it doesn't
                // trigger ie6 prompt on https
                iframe.setAttribute('src', 'java' + String.fromCharCode(115) + 'cript:false;'); //deal with "JSLint: javascript URL" warning, which apparently cannot be turned off

                qq(iframe).remove();
            }
        },
        upload: function(id){
            var input = inputs[id],
                fileName = api.getName(id),
                iframe = createIframe(id),
                form;

            if (!input){
                throw new Error('file with passed id was not added, or already uploaded or cancelled');
            }

            options.onUpload(id, this.getName(id));

            form = createForm(id, iframe);
            form.appendChild(input);

            attachLoadEvent(iframe, function(responseFromMessage){
                log('iframe loaded');

                var response = responseFromMessage ? responseFromMessage : getIframeContentJson(iframe);

                detachLoadEvent(id);

                //we can't remove an iframe if the iframe doesn't belong to the same domain
                if (!options.cors.expected) {
                    qq(iframe).remove();
                }

                if (!response.success) {
                    if (options.onAutoRetry(id, fileName, response)) {
                        return;
                    }
                }
                options.onComplete(id, fileName, response);
                uploadComplete(id);
            });

            log('Sending upload request for ' + id);
            form.submit();
            qq(form).remove();

            return id;
        }
    };

    return api;
};
<commit_msg>#759 - fix reset API function for IE7-9<commit_after>/*globals qq, document, setTimeout*/
/*globals clearTimeout*/
qq.UploadHandlerForm = function(o, uploadCompleteCallback, logCallback) {
    "use strict";

    var options = o,
        inputs = [],
        uuids = [],
        detachLoadEvents = {},
        postMessageCallbackTimers = {},
        uploadComplete = uploadCompleteCallback,
        log = logCallback,
        corsMessageReceiver = new qq.WindowReceiveMessage({log: log}),
        onloadCallbacks = {},
        api;

    function detachLoadEvent(id) {
        if (detachLoadEvents[id] !== undefined) {
            detachLoadEvents[id]();
            delete detachLoadEvents[id];
        }
    }

    function registerPostMessageCallback(iframe, callback) {
        var id = iframe.id;

        onloadCallbacks[uuids[id]] = callback;

        detachLoadEvents[id] = qq(iframe).attach('load', function() {
            if (inputs[id]) {
                log("Received iframe load event for CORS upload request (file id " + id + ")");

                postMessageCallbackTimers[id] = setTimeout(function() {
                    var errorMessage = "No valid message received from loaded iframe for file id " + id;
                    log(errorMessage, "error");
                    callback({
                        error: errorMessage
                    });
                }, 1000);
            }
        });

        corsMessageReceiver.receiveMessage(id, function(message) {
            log("Received the following window message: '" + message + "'");
            var response = qq.parseJson(message),
                uuid = response.uuid,
                onloadCallback;

            if (uuid && onloadCallbacks[uuid]) {
                clearTimeout(postMessageCallbackTimers[id]);
                delete postMessageCallbackTimers[id];

                detachLoadEvent(id);

                onloadCallback = onloadCallbacks[uuid];

                delete onloadCallbacks[uuid];
                corsMessageReceiver.stopReceivingMessages(id);
                onloadCallback(response);
            }
            else if (!uuid) {
                log("'" + message + "' does not contain a UUID - ignoring.");
            }
        });
    }

    function attachLoadEvent(iframe, callback) {
        /*jslint eqeq: true*/

        if (options.cors.expected) {
            registerPostMessageCallback(iframe, callback);
        }
        else {
            detachLoadEvents[iframe.id] = qq(iframe).attach('load', function(){
                log('Received response for ' + iframe.id);

                // when we remove iframe from dom
                // the request stops, but in IE load
                // event fires
                if (!iframe.parentNode){
                    return;
                }

                try {
                    // fixing Opera 10.53
                    if (iframe.contentDocument &&
                        iframe.contentDocument.body &&
                        iframe.contentDocument.body.innerHTML == "false"){
                        // In Opera event is fired second time
                        // when body.innerHTML changed from false
                        // to server response approx. after 1 sec
                        // when we upload file with iframe
                        return;
                    }
                }
                catch (error) {
                    //IE may throw an "access is denied" error when attempting to access contentDocument on the iframe in some cases
                    log('Error when attempting to access iframe during handling of upload response (' + error + ")", 'error');
                }

                callback();
            });
        }
    }

    /**
     * Returns json object received by iframe from server.
     */
    function getIframeContentJson(iframe) {
        /*jshint evil: true*/

        var response;

        //IE may throw an "access is denied" error when attempting to access contentDocument on the iframe in some cases
        try {
            // iframe.contentWindow.document - for IE<7
            var doc = iframe.contentDocument || iframe.contentWindow.document,
                innerHTML = doc.body.innerHTML;

            log("converting iframe's innerHTML to JSON");
            log("innerHTML = " + innerHTML);
            //plain text response may be wrapped in <pre> tag
            if (innerHTML && innerHTML.match(/^<pre/i)) {
                innerHTML = doc.body.firstChild.firstChild.nodeValue;
            }

            response = qq.parseJson(innerHTML);
        } catch(error){
            log('Error when attempting to parse form upload response (' + error + ")", 'error');
            response = {success: false};
        }

        return response;
    }

    /**
     * Creates iframe with unique name
     */
    function createIframe(id){
        // We can't use following code as the name attribute
        // won't be properly registered in IE6, and new window
        // on form submit will open
        // var iframe = document.createElement('iframe');
        // iframe.setAttribute('name', id);

        var iframe = qq.toElement('<iframe src="javascript:false;" name="' + id + '" />');

        iframe.setAttribute('id', id);

        iframe.style.display = 'none';
        document.body.appendChild(iframe);

        return iframe;
    }

    /**
     * Creates form, that will be submitted to iframe
     */
    function createForm(id, iframe){
        var params = options.paramsStore.getParams(id),
            protocol = options.demoMode ? "GET" : "POST",
            form = qq.toElement('<form method="' + protocol + '" enctype="multipart/form-data"></form>'),
            endpoint = options.endpointStore.getEndpoint(id),
            url = endpoint;

        params[options.uuidParamName] = uuids[id];

        if (!options.paramsInBody) {
            url = qq.obj2url(params, endpoint);
        }
        else {
            qq.obj2Inputs(params, form);
        }

        form.setAttribute('action', url);
        form.setAttribute('target', iframe.name);
        form.style.display = 'none';
        document.body.appendChild(form);

        return form;
    }

    api = {
        add: function(fileInput) {
            fileInput.setAttribute('name', options.inputName);

            var id = inputs.push(fileInput) - 1;
            uuids[id] = qq.getUniqueId();

            // remove file input from DOM
            if (fileInput.parentNode){
                qq(fileInput).remove();
            }

            return id;
        },
        getName: function(id) {
            /*jslint regexp: true*/

            // get input value and remove path to normalize
            return inputs[id].value.replace(/.*(\/|\\)/, "");
        },
        isValid: function(id) {
            return inputs[id] !== undefined;
        },
        reset: function() {
            inputs = [];
            uuids = [];
            detachLoadEvents = {};
        },
        getUuid: function(id) {
            return uuids[id];
        },
        cancel: function(id) {
            options.onCancel(id, this.getName(id));

            delete inputs[id];
            delete uuids[id];
            delete detachLoadEvents[id];

            if (options.cors.expected) {
                clearTimeout(postMessageCallbackTimers[id]);
                delete postMessageCallbackTimers[id];
                corsMessageReceiver.stopReceivingMessages(id);
            }

            var iframe = document.getElementById(id);
            if (iframe) {
                // to cancel request set src to something else
                // we use src="javascript:false;" because it doesn't
                // trigger ie6 prompt on https
                iframe.setAttribute('src', 'java' + String.fromCharCode(115) + 'cript:false;'); //deal with "JSLint: javascript URL" warning, which apparently cannot be turned off

                qq(iframe).remove();
            }
        },
        upload: function(id){
            var input = inputs[id],
                fileName = api.getName(id),
                iframe = createIframe(id),
                form;

            if (!input){
                throw new Error('file with passed id was not added, or already uploaded or cancelled');
            }

            options.onUpload(id, this.getName(id));

            form = createForm(id, iframe);
            form.appendChild(input);

            attachLoadEvent(iframe, function(responseFromMessage){
                log('iframe loaded');

                var response = responseFromMessage ? responseFromMessage : getIframeContentJson(iframe);

                detachLoadEvent(id);

                //we can't remove an iframe if the iframe doesn't belong to the same domain
                if (!options.cors.expected) {
                    qq(iframe).remove();
                }

                if (!response.success) {
                    if (options.onAutoRetry(id, fileName, response)) {
                        return;
                    }
                }
                options.onComplete(id, fileName, response);
                uploadComplete(id);
            });

            log('Sending upload request for ' + id);
            form.submit();
            qq(form).remove();

            return id;
        }
    };

    return api;
};
<|endoftext|>


<commit_before>const {resolve} = require('path');
const {DefinePlugin} = require('webpack');
const {
  GITHUB_URL,
  getVersionString,
} = require('react-devtools-extensions/utils');
const {resolveFeatureFlags} = require('react-devtools-shared/buildUtils');

const NODE_ENV = process.env.NODE_ENV;
if (!NODE_ENV) {
  console.error('NODE_ENV not set');
  process.exit(1);
}

const __DEV__ = NODE_ENV === 'development';

const DEVTOOLS_VERSION = getVersionString();

module.exports = {
  mode: __DEV__ ? 'development' : 'production',
  devtool: __DEV__ ? 'eval-cheap-source-map' : 'source-map',
  entry: {
    backend: './src/backend.js',
    frontend: './src/frontend.js',
  },
  output: {
    path: __dirname + '/dist',
    filename: '[name].js',
    library: '[name]',
    libraryTarget: 'commonjs2',
  },
  externals: {
    react: 'react',
    // TODO: Once this package is published, remove the external
    // 'react-debug-tools': 'react-debug-tools',
    'react-devtools-feature-flags': resolveFeatureFlags('inline'),
    'react-dom': 'react-dom',
    'react-is': 'react-is',
    scheduler: 'scheduler',
  },
  optimization: {
    minimize: false,
  },
  plugins: [
    new DefinePlugin({
      __DEV__,
      __EXPERIMENTAL__: true,
      __EXTENSION__: false,
      __PROFILE__: false,
      __TEST__: NODE_ENV === 'test',
      'process.env.DEVTOOLS_VERSION': `"${DEVTOOLS_VERSION}"`,
      'process.env.GITHUB_URL': `"${GITHUB_URL}"`,
      'process.env.NODE_ENV': `"${NODE_ENV}"`,
    }),
  ],
  module: {
    rules: [
      {
        test: /\.js$/,
        loader: 'babel-loader',
        options: {
          configFile: resolve(
            __dirname,
            '..',
            'react-devtools-shared',
            'babel.config.js',
          ),
        },
      },
      {
        test: /\.css$/,
        use: [
          {
            loader: 'style-loader',
          },
          {
            loader: 'css-loader',
            options: {
              sourceMap: true,
              modules: true,
              localIdentName: '[local]___[hash:base64:5]',
            },
          },
        ],
      },
    ],
  },
};
<commit_msg>react-devtools-inline: Remove css-sourcemap's when bundling for dist (#20170)<commit_after>const {resolve} = require('path');
const {DefinePlugin} = require('webpack');
const {
  GITHUB_URL,
  getVersionString,
} = require('react-devtools-extensions/utils');
const {resolveFeatureFlags} = require('react-devtools-shared/buildUtils');

const NODE_ENV = process.env.NODE_ENV;
if (!NODE_ENV) {
  console.error('NODE_ENV not set');
  process.exit(1);
}

const __DEV__ = NODE_ENV === 'development';

const DEVTOOLS_VERSION = getVersionString();

module.exports = {
  mode: __DEV__ ? 'development' : 'production',
  devtool: __DEV__ ? 'eval-cheap-source-map' : 'source-map',
  entry: {
    backend: './src/backend.js',
    frontend: './src/frontend.js',
  },
  output: {
    path: __dirname + '/dist',
    filename: '[name].js',
    library: '[name]',
    libraryTarget: 'commonjs2',
  },
  externals: {
    react: 'react',
    // TODO: Once this package is published, remove the external
    // 'react-debug-tools': 'react-debug-tools',
    'react-devtools-feature-flags': resolveFeatureFlags('inline'),
    'react-dom': 'react-dom',
    'react-is': 'react-is',
    scheduler: 'scheduler',
  },
  optimization: {
    minimize: false,
  },
  plugins: [
    new DefinePlugin({
      __DEV__,
      __EXPERIMENTAL__: true,
      __EXTENSION__: false,
      __PROFILE__: false,
      __TEST__: NODE_ENV === 'test',
      'process.env.DEVTOOLS_VERSION': `"${DEVTOOLS_VERSION}"`,
      'process.env.GITHUB_URL': `"${GITHUB_URL}"`,
      'process.env.NODE_ENV': `"${NODE_ENV}"`,
    }),
  ],
  module: {
    rules: [
      {
        test: /\.js$/,
        loader: 'babel-loader',
        options: {
          configFile: resolve(
            __dirname,
            '..',
            'react-devtools-shared',
            'babel.config.js',
          ),
        },
      },
      {
        test: /\.css$/,
        use: [
          {
            loader: 'style-loader',
          },
          {
            loader: 'css-loader',
            options: {
              sourceMap: __DEV__,
              modules: true,
              localIdentName: '[local]___[hash:base64:5]',
            },
          },
        ],
      },
    ],
  },
};
<|endoftext|>