function getScopeData(fileInfo, offset) {
    // Create a new tern Server
    // Existing tern server resolves all the required modules which might take time
    // We only need to analyze single file for getting the scope
    ternOptions.plugins = {};
    var ternServer = new Tern.Server(ternOptions);
    ternServer.addFile(fileInfo.name, fileInfo.text);

    var error;
    var request = buildRequest(fileInfo, "completions", offset); // for primepump

    try {
        // primepump
        ternServer.request(request, function (ternError, data) {
            if (ternError) {
                _log("Error for Tern request: \n" + JSON.stringify(request) + "\n" + ternError);
                error = ternError.toString();
            } else {
                var file = ternServer.findFile(fileInfo.name);
                var scope = Infer.scopeAt(file.ast, Tern.resolvePos(file, offset), file.scope);

                if (scope) {
                    // Remove unwanted properties to remove cycles in the object
                    scope = JSON.parse(JSON.stringify(scope, function(key, value) {
                        if (["proto", "propertyOf", "onNewProp", "sourceFile", "maybeProps"].includes(key)) {
                            return undefined;
                        }
                        else if (key === "fnType") {
                             return value.name || "FunctionExpression";
                        }
                        else if (key === "props") {
                            for (var key in value) {
                                value[key] = value[key].propertyName;
                            }
                            return value;
                        } else if (key === "originNode") {
                            return value && {
                                start: value.start,
                                end: value.end,
                                type: value.type,
                                body: {
                                    start: value.body.start,
                                    end: value.body.end
                                }
                            };
                        }

                        return value;
                    }));
                }

                self.postMessage({
                    type: MessageIds.TERN_SCOPEDATA_MSG,
                    file: _getNormalizedFilename(fileInfo.name),
                    offset: offset,
                    scope: scope
                });
            }
        });
    } catch (e) {
        _reportError(e, fileInfo.name);
    } finally {
        ternServer.reset();
        Infer.resetGuessing();
    }
}
Get scope at the offset in the file
@param {{type: string, name: string, offsetLines: number, text: string}} fileInfo
- type of update, name of file, and the text of the update.
For "full" updates, the whole text of the file is present. For "part" updates,
the changed portion of the text. For "empty" updates, the file has not been modified
and the text is empty.
@param {{line: number, ch: number}} offset - the offset into the
file for cursor