github.com/ManabuSeki/goa-v1@v1.4.3/goagen/gen_js/generator.go (about)

     1  package genjs
     2  
     3  import (
     4  	"flag"
     5  	"fmt"
     6  	"io/ioutil"
     7  	"os"
     8  	"path/filepath"
     9  	"sort"
    10  	"strings"
    11  	"text/template"
    12  	"time"
    13  
    14  	"github.com/goadesign/goa/design"
    15  	"github.com/goadesign/goa/goagen/codegen"
    16  	"github.com/goadesign/goa/goagen/utils"
    17  )
    18  
    19  //NewGenerator returns an initialized instance of a JavaScript Client Generator
    20  func NewGenerator(options ...Option) *Generator {
    21  	g := &Generator{}
    22  
    23  	for _, option := range options {
    24  		option(g)
    25  	}
    26  
    27  	return g
    28  }
    29  
    30  // Generator is the application code generator.
    31  type Generator struct {
    32  	API       *design.APIDefinition // The API definition
    33  	OutDir    string                // Destination directory
    34  	Timeout   time.Duration         // Timeout used by JavaScript client when making requests
    35  	Scheme    string                // Scheme used by JavaScript client
    36  	Host      string                // Host addressed by JavaScript client
    37  	NoExample bool                  // Do not generate an HTML example file
    38  	genfiles  []string              // Generated files
    39  }
    40  
    41  // Generate is the generator entry point called by the meta generator.
    42  func Generate() (files []string, err error) {
    43  	var (
    44  		outDir, ver  string
    45  		timeout      time.Duration
    46  		scheme, host string
    47  		noexample    bool
    48  	)
    49  
    50  	set := flag.NewFlagSet("client", flag.PanicOnError)
    51  	set.StringVar(&outDir, "out", "", "")
    52  	set.String("design", "", "")
    53  	set.DurationVar(&timeout, "timeout", time.Duration(20)*time.Second, "")
    54  	set.StringVar(&scheme, "scheme", "", "")
    55  	set.StringVar(&host, "host", "", "")
    56  	set.StringVar(&ver, "version", "", "")
    57  	set.BoolVar(&noexample, "noexample", false, "")
    58  	set.Parse(os.Args[1:])
    59  
    60  	// First check compatibility
    61  	if err := codegen.CheckVersion(ver); err != nil {
    62  		return nil, err
    63  	}
    64  
    65  	// Now proceed
    66  	g := &Generator{OutDir: outDir, Timeout: timeout, Scheme: scheme, Host: host, NoExample: noexample, API: design.Design}
    67  
    68  	return g.Generate()
    69  }
    70  
    71  // Generate produces the skeleton main.
    72  func (g *Generator) Generate() (_ []string, err error) {
    73  	if g.API == nil {
    74  		return nil, fmt.Errorf("missing API definition, make sure design is properly initialized")
    75  	}
    76  
    77  	go utils.Catch(nil, func() { g.Cleanup() })
    78  
    79  	defer func() {
    80  		if err != nil {
    81  			g.Cleanup()
    82  		}
    83  	}()
    84  
    85  	if g.Timeout == 0 {
    86  		g.Timeout = 20 * time.Second
    87  	}
    88  	if g.Scheme == "" && len(g.API.Schemes) > 0 {
    89  		g.Scheme = g.API.Schemes[0]
    90  	}
    91  	if g.Scheme == "" {
    92  		g.Scheme = "http"
    93  	}
    94  	if g.Host == "" {
    95  		g.Host = g.API.Host
    96  	}
    97  	if g.Host == "" {
    98  		return nil, fmt.Errorf("missing host value, set it with --host")
    99  	}
   100  
   101  	g.OutDir = filepath.Join(g.OutDir, "js")
   102  	if err := os.RemoveAll(g.OutDir); err != nil {
   103  		return nil, err
   104  	}
   105  	if err := os.MkdirAll(g.OutDir, 0755); err != nil {
   106  		return nil, err
   107  	}
   108  	g.genfiles = append(g.genfiles, g.OutDir)
   109  
   110  	// Generate client.js
   111  	exampleAction, err := g.generateJS(filepath.Join(g.OutDir, "client.js"))
   112  	if err != nil {
   113  		return
   114  	}
   115  
   116  	// Generate axios.html
   117  	if err = g.generateAxiosJS(); err != nil {
   118  		return
   119  	}
   120  
   121  	if exampleAction != nil && !g.NoExample {
   122  		// Generate index.html
   123  		if err = g.generateIndexHTML(filepath.Join(g.OutDir, "index.html"), exampleAction); err != nil {
   124  			return
   125  		}
   126  
   127  		// Generate example
   128  		if err = g.generateExample(); err != nil {
   129  			return
   130  		}
   131  	}
   132  
   133  	return g.genfiles, nil
   134  }
   135  
   136  func (g *Generator) generateJS(jsFile string) (_ *design.ActionDefinition, err error) {
   137  	file, err := codegen.SourceFileFor(jsFile)
   138  	if err != nil {
   139  		return
   140  	}
   141  	defer file.Close()
   142  	g.genfiles = append(g.genfiles, jsFile)
   143  
   144  	data := map[string]interface{}{
   145  		"API":     g.API,
   146  		"Host":    g.Host,
   147  		"Scheme":  g.Scheme,
   148  		"Timeout": int64(g.Timeout / time.Millisecond),
   149  	}
   150  	if err = file.ExecuteTemplate("module", moduleT, nil, data); err != nil {
   151  		return
   152  	}
   153  
   154  	actions := make(map[string][]*design.ActionDefinition)
   155  	g.API.IterateResources(func(res *design.ResourceDefinition) error {
   156  		return res.IterateActions(func(action *design.ActionDefinition) error {
   157  			if as, ok := actions[action.Name]; ok {
   158  				actions[action.Name] = append(as, action)
   159  			} else {
   160  				actions[action.Name] = []*design.ActionDefinition{action}
   161  			}
   162  			return nil
   163  		})
   164  	})
   165  
   166  	var exampleAction *design.ActionDefinition
   167  	keys := []string{}
   168  	for n := range actions {
   169  		keys = append(keys, n)
   170  	}
   171  	sort.Strings(keys)
   172  	for _, n := range keys {
   173  		for _, a := range actions[n] {
   174  			if exampleAction == nil && a.Routes[0].Verb == "GET" {
   175  				exampleAction = a
   176  			}
   177  			data := map[string]interface{}{"Action": a}
   178  			funcs := template.FuncMap{"params": params}
   179  			if err = file.ExecuteTemplate("jsFuncs", jsFuncsT, funcs, data); err != nil {
   180  				return
   181  			}
   182  		}
   183  	}
   184  
   185  	_, err = file.Write([]byte(moduleTend))
   186  	return exampleAction, err
   187  }
   188  
   189  func (g *Generator) generateIndexHTML(htmlFile string, exampleAction *design.ActionDefinition) error {
   190  	file, err := codegen.SourceFileFor(htmlFile)
   191  	if err != nil {
   192  		return err
   193  	}
   194  	defer file.Close()
   195  	g.genfiles = append(g.genfiles, htmlFile)
   196  
   197  	argNames := params(exampleAction)
   198  	var args string
   199  	if len(argNames) > 0 {
   200  		query := exampleAction.QueryParams.Type.ToObject()
   201  		argValues := make([]string, len(argNames))
   202  		for i, n := range argNames {
   203  			ex := query[n].GenerateExample(g.API.RandomGenerator(), nil)
   204  			argValues[i] = fmt.Sprintf("%v", ex)
   205  		}
   206  		args = strings.Join(argValues, ", ")
   207  	}
   208  	examplePath := exampleAction.Routes[0].FullPath()
   209  	pathParams := exampleAction.Routes[0].Params()
   210  	if len(pathParams) > 0 {
   211  		pathVars := exampleAction.AllParams().Type.ToObject()
   212  		pathValues := make([]interface{}, len(pathParams))
   213  		for i, n := range pathParams {
   214  			ex := pathVars[n].GenerateExample(g.API.RandomGenerator(), nil)
   215  			pathValues[i] = ex
   216  		}
   217  		format := design.WildcardRegex.ReplaceAllLiteralString(examplePath, "/%v")
   218  		examplePath = fmt.Sprintf(format, pathValues...)
   219  	}
   220  	if len(argNames) > 0 {
   221  		args = ", " + args
   222  	}
   223  	exampleFunc := fmt.Sprintf(
   224  		`%s%s ("%s"%s)`,
   225  		exampleAction.Name,
   226  		strings.Title(exampleAction.Parent.Name),
   227  		examplePath,
   228  		args,
   229  	)
   230  	data := map[string]interface{}{
   231  		"API":         g.API,
   232  		"ExampleFunc": exampleFunc,
   233  	}
   234  
   235  	return file.ExecuteTemplate("exampleHTML", exampleT, nil, data)
   236  }
   237  
   238  func (g *Generator) generateAxiosJS() error {
   239  	filePath := filepath.Join(g.OutDir, "axios.min.js")
   240  	if err := ioutil.WriteFile(filePath, []byte(axios), 0644); err != nil {
   241  		return err
   242  	}
   243  	g.genfiles = append(g.genfiles, filePath)
   244  
   245  	return nil
   246  }
   247  
   248  func (g *Generator) generateExample() error {
   249  	controllerFile := filepath.Join(g.OutDir, "example.go")
   250  	file, err := codegen.SourceFileFor(controllerFile)
   251  	if err != nil {
   252  		return err
   253  	}
   254  	defer func() {
   255  		file.Close()
   256  		if err == nil {
   257  			err = file.FormatCode()
   258  		}
   259  	}()
   260  	imports := []*codegen.ImportSpec{
   261  		codegen.SimpleImport("net/http"),
   262  		codegen.SimpleImport("github.com/dimfeld/httptreemux"),
   263  		codegen.SimpleImport("github.com/goadesign/goa"),
   264  	}
   265  	if err := file.WriteHeader(fmt.Sprintf("%s JavaScript Client Example", g.API.Name), "js", imports); err != nil {
   266  		return err
   267  	}
   268  	g.genfiles = append(g.genfiles, controllerFile)
   269  
   270  	data := map[string]interface{}{"ServeDir": g.OutDir}
   271  	return file.ExecuteTemplate("examples", exampleCtrlT, nil, data)
   272  }
   273  
   274  // Cleanup removes all the files generated by this generator during the last invokation of Generate.
   275  func (g *Generator) Cleanup() {
   276  	for _, f := range g.genfiles {
   277  		os.Remove(f)
   278  	}
   279  	g.genfiles = nil
   280  }
   281  
   282  func params(action *design.ActionDefinition) []string {
   283  	if action.QueryParams == nil {
   284  		return nil
   285  	}
   286  	params := make([]string, len(action.QueryParams.Type.ToObject()))
   287  	i := 0
   288  	for n := range action.QueryParams.Type.ToObject() {
   289  		params[i] = n
   290  		i++
   291  	}
   292  	sort.Strings(params)
   293  	return params
   294  }
   295  
   296  const moduleT = `// This module exports functions that give access to the {{.API.Name}} API hosted at {{.API.Host}}.
   297  // It uses the axios javascript library for making the actual HTTP requests.
   298  define(['axios'] , function (axios) {
   299    function merge(obj1, obj2) {
   300      var obj3 = {};
   301      for (var attrname in obj1) { obj3[attrname] = obj1[attrname]; }
   302      for (var attrname in obj2) { obj3[attrname] = obj2[attrname]; }
   303      return obj3;
   304    }
   305  
   306    return function (scheme, host, timeout) {
   307      scheme = scheme || '{{.Scheme}}';
   308      host = host || '{{.Host}}';
   309      timeout = timeout || {{.Timeout}};
   310  
   311      // Client is the object returned by this module.
   312      var client = axios;
   313  
   314      // URL prefix for all API requests.
   315      var urlPrefix = scheme + '://' + host;
   316  `
   317  
   318  const moduleTend = `  return client;
   319    };
   320  });
   321  `
   322  
   323  const jsFuncsT = `{{$params := params .Action}}
   324    {{$name := printf "%s%s" .Action.Name (title .Action.Parent.Name)}}// {{if .Action.Description}}{{.Action.Description}}{{else}}{{$name}} calls the {{.Action.Name}} action of the {{.Action.Parent.Name}} resource.{{end}}
   325    // path is the request path, the format is "{{(index .Action.Routes 0).FullPath}}"
   326    {{if .Action.Payload}}// data contains the action payload (request body)
   327    {{end}}{{if $params}}// {{join $params ", "}} {{if gt (len $params) 1}}are{{else}}is{{end}} used to build the request query string.
   328    {{end}}// config is an optional object to be merged into the config built by the function prior to making the request.
   329    // The content of the config object is described here: https://github.com/mzabriskie/axios#request-api
   330    // This function returns a promise which raises an error if the HTTP response is a 4xx or 5xx.
   331    client.{{$name}} = function (path{{if .Action.Payload}}, data{{end}}{{if $params}}, {{join $params ", "}}{{end}}, config) {
   332      var cfg = {
   333        timeout: timeout,
   334        url: urlPrefix + path,
   335        method: '{{toLower (index .Action.Routes 0).Verb}}',
   336  {{if $params}}      params: {
   337  {{range $index, $param := $params}}{{if $index}},
   338  {{end}}        {{$param}}: {{$param}}{{end}}
   339        },
   340  {{end}}{{if .Action.Payload}}    data: data,
   341  {{end}}      responseType: 'json'
   342      };
   343      if (config) {
   344        cfg = merge(cfg, config);
   345      }
   346      return client(cfg);
   347    }
   348  `
   349  
   350  const exampleT = `<!doctype html>
   351  <html>
   352    <head>
   353      <title>goa JavaScript client loader</title>
   354    </head>
   355    <body>
   356      <h1>{{.API.Name}} Client Test</h1>
   357      <div id="response"></div>
   358      <script src="https://cdnjs.cloudflare.com/ajax/libs/require.js/2.1.16/require.min.js"></script>
   359      <script>
   360        requirejs.config({
   361          paths: {
   362            axios: '/js/axios.min',
   363            client: '/js/client'
   364          }
   365        });
   366        requirejs(['client'], function (client) {
   367          client().{{.ExampleFunc}}
   368            .then(function (resp) {
   369              document.getElementById('response').innerHTML = resp.statusText;
   370            })
   371            .catch(function (resp) {
   372              document.getElementById('response').innerHTML = resp.statusText;
   373            });
   374        });
   375      </script>
   376    </body>
   377  </html>
   378  `
   379  
   380  const exampleCtrlT = `// MountController mounts the JavaScript example controller under "/js".
   381  // This is just an example, not the best way to do this. A better way would be to specify a file
   382  // server using the Files DSL in the design.
   383  // Use --noexample to prevent this file from being generated.
   384  func MountController(service *goa.Service) {
   385  	// Serve static files under js
   386  	service.ServeFiles("/js/*filepath", {{printf "%q" .ServeDir}})
   387  	service.LogInfo("mount", "ctrl", "JS", "action", "ServeFiles", "route", "GET /js/*")
   388  }
   389  `
   390  
   391  const axios = `/* axios v0.7.0 | (c) 2015 by Matt Zabriskie */
   392  !function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.axios=t():e.axios=t()}(this,function(){return function(e){function t(r){if(n[r])return n[r].exports;var o=n[r]={exports:{},id:r,loaded:!1};return e[r].call(o.exports,o,o.exports,t),o.loaded=!0,o.exports}var n={};return t.m=e,t.c=n,t.p="",t(0)}([function(e,t,n){e.exports=n(1)},function(e,t,n){"use strict";var r=n(2),o=n(3),i=n(4),s=n(12),u=e.exports=function(e){"string"==typeof e&&(e=o.merge({url:arguments[0]},arguments[1])),e=o.merge({method:"get",headers:{},timeout:r.timeout,transformRequest:r.transformRequest,transformResponse:r.transformResponse},e),e.withCredentials=e.withCredentials||r.withCredentials;var t=[i,void 0],n=Promise.resolve(e);for(u.interceptors.request.forEach(function(e){t.unshift(e.fulfilled,e.rejected)}),u.interceptors.response.forEach(function(e){t.push(e.fulfilled,e.rejected)});t.length;)n=n.then(t.shift(),t.shift());return n};u.defaults=r,u.all=function(e){return Promise.all(e)},u.spread=n(13),u.interceptors={request:new s,response:new s},function(){function e(){o.forEach(arguments,function(e){u[e]=function(t,n){return u(o.merge(n||{},{method:e,url:t}))}})}function t(){o.forEach(arguments,function(e){u[e]=function(t,n,r){return u(o.merge(r||{},{method:e,url:t,data:n}))}})}e("delete","get","head"),t("post","put","patch")}()},function(e,t,n){"use strict";var r=n(3),o=/^\)\]\}',?\n/,i={"Content-Type":"application/x-www-form-urlencoded"};e.exports={transformRequest:[function(e,t){return r.isFormData(e)?e:r.isArrayBuffer(e)?e:r.isArrayBufferView(e)?e.buffer:!r.isObject(e)||r.isFile(e)||r.isBlob(e)?e:(r.isUndefined(t)||(r.forEach(t,function(e,n){"content-type"===n.toLowerCase()&&(t["Content-Type"]=e)}),r.isUndefined(t["Content-Type"])&&(t["Content-Type"]="application/json")),JSON.stringify(e))}],transformResponse:[function(e){if("string"==typeof e){e=e.replace(o,"");try{e=JSON.parse(e)}catch(t){}}return e}],headers:{common:{Accept:"application/json, text/plain, */*"},patch:r.merge(i),post:r.merge(i),put:r.merge(i)},timeout:0,xsrfCookieName:"XSRF-TOKEN",xsrfHeaderName:"X-XSRF-TOKEN"}},function(e,t){"use strict";function n(e){return"[object Array]"===v.call(e)}function r(e){return"[object ArrayBuffer]"===v.call(e)}function o(e){return"[object FormData]"===v.call(e)}function i(e){return"undefined"!=typeof ArrayBuffer&&ArrayBuffer.isView?ArrayBuffer.isView(e):e&&e.buffer&&e.buffer instanceof ArrayBuffer}function s(e){return"string"==typeof e}function u(e){return"number"==typeof e}function a(e){return"undefined"==typeof e}function f(e){return null!==e&&"object"==typeof e}function c(e){return"[object Date]"===v.call(e)}function p(e){return"[object File]"===v.call(e)}function l(e){return"[object Blob]"===v.call(e)}function d(e){return e.replace(/^\s*/,"").replace(/\s*$/,"")}function h(e){return"[object Arguments]"===v.call(e)}function m(){return"undefined"!=typeof window&&"undefined"!=typeof document&&"function"==typeof document.createElement}function y(e,t){if(null!==e&&"undefined"!=typeof e){var r=n(e)||h(e);if("object"==typeof e||r||(e=[e]),r)for(var o=0,i=e.length;i>o;o++)t.call(null,e[o],o,e);else for(var s in e)e.hasOwnProperty(s)&&t.call(null,e[s],s,e)}}function g(){var e={};return y(arguments,function(t){y(t,function(t,n){e[n]=t})}),e}var v=Object.prototype.toString;e.exports={isArray:n,isArrayBuffer:r,isFormData:o,isArrayBufferView:i,isString:s,isNumber:u,isObject:f,isUndefined:a,isDate:c,isFile:p,isBlob:l,isStandardBrowserEnv:m,forEach:y,merge:g,trim:d}},function(e,t,n){(function(t){"use strict";e.exports=function(e){return new Promise(function(r,o){try{"undefined"!=typeof XMLHttpRequest||"undefined"!=typeof ActiveXObject?n(6)(r,o,e):"undefined"!=typeof t&&n(6)(r,o,e)}catch(i){o(i)}})}}).call(t,n(5))},function(e,t){function n(){f=!1,s.length?a=s.concat(a):c=-1,a.length&&r()}function r(){if(!f){var e=setTimeout(n);f=!0;for(var t=a.length;t;){for(s=a,a=[];++c<t;)s&&s[c].run();c=-1,t=a.length}s=null,f=!1,clearTimeout(e)}}function o(e,t){this.fun=e,this.array=t}function i(){}var s,u=e.exports={},a=[],f=!1,c=-1;u.nextTick=function(e){var t=new Array(arguments.length-1);if(arguments.length>1)for(var n=1;n<arguments.length;n++)t[n-1]=arguments[n];a.push(new o(e,t)),1!==a.length||f||setTimeout(r,0)},o.prototype.run=function(){this.fun.apply(null,this.array)},u.title="browser",u.browser=!0,u.env={},u.argv=[],u.version="",u.versions={},u.on=i,u.addListener=i,u.once=i,u.off=i,u.removeListener=i,u.removeAllListeners=i,u.emit=i,u.binding=function(e){throw new Error("process.binding is not supported")},u.cwd=function(){return"/"},u.chdir=function(e){throw new Error("process.chdir is not supported")},u.umask=function(){return 0}},function(e,t,n){"use strict";var r=n(2),o=n(3),i=n(7),s=n(8),u=n(9);e.exports=function(e,t,a){var f=u(a.data,a.headers,a.transformRequest),c=o.merge(r.headers.common,r.headers[a.method]||{},a.headers||{});o.isFormData(f)&&delete c["Content-Type"];var p=new(XMLHttpRequest||ActiveXObject)("Microsoft.XMLHTTP");if(p.open(a.method.toUpperCase(),i(a.url,a.params),!0),p.timeout=a.timeout,p.onreadystatechange=function(){if(p&&4===p.readyState){var n=s(p.getAllResponseHeaders()),r=-1!==["text",""].indexOf(a.responseType||"")?p.responseText:p.response,o={data:u(r,n,a.transformResponse),status:p.status,statusText:p.statusText,headers:n,config:a};(p.status>=200&&p.status<300?e:t)(o),p=null}},o.isStandardBrowserEnv()){var l=n(10),d=n(11),h=d(a.url)?l.read(a.xsrfCookieName||r.xsrfCookieName):void 0;h&&(c[a.xsrfHeaderName||r.xsrfHeaderName]=h)}if(o.forEach(c,function(e,t){f||"content-type"!==t.toLowerCase()?p.setRequestHeader(t,e):delete c[t]}),a.withCredentials&&(p.withCredentials=!0),a.responseType)try{p.responseType=a.responseType}catch(m){if("json"!==p.responseType)throw m}o.isArrayBuffer(f)&&(f=new DataView(f)),p.send(f)}},function(e,t,n){"use strict";function r(e){return encodeURIComponent(e).replace(/%40/gi,"@").replace(/%3A/gi,":").replace(/%24/g,"$").replace(/%2C/gi,",").replace(/%20/g,"+").replace(/%5B/gi,"[").replace(/%5D/gi,"]")}var o=n(3);e.exports=function(e,t){if(!t)return e;var n=[];return o.forEach(t,function(e,t){null!==e&&"undefined"!=typeof e&&(o.isArray(e)&&(t+="[]"),o.isArray(e)||(e=[e]),o.forEach(e,function(e){o.isDate(e)?e=e.toISOString():o.isObject(e)&&(e=JSON.stringify(e)),n.push(r(t)+"="+r(e))}))}),n.length>0&&(e+=(-1===e.indexOf("?")?"?":"&")+n.join("&")),e}},function(e,t,n){"use strict";var r=n(3);e.exports=function(e){var t,n,o,i={};return e?(r.forEach(e.split("\n"),function(e){o=e.indexOf(":"),t=r.trim(e.substr(0,o)).toLowerCase(),n=r.trim(e.substr(o+1)),t&&(i[t]=i[t]?i[t]+", "+n:n)}),i):i}},function(e,t,n){"use strict";var r=n(3);e.exports=function(e,t,n){return r.forEach(n,function(n){e=n(e,t)}),e}},function(e,t,n){"use strict";var r=n(3);e.exports={write:function(e,t,n,o,i,s){var u=[];u.push(e+"="+encodeURIComponent(t)),r.isNumber(n)&&u.push("expires="+new Date(n).toGMTString()),r.isString(o)&&u.push("path="+o),r.isString(i)&&u.push("domain="+i),s===!0&&u.push("secure"),document.cookie=u.join("; ")},read:function(e){var t=document.cookie.match(new RegExp("(^|;\\s*)("+e+")=([^;]*)"));return t?decodeURIComponent(t[3]):null},remove:function(e){this.write(e,"",Date.now()-864e5)}}},function(e,t,n){"use strict";function r(e){var t=e;return s&&(u.setAttribute("href",t),t=u.href),u.setAttribute("href",t),{href:u.href,protocol:u.protocol?u.protocol.replace(/:$/,""):"",host:u.host,search:u.search?u.search.replace(/^\?/,""):"",hash:u.hash?u.hash.replace(/^#/,""):"",hostname:u.hostname,port:u.port,pathname:"/"===u.pathname.charAt(0)?u.pathname:"/"+u.pathname}}var o,i=n(3),s=/(msie|trident)/i.test(navigator.userAgent),u=document.createElement("a");o=r(window.location.href),e.exports=function(e){var t=i.isString(e)?r(e):e;return t.protocol===o.protocol&&t.host===o.host}},function(e,t,n){"use strict";function r(){this.handlers=[]}var o=n(3);r.prototype.use=function(e,t){return this.handlers.push({fulfilled:e,rejected:t}),this.handlers.length-1},r.prototype.eject=function(e){this.handlers[e]&&(this.handlers[e]=null)},r.prototype.forEach=function(e){o.forEach(this.handlers,function(t){null!==t&&e(t)})},e.exports=r},function(e,t){"use strict";e.exports=function(e){return function(t){return e.apply(null,t)}}}])});`