├── .eslintignore ├── .eslintrc.json ├── .gitattributes ├── .github ├── dependabot.yml └── workflows │ └── test.yml ├── .gitignore ├── .prettierignore ├── .prettierrc.json ├── Dockerfile ├── LICENSE ├── README.md ├── __tests__ ├── event.json └── setup.test.ts ├── action.yml ├── dist ├── index.js ├── index.js.map ├── licenses.txt └── sourcemap-register.js ├── jest.config.js ├── package-lock.json ├── package.json ├── src ├── handler.ts ├── install.ts ├── main.ts ├── setup-waypoint.ts └── setup.ts ├── test-html └── index.html ├── tsconfig.json └── waypoint.hcl /.eslintignore: -------------------------------------------------------------------------------- 1 | dist/ 2 | lib/ 3 | node_modules/ -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": ["jest", "@typescript-eslint"], 3 | "extends": ["plugin:github/recommended"], 4 | "parser": "@typescript-eslint/parser", 5 | "parserOptions": { 6 | "ecmaVersion": 9, 7 | "sourceType": "module", 8 | "project": "./tsconfig.json" 9 | }, 10 | "rules": { 11 | "eslint-comments/no-use": "off", 12 | "import/no-namespace": "off", 13 | "no-unused-vars": "off", 14 | "@typescript-eslint/no-unused-vars": "off", 15 | "@typescript-eslint/explicit-member-accessibility": ["error", { "accessibility": "no-public" }], 16 | "@typescript-eslint/no-require-imports": "error", 17 | "@typescript-eslint/array-type": "error", 18 | "@typescript-eslint/await-thenable": "error", 19 | "@typescript-eslint/ban-ts-comment": "error", 20 | "camelcase": "off", 21 | "@typescript-eslint/consistent-type-assertions": "error", 22 | "@typescript-eslint/explicit-function-return-type": ["error", { "allowExpressions": true }], 23 | "@typescript-eslint/func-call-spacing": ["error", "never"], 24 | "@typescript-eslint/no-array-constructor": "error", 25 | "@typescript-eslint/no-empty-interface": "error", 26 | "@typescript-eslint/no-explicit-any": "off", 27 | "@typescript-eslint/no-extraneous-class": "error", 28 | "@typescript-eslint/no-for-in-array": "error", 29 | "@typescript-eslint/no-inferrable-types": "error", 30 | "@typescript-eslint/no-misused-new": "error", 31 | "@typescript-eslint/no-namespace": "error", 32 | "@typescript-eslint/no-non-null-assertion": "warn", 33 | "@typescript-eslint/no-unnecessary-qualifier": "error", 34 | "@typescript-eslint/no-unnecessary-type-assertion": "error", 35 | "@typescript-eslint/no-useless-constructor": "error", 36 | "@typescript-eslint/no-var-requires": "error", 37 | "@typescript-eslint/prefer-for-of": "warn", 38 | "@typescript-eslint/prefer-function-type": "warn", 39 | "@typescript-eslint/prefer-includes": "error", 40 | "@typescript-eslint/prefer-string-starts-ends-with": "error", 41 | "@typescript-eslint/promise-function-async": "error", 42 | "@typescript-eslint/require-array-sort-compare": "error", 43 | "@typescript-eslint/restrict-plus-operands": "error", 44 | "@typescript-eslint/type-annotation-spacing": "error", 45 | "@typescript-eslint/unbound-method": "error" 46 | }, 47 | "env": { 48 | "node": true, 49 | "es6": true, 50 | "jest/globals": true 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | dist/** -diff linguist-generated=true -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | # Enable version updates for npm 4 | - package-ecosystem: 'npm' 5 | # Look for `package.json` and `lock` files in the `root` directory 6 | directory: '/' 7 | # Check the npm registry for updates every day (weekdays) 8 | schedule: 9 | interval: 'daily' 10 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: 'deploy' 2 | on: push 3 | 4 | jobs: 5 | test: 6 | runs-on: ubuntu-latest 7 | steps: 8 | - uses: actions/checkout@v2 9 | - run: | 10 | npm install 11 | - run: | 12 | npm run all 13 | - uses: ./ 14 | name: Setup 15 | with: 16 | version: '0.0.1-beta1' 17 | github_token: ${{ secrets.GITHUB_TOKEN }} 18 | waypoint_server_address: '2.tcp.ngrok.io:17860' 19 | waypoint_server_ui: 'https://localhost:9702' 20 | waypoint_server_token: ${{ secrets.WAYPOINT_SERVER_TOKEN }} 21 | - uses: ./ 22 | name: Build 23 | with: 24 | operation: build 25 | version: '0.0.1-beta1' 26 | workspace: default 27 | - uses: ./ 28 | name: Deploy 29 | with: 30 | operation: deploy 31 | version: '0.0.1-beta1' 32 | workspace: default 33 | - uses: ./ 34 | name: Release 35 | if: ${{ github.ref == 'refs/heads/master' }} 36 | with: 37 | operation: release 38 | version: '0.0.1-beta1' 39 | workspace: default 40 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Dependency directory 2 | node_modules 3 | 4 | # Rest pulled from https://github.com/github/gitignore/blob/master/Node.gitignore 5 | # Logs 6 | logs 7 | *.log 8 | npm-debug.log* 9 | yarn-debug.log* 10 | yarn-error.log* 11 | lerna-debug.log* 12 | 13 | # Diagnostic reports (https://nodejs.org/api/report.html) 14 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 15 | 16 | # Runtime data 17 | pids 18 | *.pid 19 | *.seed 20 | *.pid.lock 21 | 22 | # Directory for instrumented libs generated by jscoverage/JSCover 23 | lib-cov 24 | 25 | # Coverage directory used by tools like istanbul 26 | coverage 27 | *.lcov 28 | 29 | # nyc test coverage 30 | .nyc_output 31 | 32 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 33 | .grunt 34 | 35 | # Bower dependency directory (https://bower.io/) 36 | bower_components 37 | 38 | # node-waf configuration 39 | .lock-wscript 40 | 41 | # Compiled binary addons (https://nodejs.org/api/addons.html) 42 | build/Release 43 | 44 | # Dependency directories 45 | jspm_packages/ 46 | 47 | # TypeScript v1 declaration files 48 | typings/ 49 | 50 | # TypeScript cache 51 | *.tsbuildinfo 52 | 53 | # Optional npm cache directory 54 | .npm 55 | 56 | # Optional eslint cache 57 | .eslintcache 58 | 59 | # Optional REPL history 60 | .node_repl_history 61 | 62 | # Output of 'npm pack' 63 | *.tgz 64 | 65 | # Yarn Integrity file 66 | .yarn-integrity 67 | 68 | # dotenv environment variables file 69 | .env 70 | .env.test 71 | 72 | # parcel-bundler cache (https://parceljs.org/) 73 | .cache 74 | 75 | # next.js build output 76 | .next 77 | 78 | # nuxt.js build output 79 | .nuxt 80 | 81 | # vuepress build output 82 | .vuepress/dist 83 | 84 | # Serverless directories 85 | .serverless/ 86 | 87 | # FuseBox cache 88 | .fusebox/ 89 | 90 | # DynamoDB Local files 91 | .dynamodb/ 92 | 93 | # OS metadata 94 | .DS_Store 95 | Thumbs.db 96 | 97 | # Ignore built ts files 98 | __tests__/runner/* 99 | lib/**/* -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | dist/ 2 | lib/ 3 | node_modules/ -------------------------------------------------------------------------------- /.prettierrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "singleQuote": true, 3 | "trailingComma": "es5", 4 | "printWidth": 110 5 | } 6 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | # This is for the test action 2 | FROM nginx 3 | COPY test-html /usr/share/nginx/html 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2020 HashiCorp, Inc. and contributors 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in 14 | all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # action-waypoint 2 | 3 | **Note: This is an experiment and isn't recommended for consistent usage. For anything beyond 4 | experimental, we recommend using [action-setup-waypoint](https://github.com/hashicorp/action-setup-waypoint).** 5 | 6 | This action provides an abstraction for working with Waypoint 7 | and the GitHub releases and commit statuses APIs. It is 8 | intended to be the easiest way to automatically deploy 9 | applications with GitHub and Waypoint, only requiring that 10 | you are running a Waypoint server and have configured 11 | actions as below. 12 | 13 | If you want to run the waypoint binary in actions 14 | directly, without automatic status and release annotations, 15 | see [action-setup-waypoint](https://github.com/hashicorp/action-setup-waypoint). 16 | 17 | ## Usage 18 | 19 | ```yaml 20 | steps: 21 | - uses: actions/checkout@v2 22 | - uses: hashicorp/action-waypoint 23 | name: Setup 24 | with: 25 | version: '0.0.1-beta1' 26 | github_token: ${{ secrets.GITHUB_TOKEN }} 27 | waypoint_server_address: 'waypoint.example.com:9701' 28 | waypoint_server_ui: 'https://waypoint.example.com:9702' 29 | waypoint_server_token: ${{ secrets.WAYPOINT_SERVER_TOKEN }} 30 | workspace: default 31 | - uses: hashicorp/action-waypoint 32 | name: Build 33 | with: 34 | operation: build 35 | version: '0.0.1-beta1' 36 | github_token: ${{ secrets.GITHUB_TOKEN }} 37 | workspace: default 38 | - uses: hashicorp/action-waypoint 39 | name: Deploy 40 | with: 41 | operation: deploy 42 | version: '0.0.1-beta1' 43 | github_token: ${{ secrets.GITHUB_TOKEN }} 44 | workspace: default 45 | - uses: hashicorp/action-waypoint 46 | name: Release 47 | if: ${{ github.ref == 'refs/heads/master' }} 48 | with: 49 | operation: release 50 | version: '0.0.1-beta1' 51 | github_token: ${{ secrets.GITHUB_TOKEN }} 52 | workspace: default 53 | ``` 54 | 55 | ## Inputs 56 | 57 | | Input | Description | Default | Required | 58 | | ------------------------- | -------------------------------------------------------------------------------- | -------------- | -------- | 59 | | `version` | The version of Waypoint to install | | ✔ | 60 | | `operation` | The Waypoint operation to run. Should be one of `build`, `deploy`, or `release`. | | ✔ | 61 | | `workspace` | The Waypoint workspace to create resources in | | ✔ | 62 | | `github_token` | The GitHub token for interactions with the GitHub API | Built in token | | 63 | | `waypoint_server_address` | The gRPC address of the Waypoint server (persisted for future steps) | | ✔ | 64 | | `waypoint_server_ui` | The HTTP address of the Waypoint server (persisted for future steps) | | ✔ | 65 | | `waypoint_server_token` | The Waypoint server token for authentication (persisted for future steps) | | ✔ | 66 | 67 | ## Development 68 | 69 | Install the dependencies 70 | 71 | ```bash 72 | $ npm install 73 | ``` 74 | 75 | Build the typescript and package it for distribution 76 | 77 | ```bash 78 | $ npm run build && npm run package 79 | ``` 80 | 81 | Run the tests 82 | 83 | ```bash 84 | $ npm test 85 | ... 86 | ``` 87 | -------------------------------------------------------------------------------- /__tests__/event.json: -------------------------------------------------------------------------------- 1 | { 2 | "ref": "refs/heads/master", 3 | "before": "1d42aab6ef030d484135ec6bcbf0b976079ab785", 4 | "after": "265283d6a318ff52e707dd80398ac80fd8343ac3", 5 | "repository": { 6 | "id": 295363678, 7 | "node_id": "MDEwOlJlcG9zaXRvcnkyOTUzNjM2Nzg=", 8 | "name": "action-waypoint", 9 | "full_name": "hashicorp/action-waypoint", 10 | "private": true, 11 | "owner": { 12 | "name": "hashicorp", 13 | "email": "hello@hashicorp.com", 14 | "login": "hashicorp", 15 | "id": 761456, 16 | "node_id": "MDEyOk9yZ2FuaXphdGlvbjc2MTQ1Ng==", 17 | "avatar_url": "https://avatars2.githubusercontent.com/u/761456?v=4", 18 | "gravatar_id": "", 19 | "url": "https://api.github.com/users/hashicorp", 20 | "html_url": "https://github.com/hashicorp", 21 | "followers_url": "https://api.github.com/users/hashicorp/followers", 22 | "following_url": "https://api.github.com/users/hashicorp/following{/other_user}", 23 | "gists_url": "https://api.github.com/users/hashicorp/gists{/gist_id}", 24 | "starred_url": "https://api.github.com/users/hashicorp/starred{/owner}{/repo}", 25 | "subscriptions_url": "https://api.github.com/users/hashicorp/subscriptions", 26 | "organizations_url": "https://api.github.com/users/hashicorp/orgs", 27 | "repos_url": "https://api.github.com/users/hashicorp/repos", 28 | "events_url": "https://api.github.com/users/hashicorp/events{/privacy}", 29 | "received_events_url": "https://api.github.com/users/hashicorp/received_events", 30 | "type": "Organization", 31 | "site_admin": false 32 | }, 33 | "html_url": "https://github.com/hashicorp/action-waypoint", 34 | "description": null, 35 | "fork": false, 36 | "url": "https://github.com/hashicorp/action-waypoint", 37 | "forks_url": "https://api.github.com/repos/hashicorp/action-waypoint/forks", 38 | "keys_url": "https://api.github.com/repos/hashicorp/action-waypoint/keys{/key_id}", 39 | "collaborators_url": "https://api.github.com/repos/hashicorp/action-waypoint/collaborators{/collaborator}", 40 | "teams_url": "https://api.github.com/repos/hashicorp/action-waypoint/teams", 41 | "hooks_url": "https://api.github.com/repos/hashicorp/action-waypoint/hooks", 42 | "issue_events_url": "https://api.github.com/repos/hashicorp/action-waypoint/issues/events{/number}", 43 | "events_url": "https://api.github.com/repos/hashicorp/action-waypoint/events", 44 | "assignees_url": "https://api.github.com/repos/hashicorp/action-waypoint/assignees{/user}", 45 | "branches_url": "https://api.github.com/repos/hashicorp/action-waypoint/branches{/branch}", 46 | "tags_url": "https://api.github.com/repos/hashicorp/action-waypoint/tags", 47 | "blobs_url": "https://api.github.com/repos/hashicorp/action-waypoint/git/blobs{/sha}", 48 | "git_tags_url": "https://api.github.com/repos/hashicorp/action-waypoint/git/tags{/sha}", 49 | "git_refs_url": "https://api.github.com/repos/hashicorp/action-waypoint/git/refs{/sha}", 50 | "trees_url": "https://api.github.com/repos/hashicorp/action-waypoint/git/trees{/sha}", 51 | "statuses_url": "https://api.github.com/repos/hashicorp/action-waypoint/statuses/{sha}", 52 | "languages_url": "https://api.github.com/repos/hashicorp/action-waypoint/languages", 53 | "stargazers_url": "https://api.github.com/repos/hashicorp/action-waypoint/stargazers", 54 | "contributors_url": "https://api.github.com/repos/hashicorp/action-waypoint/contributors", 55 | "subscribers_url": "https://api.github.com/repos/hashicorp/action-waypoint/subscribers", 56 | "subscription_url": "https://api.github.com/repos/hashicorp/action-waypoint/subscription", 57 | "commits_url": "https://api.github.com/repos/hashicorp/action-waypoint/commits{/sha}", 58 | "git_commits_url": "https://api.github.com/repos/hashicorp/action-waypoint/git/commits{/sha}", 59 | "comments_url": "https://api.github.com/repos/hashicorp/action-waypoint/comments{/number}", 60 | "issue_comment_url": "https://api.github.com/repos/hashicorp/action-waypoint/issues/comments{/number}", 61 | "contents_url": "https://api.github.com/repos/hashicorp/action-waypoint/contents/{+path}", 62 | "compare_url": "https://api.github.com/repos/hashicorp/action-waypoint/compare/{base}...{head}", 63 | "merges_url": "https://api.github.com/repos/hashicorp/action-waypoint/merges", 64 | "archive_url": "https://api.github.com/repos/hashicorp/action-waypoint/{archive_format}{/ref}", 65 | "downloads_url": "https://api.github.com/repos/hashicorp/action-waypoint/downloads", 66 | "issues_url": "https://api.github.com/repos/hashicorp/action-waypoint/issues{/number}", 67 | "pulls_url": "https://api.github.com/repos/hashicorp/action-waypoint/pulls{/number}", 68 | "milestones_url": "https://api.github.com/repos/hashicorp/action-waypoint/milestones{/number}", 69 | "notifications_url": "https://api.github.com/repos/hashicorp/action-waypoint/notifications{?since,all,participating}", 70 | "labels_url": "https://api.github.com/repos/hashicorp/action-waypoint/labels{/name}", 71 | "releases_url": "https://api.github.com/repos/hashicorp/action-waypoint/releases{/id}", 72 | "deployments_url": "https://api.github.com/repos/hashicorp/action-waypoint/deployments", 73 | "created_at": 1600074735, 74 | "updated_at": "2020-09-15T20:55:47Z", 75 | "pushed_at": 1600203457, 76 | "git_url": "git://github.com/hashicorp/action-waypoint.git", 77 | "ssh_url": "git@github.com:hashicorp/action-waypoint.git", 78 | "clone_url": "https://github.com/hashicorp/action-waypoint.git", 79 | "svn_url": "https://github.com/hashicorp/action-waypoint", 80 | "homepage": null, 81 | "size": 1456, 82 | "stargazers_count": 0, 83 | "watchers_count": 0, 84 | "language": "TypeScript", 85 | "has_issues": true, 86 | "has_projects": true, 87 | "has_downloads": true, 88 | "has_wiki": true, 89 | "has_pages": false, 90 | "forks_count": 0, 91 | "mirror_url": null, 92 | "archived": false, 93 | "disabled": false, 94 | "open_issues_count": 0, 95 | "license": { 96 | "key": "mit", 97 | "name": "MIT License", 98 | "spdx_id": "MIT", 99 | "url": "https://api.github.com/licenses/mit", 100 | "node_id": "MDc6TGljZW5zZTEz" 101 | }, 102 | "forks": 0, 103 | "open_issues": 0, 104 | "watchers": 0, 105 | "default_branch": "master", 106 | "stargazers": 0, 107 | "master_branch": "master", 108 | "organization": "hashicorp" 109 | }, 110 | "pusher": { 111 | "name": "pearkes", 112 | "email": "jackpearkes@gmail.com" 113 | }, 114 | "organization": { 115 | "login": "hashicorp", 116 | "id": 761456, 117 | "node_id": "MDEyOk9yZ2FuaXphdGlvbjc2MTQ1Ng==", 118 | "url": "https://api.github.com/orgs/hashicorp", 119 | "repos_url": "https://api.github.com/orgs/hashicorp/repos", 120 | "events_url": "https://api.github.com/orgs/hashicorp/events", 121 | "hooks_url": "https://api.github.com/orgs/hashicorp/hooks", 122 | "issues_url": "https://api.github.com/orgs/hashicorp/issues", 123 | "members_url": "https://api.github.com/orgs/hashicorp/members{/member}", 124 | "public_members_url": "https://api.github.com/orgs/hashicorp/public_members{/member}", 125 | "avatar_url": "https://avatars2.githubusercontent.com/u/761456?v=4", 126 | "description": "Consistent workflows to provision, secure, connect, and run any infrastructure for any application." 127 | }, 128 | "enterprise": { 129 | "id": 290, 130 | "slug": "hashicorp", 131 | "name": "HashiCorp", 132 | "node_id": "MDEwOkVudGVycHJpc2UyOTA=", 133 | "avatar_url": "https://avatars1.githubusercontent.com/b/290?v=4", 134 | "description": "HashiCorp GitHub Enterprise Cloud", 135 | "website_url": "https://hashicorp.com", 136 | "html_url": "https://github.com/enterprises/hashicorp", 137 | "created_at": "2019-06-17T02:38:16Z", 138 | "updated_at": "2020-07-15T22:02:20Z" 139 | }, 140 | "sender": { 141 | "login": "pearkes", 142 | "id": 846194, 143 | "node_id": "MDQ6VXNlcjg0NjE5NA==", 144 | "avatar_url": "https://avatars0.githubusercontent.com/u/846194?v=4", 145 | "gravatar_id": "", 146 | "url": "https://api.github.com/users/pearkes", 147 | "html_url": "https://github.com/pearkes", 148 | "followers_url": "https://api.github.com/users/pearkes/followers", 149 | "following_url": "https://api.github.com/users/pearkes/following{/other_user}", 150 | "gists_url": "https://api.github.com/users/pearkes/gists{/gist_id}", 151 | "starred_url": "https://api.github.com/users/pearkes/starred{/owner}{/repo}", 152 | "subscriptions_url": "https://api.github.com/users/pearkes/subscriptions", 153 | "organizations_url": "https://api.github.com/users/pearkes/orgs", 154 | "repos_url": "https://api.github.com/users/pearkes/repos", 155 | "events_url": "https://api.github.com/users/pearkes/events{/privacy}", 156 | "received_events_url": "https://api.github.com/users/pearkes/received_events", 157 | "type": "User", 158 | "site_admin": false 159 | }, 160 | "created": false, 161 | "deleted": false, 162 | "forced": true, 163 | "base_ref": null, 164 | "compare": "https://github.com/hashicorp/action-waypoint/compare/1d42aab6ef03...265283d6a318", 165 | "commits": [ 166 | { 167 | "id": "265283d6a318ff52e707dd80398ac80fd8343ac3", 168 | "tree_id": "54cdee29768a5a3ff58281e91098d3dbd6c8698a", 169 | "distinct": true, 170 | "message": "initial commit", 171 | "timestamp": "2020-09-15T13:57:24-07:00", 172 | "url": "https://github.com/hashicorp/action-waypoint/commit/265283d6a318ff52e707dd80398ac80fd8343ac3", 173 | "author": { 174 | "name": "Jack Pearkes", 175 | "email": "jackpearkes@gmail.com", 176 | "username": "pearkes" 177 | }, 178 | "committer": { 179 | "name": "Jack Pearkes", 180 | "email": "jackpearkes@gmail.com", 181 | "username": "pearkes" 182 | }, 183 | "added": [ 184 | ".eslintignore", 185 | ".eslintrc.json", 186 | ".gitattributes", 187 | ".github/dependabot.yml", 188 | ".github/workflows/test.yml", 189 | ".gitignore", 190 | ".prettierignore", 191 | ".prettierrc.json", 192 | "Dockerfile", 193 | "LICENSE", 194 | "README.md", 195 | "__tests__/event.json", 196 | "__tests__/metadata.json", 197 | "__tests__/product.zip", 198 | "__tests__/setup.test.ts", 199 | "action.yml", 200 | "dist/index.js", 201 | "dist/index.js.map", 202 | "dist/licenses.txt", 203 | "dist/sourcemap-register.js", 204 | "jest.config.js", 205 | "package-lock.json", 206 | "package.json", 207 | "src/handler.ts", 208 | "src/install.ts", 209 | "src/main.ts", 210 | "src/setup-waypoint.ts", 211 | "src/setup.ts", 212 | "test-html/index.html", 213 | "tsconfig.json", 214 | "waypoint.hcl" 215 | ], 216 | "removed": [], 217 | "modified": [] 218 | } 219 | ], 220 | "head_commit": { 221 | "id": "265283d6a318ff52e707dd80398ac80fd8343ac3", 222 | "tree_id": "54cdee29768a5a3ff58281e91098d3dbd6c8698a", 223 | "distinct": true, 224 | "message": "initial commit", 225 | "timestamp": "2020-09-15T13:57:24-07:00", 226 | "url": "https://github.com/hashicorp/action-waypoint/commit/265283d6a318ff52e707dd80398ac80fd8343ac3", 227 | "author": { 228 | "name": "Jack Pearkes", 229 | "email": "jackpearkes@gmail.com", 230 | "username": "pearkes" 231 | }, 232 | "committer": { 233 | "name": "Jack Pearkes", 234 | "email": "jackpearkes@gmail.com", 235 | "username": "pearkes" 236 | }, 237 | "added": [ 238 | ".eslintignore", 239 | ".eslintrc.json", 240 | ".gitattributes", 241 | ".github/dependabot.yml", 242 | ".github/workflows/test.yml", 243 | ".gitignore", 244 | ".prettierignore", 245 | ".prettierrc.json", 246 | "Dockerfile", 247 | "LICENSE", 248 | "README.md", 249 | "__tests__/event.json", 250 | "__tests__/metadata.json", 251 | "__tests__/product.zip", 252 | "__tests__/setup.test.ts", 253 | "action.yml", 254 | "dist/index.js", 255 | "dist/index.js.map", 256 | "dist/licenses.txt", 257 | "dist/sourcemap-register.js", 258 | "jest.config.js", 259 | "package-lock.json", 260 | "package.json", 261 | "src/handler.ts", 262 | "src/install.ts", 263 | "src/main.ts", 264 | "src/setup-waypoint.ts", 265 | "src/setup.ts", 266 | "test-html/index.html", 267 | "tsconfig.json", 268 | "waypoint.hcl" 269 | ], 270 | "removed": [], 271 | "modified": [] 272 | } 273 | } 274 | -------------------------------------------------------------------------------- /__tests__/setup.test.ts: -------------------------------------------------------------------------------- 1 | import io = require('@actions/io'); 2 | import fs = require('fs'); 3 | import os = require('os'); 4 | import path = require('path'); 5 | import nock from 'nock'; 6 | import { Ctx } from '../src/setup'; 7 | import * as core from '@actions/core'; 8 | 9 | describe('setup tests', () => { 10 | let inputs = {} as any; 11 | 12 | beforeAll(function () { 13 | // We don't want any real http requests in the tests 14 | // nock.disableNetConnect(); 15 | }); 16 | 17 | beforeEach(async function () { 18 | const inSpy = jest.spyOn(core, 'getInput'); 19 | inSpy.mockImplementation((name) => inputs[name]); 20 | }); 21 | 22 | afterEach(function () { 23 | jest.resetAllMocks(); 24 | jest.clearAllMocks(); 25 | }); 26 | 27 | afterAll(async function () {}); 28 | 29 | it('constructs a context', async () => { 30 | inputs['github_token'] = 'foobar'; 31 | 32 | new Ctx(); 33 | }); 34 | }); 35 | -------------------------------------------------------------------------------- /action.yml: -------------------------------------------------------------------------------- 1 | name: 'action-waypoint' 2 | description: 'Provide a description here' 3 | author: 'Your name or organization here' 4 | inputs: 5 | version: 6 | required: true 7 | description: 'The version of Waypoint to install' 8 | github_token: 9 | description: 'GitHub token' 10 | default: 'A GitHub token with permissions to update commit statuses and deployments' 11 | waypoint_server_token: 12 | description: 'The token for the Waypoint server' 13 | default: '' 14 | waypoint_server_address: 15 | description: 'The grpc address of the Waypoint server' 16 | default: '' 17 | waypoint_server_ui: 18 | description: 'The UI HTTP address of the Waypoint server' 19 | default: '' 20 | workspace: 21 | description: 'The Waypoint workspace' 22 | default: 'default' 23 | project: 24 | description: 'The Waypoint project' 25 | operation: 26 | description: 'input description here' 27 | runs: 28 | using: 'node12' 29 | main: 'dist/index.js' 30 | -------------------------------------------------------------------------------- /dist/sourcemap-register.js: -------------------------------------------------------------------------------- 1 | module.exports = 2 | /******/ (function(modules, runtime) { // webpackBootstrap 3 | /******/ "use strict"; 4 | /******/ // The module cache 5 | /******/ var installedModules = {}; 6 | /******/ 7 | /******/ // The require function 8 | /******/ function __webpack_require__(moduleId) { 9 | /******/ 10 | /******/ // Check if module is in cache 11 | /******/ if(installedModules[moduleId]) { 12 | /******/ return installedModules[moduleId].exports; 13 | /******/ } 14 | /******/ // Create a new module (and put it into the cache) 15 | /******/ var module = installedModules[moduleId] = { 16 | /******/ i: moduleId, 17 | /******/ l: false, 18 | /******/ exports: {} 19 | /******/ }; 20 | /******/ 21 | /******/ // Execute the module function 22 | /******/ var threw = true; 23 | /******/ try { 24 | /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); 25 | /******/ threw = false; 26 | /******/ } finally { 27 | /******/ if(threw) delete installedModules[moduleId]; 28 | /******/ } 29 | /******/ 30 | /******/ // Flag the module as loaded 31 | /******/ module.l = true; 32 | /******/ 33 | /******/ // Return the exports of the module 34 | /******/ return module.exports; 35 | /******/ } 36 | /******/ 37 | /******/ 38 | /******/ __webpack_require__.ab = __dirname + "/"; 39 | /******/ 40 | /******/ // the startup function 41 | /******/ function startup() { 42 | /******/ // Load entry module and return exports 43 | /******/ return __webpack_require__(645); 44 | /******/ }; 45 | /******/ 46 | /******/ // run startup 47 | /******/ return startup(); 48 | /******/ }) 49 | /************************************************************************/ 50 | /******/ ({ 51 | 52 | /***/ 164: 53 | /***/ (function(__unusedmodule, exports) { 54 | 55 | /* -*- Mode: js; js-indent-level: 2; -*- */ 56 | /* 57 | * Copyright 2011 Mozilla Foundation and contributors 58 | * Licensed under the New BSD license. See LICENSE or: 59 | * http://opensource.org/licenses/BSD-3-Clause 60 | */ 61 | 62 | exports.GREATEST_LOWER_BOUND = 1; 63 | exports.LEAST_UPPER_BOUND = 2; 64 | 65 | /** 66 | * Recursive implementation of binary search. 67 | * 68 | * @param aLow Indices here and lower do not contain the needle. 69 | * @param aHigh Indices here and higher do not contain the needle. 70 | * @param aNeedle The element being searched for. 71 | * @param aHaystack The non-empty array being searched. 72 | * @param aCompare Function which takes two elements and returns -1, 0, or 1. 73 | * @param aBias Either 'binarySearch.GREATEST_LOWER_BOUND' or 74 | * 'binarySearch.LEAST_UPPER_BOUND'. Specifies whether to return the 75 | * closest element that is smaller than or greater than the one we are 76 | * searching for, respectively, if the exact element cannot be found. 77 | */ 78 | function recursiveSearch(aLow, aHigh, aNeedle, aHaystack, aCompare, aBias) { 79 | // This function terminates when one of the following is true: 80 | // 81 | // 1. We find the exact element we are looking for. 82 | // 83 | // 2. We did not find the exact element, but we can return the index of 84 | // the next-closest element. 85 | // 86 | // 3. We did not find the exact element, and there is no next-closest 87 | // element than the one we are searching for, so we return -1. 88 | var mid = Math.floor((aHigh - aLow) / 2) + aLow; 89 | var cmp = aCompare(aNeedle, aHaystack[mid], true); 90 | if (cmp === 0) { 91 | // Found the element we are looking for. 92 | return mid; 93 | } 94 | else if (cmp > 0) { 95 | // Our needle is greater than aHaystack[mid]. 96 | if (aHigh - mid > 1) { 97 | // The element is in the upper half. 98 | return recursiveSearch(mid, aHigh, aNeedle, aHaystack, aCompare, aBias); 99 | } 100 | 101 | // The exact needle element was not found in this haystack. Determine if 102 | // we are in termination case (3) or (2) and return the appropriate thing. 103 | if (aBias == exports.LEAST_UPPER_BOUND) { 104 | return aHigh < aHaystack.length ? aHigh : -1; 105 | } else { 106 | return mid; 107 | } 108 | } 109 | else { 110 | // Our needle is less than aHaystack[mid]. 111 | if (mid - aLow > 1) { 112 | // The element is in the lower half. 113 | return recursiveSearch(aLow, mid, aNeedle, aHaystack, aCompare, aBias); 114 | } 115 | 116 | // we are in termination case (3) or (2) and return the appropriate thing. 117 | if (aBias == exports.LEAST_UPPER_BOUND) { 118 | return mid; 119 | } else { 120 | return aLow < 0 ? -1 : aLow; 121 | } 122 | } 123 | } 124 | 125 | /** 126 | * This is an implementation of binary search which will always try and return 127 | * the index of the closest element if there is no exact hit. This is because 128 | * mappings between original and generated line/col pairs are single points, 129 | * and there is an implicit region between each of them, so a miss just means 130 | * that you aren't on the very start of a region. 131 | * 132 | * @param aNeedle The element you are looking for. 133 | * @param aHaystack The array that is being searched. 134 | * @param aCompare A function which takes the needle and an element in the 135 | * array and returns -1, 0, or 1 depending on whether the needle is less 136 | * than, equal to, or greater than the element, respectively. 137 | * @param aBias Either 'binarySearch.GREATEST_LOWER_BOUND' or 138 | * 'binarySearch.LEAST_UPPER_BOUND'. Specifies whether to return the 139 | * closest element that is smaller than or greater than the one we are 140 | * searching for, respectively, if the exact element cannot be found. 141 | * Defaults to 'binarySearch.GREATEST_LOWER_BOUND'. 142 | */ 143 | exports.search = function search(aNeedle, aHaystack, aCompare, aBias) { 144 | if (aHaystack.length === 0) { 145 | return -1; 146 | } 147 | 148 | var index = recursiveSearch(-1, aHaystack.length, aNeedle, aHaystack, 149 | aCompare, aBias || exports.GREATEST_LOWER_BOUND); 150 | if (index < 0) { 151 | return -1; 152 | } 153 | 154 | // We have found either the exact element, or the next-closest element than 155 | // the one we are searching for. However, there may be more than one such 156 | // element. Make sure we always return the smallest of these. 157 | while (index - 1 >= 0) { 158 | if (aCompare(aHaystack[index], aHaystack[index - 1], true) !== 0) { 159 | break; 160 | } 161 | --index; 162 | } 163 | 164 | return index; 165 | }; 166 | 167 | 168 | /***/ }), 169 | 170 | /***/ 215: 171 | /***/ (function(__unusedmodule, exports, __webpack_require__) { 172 | 173 | /* -*- Mode: js; js-indent-level: 2; -*- */ 174 | /* 175 | * Copyright 2011 Mozilla Foundation and contributors 176 | * Licensed under the New BSD license. See LICENSE or: 177 | * http://opensource.org/licenses/BSD-3-Clause 178 | * 179 | * Based on the Base 64 VLQ implementation in Closure Compiler: 180 | * https://code.google.com/p/closure-compiler/source/browse/trunk/src/com/google/debugging/sourcemap/Base64VLQ.java 181 | * 182 | * Copyright 2011 The Closure Compiler Authors. All rights reserved. 183 | * Redistribution and use in source and binary forms, with or without 184 | * modification, are permitted provided that the following conditions are 185 | * met: 186 | * 187 | * * Redistributions of source code must retain the above copyright 188 | * notice, this list of conditions and the following disclaimer. 189 | * * Redistributions in binary form must reproduce the above 190 | * copyright notice, this list of conditions and the following 191 | * disclaimer in the documentation and/or other materials provided 192 | * with the distribution. 193 | * * Neither the name of Google Inc. nor the names of its 194 | * contributors may be used to endorse or promote products derived 195 | * from this software without specific prior written permission. 196 | * 197 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 198 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 199 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 200 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 201 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 202 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 203 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 204 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 205 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 206 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 207 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 208 | */ 209 | 210 | var base64 = __webpack_require__(537); 211 | 212 | // A single base 64 digit can contain 6 bits of data. For the base 64 variable 213 | // length quantities we use in the source map spec, the first bit is the sign, 214 | // the next four bits are the actual value, and the 6th bit is the 215 | // continuation bit. The continuation bit tells us whether there are more 216 | // digits in this value following this digit. 217 | // 218 | // Continuation 219 | // | Sign 220 | // | | 221 | // V V 222 | // 101011 223 | 224 | var VLQ_BASE_SHIFT = 5; 225 | 226 | // binary: 100000 227 | var VLQ_BASE = 1 << VLQ_BASE_SHIFT; 228 | 229 | // binary: 011111 230 | var VLQ_BASE_MASK = VLQ_BASE - 1; 231 | 232 | // binary: 100000 233 | var VLQ_CONTINUATION_BIT = VLQ_BASE; 234 | 235 | /** 236 | * Converts from a two-complement value to a value where the sign bit is 237 | * placed in the least significant bit. For example, as decimals: 238 | * 1 becomes 2 (10 binary), -1 becomes 3 (11 binary) 239 | * 2 becomes 4 (100 binary), -2 becomes 5 (101 binary) 240 | */ 241 | function toVLQSigned(aValue) { 242 | return aValue < 0 243 | ? ((-aValue) << 1) + 1 244 | : (aValue << 1) + 0; 245 | } 246 | 247 | /** 248 | * Converts to a two-complement value from a value where the sign bit is 249 | * placed in the least significant bit. For example, as decimals: 250 | * 2 (10 binary) becomes 1, 3 (11 binary) becomes -1 251 | * 4 (100 binary) becomes 2, 5 (101 binary) becomes -2 252 | */ 253 | function fromVLQSigned(aValue) { 254 | var isNegative = (aValue & 1) === 1; 255 | var shifted = aValue >> 1; 256 | return isNegative 257 | ? -shifted 258 | : shifted; 259 | } 260 | 261 | /** 262 | * Returns the base 64 VLQ encoded value. 263 | */ 264 | exports.encode = function base64VLQ_encode(aValue) { 265 | var encoded = ""; 266 | var digit; 267 | 268 | var vlq = toVLQSigned(aValue); 269 | 270 | do { 271 | digit = vlq & VLQ_BASE_MASK; 272 | vlq >>>= VLQ_BASE_SHIFT; 273 | if (vlq > 0) { 274 | // There are still more digits in this value, so we must make sure the 275 | // continuation bit is marked. 276 | digit |= VLQ_CONTINUATION_BIT; 277 | } 278 | encoded += base64.encode(digit); 279 | } while (vlq > 0); 280 | 281 | return encoded; 282 | }; 283 | 284 | /** 285 | * Decodes the next base 64 VLQ value from the given string and returns the 286 | * value and the rest of the string via the out parameter. 287 | */ 288 | exports.decode = function base64VLQ_decode(aStr, aIndex, aOutParam) { 289 | var strLen = aStr.length; 290 | var result = 0; 291 | var shift = 0; 292 | var continuation, digit; 293 | 294 | do { 295 | if (aIndex >= strLen) { 296 | throw new Error("Expected more digits in base 64 VLQ value."); 297 | } 298 | 299 | digit = base64.decode(aStr.charCodeAt(aIndex++)); 300 | if (digit === -1) { 301 | throw new Error("Invalid base64 digit: " + aStr.charAt(aIndex - 1)); 302 | } 303 | 304 | continuation = !!(digit & VLQ_CONTINUATION_BIT); 305 | digit &= VLQ_BASE_MASK; 306 | result = result + (digit << shift); 307 | shift += VLQ_BASE_SHIFT; 308 | } while (continuation); 309 | 310 | aOutParam.value = fromVLQSigned(result); 311 | aOutParam.rest = aIndex; 312 | }; 313 | 314 | 315 | /***/ }), 316 | 317 | /***/ 226: 318 | /***/ (function(__unusedmodule, exports) { 319 | 320 | /* -*- Mode: js; js-indent-level: 2; -*- */ 321 | /* 322 | * Copyright 2011 Mozilla Foundation and contributors 323 | * Licensed under the New BSD license. See LICENSE or: 324 | * http://opensource.org/licenses/BSD-3-Clause 325 | */ 326 | 327 | // It turns out that some (most?) JavaScript engines don't self-host 328 | // `Array.prototype.sort`. This makes sense because C++ will likely remain 329 | // faster than JS when doing raw CPU-intensive sorting. However, when using a 330 | // custom comparator function, calling back and forth between the VM's C++ and 331 | // JIT'd JS is rather slow *and* loses JIT type information, resulting in 332 | // worse generated code for the comparator function than would be optimal. In 333 | // fact, when sorting with a comparator, these costs outweigh the benefits of 334 | // sorting in C++. By using our own JS-implemented Quick Sort (below), we get 335 | // a ~3500ms mean speed-up in `bench/bench.html`. 336 | 337 | /** 338 | * Swap the elements indexed by `x` and `y` in the array `ary`. 339 | * 340 | * @param {Array} ary 341 | * The array. 342 | * @param {Number} x 343 | * The index of the first item. 344 | * @param {Number} y 345 | * The index of the second item. 346 | */ 347 | function swap(ary, x, y) { 348 | var temp = ary[x]; 349 | ary[x] = ary[y]; 350 | ary[y] = temp; 351 | } 352 | 353 | /** 354 | * Returns a random integer within the range `low .. high` inclusive. 355 | * 356 | * @param {Number} low 357 | * The lower bound on the range. 358 | * @param {Number} high 359 | * The upper bound on the range. 360 | */ 361 | function randomIntInRange(low, high) { 362 | return Math.round(low + (Math.random() * (high - low))); 363 | } 364 | 365 | /** 366 | * The Quick Sort algorithm. 367 | * 368 | * @param {Array} ary 369 | * An array to sort. 370 | * @param {function} comparator 371 | * Function to use to compare two items. 372 | * @param {Number} p 373 | * Start index of the array 374 | * @param {Number} r 375 | * End index of the array 376 | */ 377 | function doQuickSort(ary, comparator, p, r) { 378 | // If our lower bound is less than our upper bound, we (1) partition the 379 | // array into two pieces and (2) recurse on each half. If it is not, this is 380 | // the empty array and our base case. 381 | 382 | if (p < r) { 383 | // (1) Partitioning. 384 | // 385 | // The partitioning chooses a pivot between `p` and `r` and moves all 386 | // elements that are less than or equal to the pivot to the before it, and 387 | // all the elements that are greater than it after it. The effect is that 388 | // once partition is done, the pivot is in the exact place it will be when 389 | // the array is put in sorted order, and it will not need to be moved 390 | // again. This runs in O(n) time. 391 | 392 | // Always choose a random pivot so that an input array which is reverse 393 | // sorted does not cause O(n^2) running time. 394 | var pivotIndex = randomIntInRange(p, r); 395 | var i = p - 1; 396 | 397 | swap(ary, pivotIndex, r); 398 | var pivot = ary[r]; 399 | 400 | // Immediately after `j` is incremented in this loop, the following hold 401 | // true: 402 | // 403 | // * Every element in `ary[p .. i]` is less than or equal to the pivot. 404 | // 405 | // * Every element in `ary[i+1 .. j-1]` is greater than the pivot. 406 | for (var j = p; j < r; j++) { 407 | if (comparator(ary[j], pivot) <= 0) { 408 | i += 1; 409 | swap(ary, i, j); 410 | } 411 | } 412 | 413 | swap(ary, i + 1, j); 414 | var q = i + 1; 415 | 416 | // (2) Recurse on each half. 417 | 418 | doQuickSort(ary, comparator, p, q - 1); 419 | doQuickSort(ary, comparator, q + 1, r); 420 | } 421 | } 422 | 423 | /** 424 | * Sort the given array in-place with the given comparator function. 425 | * 426 | * @param {Array} ary 427 | * An array to sort. 428 | * @param {function} comparator 429 | * Function to use to compare two items. 430 | */ 431 | exports.quickSort = function (ary, comparator) { 432 | doQuickSort(ary, comparator, 0, ary.length - 1); 433 | }; 434 | 435 | 436 | /***/ }), 437 | 438 | /***/ 282: 439 | /***/ (function(module) { 440 | 441 | module.exports = require("module"); 442 | 443 | /***/ }), 444 | 445 | /***/ 284: 446 | /***/ (function(__unusedmodule, exports, __webpack_require__) { 447 | 448 | var SourceMapConsumer = __webpack_require__(596).SourceMapConsumer; 449 | var path = __webpack_require__(622); 450 | 451 | var fs; 452 | try { 453 | fs = __webpack_require__(747); 454 | if (!fs.existsSync || !fs.readFileSync) { 455 | // fs doesn't have all methods we need 456 | fs = null; 457 | } 458 | } catch (err) { 459 | /* nop */ 460 | } 461 | 462 | var bufferFrom = __webpack_require__(650); 463 | 464 | // Only install once if called multiple times 465 | var errorFormatterInstalled = false; 466 | var uncaughtShimInstalled = false; 467 | 468 | // If true, the caches are reset before a stack trace formatting operation 469 | var emptyCacheBetweenOperations = false; 470 | 471 | // Supports {browser, node, auto} 472 | var environment = "auto"; 473 | 474 | // Maps a file path to a string containing the file contents 475 | var fileContentsCache = {}; 476 | 477 | // Maps a file path to a source map for that file 478 | var sourceMapCache = {}; 479 | 480 | // Regex for detecting source maps 481 | var reSourceMap = /^data:application\/json[^,]+base64,/; 482 | 483 | // Priority list of retrieve handlers 484 | var retrieveFileHandlers = []; 485 | var retrieveMapHandlers = []; 486 | 487 | function isInBrowser() { 488 | if (environment === "browser") 489 | return true; 490 | if (environment === "node") 491 | return false; 492 | return ((typeof window !== 'undefined') && (typeof XMLHttpRequest === 'function') && !(window.require && window.module && window.process && window.process.type === "renderer")); 493 | } 494 | 495 | function hasGlobalProcessEventEmitter() { 496 | return ((typeof process === 'object') && (process !== null) && (typeof process.on === 'function')); 497 | } 498 | 499 | function handlerExec(list) { 500 | return function(arg) { 501 | for (var i = 0; i < list.length; i++) { 502 | var ret = list[i](arg); 503 | if (ret) { 504 | return ret; 505 | } 506 | } 507 | return null; 508 | }; 509 | } 510 | 511 | var retrieveFile = handlerExec(retrieveFileHandlers); 512 | 513 | retrieveFileHandlers.push(function(path) { 514 | // Trim the path to make sure there is no extra whitespace. 515 | path = path.trim(); 516 | if (/^file:/.test(path)) { 517 | // existsSync/readFileSync can't handle file protocol, but once stripped, it works 518 | path = path.replace(/file:\/\/\/(\w:)?/, function(protocol, drive) { 519 | return drive ? 520 | '' : // file:///C:/dir/file -> C:/dir/file 521 | '/'; // file:///root-dir/file -> /root-dir/file 522 | }); 523 | } 524 | if (path in fileContentsCache) { 525 | return fileContentsCache[path]; 526 | } 527 | 528 | var contents = ''; 529 | try { 530 | if (!fs) { 531 | // Use SJAX if we are in the browser 532 | var xhr = new XMLHttpRequest(); 533 | xhr.open('GET', path, /** async */ false); 534 | xhr.send(null); 535 | if (xhr.readyState === 4 && xhr.status === 200) { 536 | contents = xhr.responseText; 537 | } 538 | } else if (fs.existsSync(path)) { 539 | // Otherwise, use the filesystem 540 | contents = fs.readFileSync(path, 'utf8'); 541 | } 542 | } catch (er) { 543 | /* ignore any errors */ 544 | } 545 | 546 | return fileContentsCache[path] = contents; 547 | }); 548 | 549 | // Support URLs relative to a directory, but be careful about a protocol prefix 550 | // in case we are in the browser (i.e. directories may start with "http://" or "file:///") 551 | function supportRelativeURL(file, url) { 552 | if (!file) return url; 553 | var dir = path.dirname(file); 554 | var match = /^\w+:\/\/[^\/]*/.exec(dir); 555 | var protocol = match ? match[0] : ''; 556 | var startPath = dir.slice(protocol.length); 557 | if (protocol && /^\/\w\:/.test(startPath)) { 558 | // handle file:///C:/ paths 559 | protocol += '/'; 560 | return protocol + path.resolve(dir.slice(protocol.length), url).replace(/\\/g, '/'); 561 | } 562 | return protocol + path.resolve(dir.slice(protocol.length), url); 563 | } 564 | 565 | function retrieveSourceMapURL(source) { 566 | var fileData; 567 | 568 | if (isInBrowser()) { 569 | try { 570 | var xhr = new XMLHttpRequest(); 571 | xhr.open('GET', source, false); 572 | xhr.send(null); 573 | fileData = xhr.readyState === 4 ? xhr.responseText : null; 574 | 575 | // Support providing a sourceMappingURL via the SourceMap header 576 | var sourceMapHeader = xhr.getResponseHeader("SourceMap") || 577 | xhr.getResponseHeader("X-SourceMap"); 578 | if (sourceMapHeader) { 579 | return sourceMapHeader; 580 | } 581 | } catch (e) { 582 | } 583 | } 584 | 585 | // Get the URL of the source map 586 | fileData = retrieveFile(source); 587 | var re = /(?:\/\/[@#][ \t]+sourceMappingURL=([^\s'"]+?)[ \t]*$)|(?:\/\*[@#][ \t]+sourceMappingURL=([^\*]+?)[ \t]*(?:\*\/)[ \t]*$)/mg; 588 | // Keep executing the search to find the *last* sourceMappingURL to avoid 589 | // picking up sourceMappingURLs from comments, strings, etc. 590 | var lastMatch, match; 591 | while (match = re.exec(fileData)) lastMatch = match; 592 | if (!lastMatch) return null; 593 | return lastMatch[1]; 594 | }; 595 | 596 | // Can be overridden by the retrieveSourceMap option to install. Takes a 597 | // generated source filename; returns a {map, optional url} object, or null if 598 | // there is no source map. The map field may be either a string or the parsed 599 | // JSON object (ie, it must be a valid argument to the SourceMapConsumer 600 | // constructor). 601 | var retrieveSourceMap = handlerExec(retrieveMapHandlers); 602 | retrieveMapHandlers.push(function(source) { 603 | var sourceMappingURL = retrieveSourceMapURL(source); 604 | if (!sourceMappingURL) return null; 605 | 606 | // Read the contents of the source map 607 | var sourceMapData; 608 | if (reSourceMap.test(sourceMappingURL)) { 609 | // Support source map URL as a data url 610 | var rawData = sourceMappingURL.slice(sourceMappingURL.indexOf(',') + 1); 611 | sourceMapData = bufferFrom(rawData, "base64").toString(); 612 | sourceMappingURL = source; 613 | } else { 614 | // Support source map URLs relative to the source URL 615 | sourceMappingURL = supportRelativeURL(source, sourceMappingURL); 616 | sourceMapData = retrieveFile(sourceMappingURL); 617 | } 618 | 619 | if (!sourceMapData) { 620 | return null; 621 | } 622 | 623 | return { 624 | url: sourceMappingURL, 625 | map: sourceMapData 626 | }; 627 | }); 628 | 629 | function mapSourcePosition(position) { 630 | var sourceMap = sourceMapCache[position.source]; 631 | if (!sourceMap) { 632 | // Call the (overrideable) retrieveSourceMap function to get the source map. 633 | var urlAndMap = retrieveSourceMap(position.source); 634 | if (urlAndMap) { 635 | sourceMap = sourceMapCache[position.source] = { 636 | url: urlAndMap.url, 637 | map: new SourceMapConsumer(urlAndMap.map) 638 | }; 639 | 640 | // Load all sources stored inline with the source map into the file cache 641 | // to pretend like they are already loaded. They may not exist on disk. 642 | if (sourceMap.map.sourcesContent) { 643 | sourceMap.map.sources.forEach(function(source, i) { 644 | var contents = sourceMap.map.sourcesContent[i]; 645 | if (contents) { 646 | var url = supportRelativeURL(sourceMap.url, source); 647 | fileContentsCache[url] = contents; 648 | } 649 | }); 650 | } 651 | } else { 652 | sourceMap = sourceMapCache[position.source] = { 653 | url: null, 654 | map: null 655 | }; 656 | } 657 | } 658 | 659 | // Resolve the source URL relative to the URL of the source map 660 | if (sourceMap && sourceMap.map) { 661 | var originalPosition = sourceMap.map.originalPositionFor(position); 662 | 663 | // Only return the original position if a matching line was found. If no 664 | // matching line is found then we return position instead, which will cause 665 | // the stack trace to print the path and line for the compiled file. It is 666 | // better to give a precise location in the compiled file than a vague 667 | // location in the original file. 668 | if (originalPosition.source !== null) { 669 | originalPosition.source = supportRelativeURL( 670 | sourceMap.url, originalPosition.source); 671 | return originalPosition; 672 | } 673 | } 674 | 675 | return position; 676 | } 677 | 678 | // Parses code generated by FormatEvalOrigin(), a function inside V8: 679 | // https://code.google.com/p/v8/source/browse/trunk/src/messages.js 680 | function mapEvalOrigin(origin) { 681 | // Most eval() calls are in this format 682 | var match = /^eval at ([^(]+) \((.+):(\d+):(\d+)\)$/.exec(origin); 683 | if (match) { 684 | var position = mapSourcePosition({ 685 | source: match[2], 686 | line: +match[3], 687 | column: match[4] - 1 688 | }); 689 | return 'eval at ' + match[1] + ' (' + position.source + ':' + 690 | position.line + ':' + (position.column + 1) + ')'; 691 | } 692 | 693 | // Parse nested eval() calls using recursion 694 | match = /^eval at ([^(]+) \((.+)\)$/.exec(origin); 695 | if (match) { 696 | return 'eval at ' + match[1] + ' (' + mapEvalOrigin(match[2]) + ')'; 697 | } 698 | 699 | // Make sure we still return useful information if we didn't find anything 700 | return origin; 701 | } 702 | 703 | // This is copied almost verbatim from the V8 source code at 704 | // https://code.google.com/p/v8/source/browse/trunk/src/messages.js. The 705 | // implementation of wrapCallSite() used to just forward to the actual source 706 | // code of CallSite.prototype.toString but unfortunately a new release of V8 707 | // did something to the prototype chain and broke the shim. The only fix I 708 | // could find was copy/paste. 709 | function CallSiteToString() { 710 | var fileName; 711 | var fileLocation = ""; 712 | if (this.isNative()) { 713 | fileLocation = "native"; 714 | } else { 715 | fileName = this.getScriptNameOrSourceURL(); 716 | if (!fileName && this.isEval()) { 717 | fileLocation = this.getEvalOrigin(); 718 | fileLocation += ", "; // Expecting source position to follow. 719 | } 720 | 721 | if (fileName) { 722 | fileLocation += fileName; 723 | } else { 724 | // Source code does not originate from a file and is not native, but we 725 | // can still get the source position inside the source string, e.g. in 726 | // an eval string. 727 | fileLocation += ""; 728 | } 729 | var lineNumber = this.getLineNumber(); 730 | if (lineNumber != null) { 731 | fileLocation += ":" + lineNumber; 732 | var columnNumber = this.getColumnNumber(); 733 | if (columnNumber) { 734 | fileLocation += ":" + columnNumber; 735 | } 736 | } 737 | } 738 | 739 | var line = ""; 740 | var functionName = this.getFunctionName(); 741 | var addSuffix = true; 742 | var isConstructor = this.isConstructor(); 743 | var isMethodCall = !(this.isToplevel() || isConstructor); 744 | if (isMethodCall) { 745 | var typeName = this.getTypeName(); 746 | // Fixes shim to be backward compatable with Node v0 to v4 747 | if (typeName === "[object Object]") { 748 | typeName = "null"; 749 | } 750 | var methodName = this.getMethodName(); 751 | if (functionName) { 752 | if (typeName && functionName.indexOf(typeName) != 0) { 753 | line += typeName + "."; 754 | } 755 | line += functionName; 756 | if (methodName && functionName.indexOf("." + methodName) != functionName.length - methodName.length - 1) { 757 | line += " [as " + methodName + "]"; 758 | } 759 | } else { 760 | line += typeName + "." + (methodName || ""); 761 | } 762 | } else if (isConstructor) { 763 | line += "new " + (functionName || ""); 764 | } else if (functionName) { 765 | line += functionName; 766 | } else { 767 | line += fileLocation; 768 | addSuffix = false; 769 | } 770 | if (addSuffix) { 771 | line += " (" + fileLocation + ")"; 772 | } 773 | return line; 774 | } 775 | 776 | function cloneCallSite(frame) { 777 | var object = {}; 778 | Object.getOwnPropertyNames(Object.getPrototypeOf(frame)).forEach(function(name) { 779 | object[name] = /^(?:is|get)/.test(name) ? function() { return frame[name].call(frame); } : frame[name]; 780 | }); 781 | object.toString = CallSiteToString; 782 | return object; 783 | } 784 | 785 | function wrapCallSite(frame) { 786 | if(frame.isNative()) { 787 | return frame; 788 | } 789 | 790 | // Most call sites will return the source file from getFileName(), but code 791 | // passed to eval() ending in "//# sourceURL=..." will return the source file 792 | // from getScriptNameOrSourceURL() instead 793 | var source = frame.getFileName() || frame.getScriptNameOrSourceURL(); 794 | if (source) { 795 | var line = frame.getLineNumber(); 796 | var column = frame.getColumnNumber() - 1; 797 | 798 | // Fix position in Node where some (internal) code is prepended. 799 | // See https://github.com/evanw/node-source-map-support/issues/36 800 | var headerLength = 62; 801 | if (line === 1 && column > headerLength && !isInBrowser() && !frame.isEval()) { 802 | column -= headerLength; 803 | } 804 | 805 | var position = mapSourcePosition({ 806 | source: source, 807 | line: line, 808 | column: column 809 | }); 810 | frame = cloneCallSite(frame); 811 | var originalFunctionName = frame.getFunctionName; 812 | frame.getFunctionName = function() { return position.name || originalFunctionName(); }; 813 | frame.getFileName = function() { return position.source; }; 814 | frame.getLineNumber = function() { return position.line; }; 815 | frame.getColumnNumber = function() { return position.column + 1; }; 816 | frame.getScriptNameOrSourceURL = function() { return position.source; }; 817 | return frame; 818 | } 819 | 820 | // Code called using eval() needs special handling 821 | var origin = frame.isEval() && frame.getEvalOrigin(); 822 | if (origin) { 823 | origin = mapEvalOrigin(origin); 824 | frame = cloneCallSite(frame); 825 | frame.getEvalOrigin = function() { return origin; }; 826 | return frame; 827 | } 828 | 829 | // If we get here then we were unable to change the source position 830 | return frame; 831 | } 832 | 833 | // This function is part of the V8 stack trace API, for more info see: 834 | // http://code.google.com/p/v8/wiki/JavaScriptStackTraceApi 835 | function prepareStackTrace(error, stack) { 836 | if (emptyCacheBetweenOperations) { 837 | fileContentsCache = {}; 838 | sourceMapCache = {}; 839 | } 840 | 841 | return error + stack.map(function(frame) { 842 | return '\n at ' + wrapCallSite(frame); 843 | }).join(''); 844 | } 845 | 846 | // Generate position and snippet of original source with pointer 847 | function getErrorSource(error) { 848 | var match = /\n at [^(]+ \((.*):(\d+):(\d+)\)/.exec(error.stack); 849 | if (match) { 850 | var source = match[1]; 851 | var line = +match[2]; 852 | var column = +match[3]; 853 | 854 | // Support the inline sourceContents inside the source map 855 | var contents = fileContentsCache[source]; 856 | 857 | // Support files on disk 858 | if (!contents && fs && fs.existsSync(source)) { 859 | try { 860 | contents = fs.readFileSync(source, 'utf8'); 861 | } catch (er) { 862 | contents = ''; 863 | } 864 | } 865 | 866 | // Format the line from the original source code like node does 867 | if (contents) { 868 | var code = contents.split(/(?:\r\n|\r|\n)/)[line - 1]; 869 | if (code) { 870 | return source + ':' + line + '\n' + code + '\n' + 871 | new Array(column).join(' ') + '^'; 872 | } 873 | } 874 | } 875 | return null; 876 | } 877 | 878 | function printErrorAndExit (error) { 879 | var source = getErrorSource(error); 880 | 881 | // Ensure error is printed synchronously and not truncated 882 | if (process.stderr._handle && process.stderr._handle.setBlocking) { 883 | process.stderr._handle.setBlocking(true); 884 | } 885 | 886 | if (source) { 887 | console.error(); 888 | console.error(source); 889 | } 890 | 891 | console.error(error.stack); 892 | process.exit(1); 893 | } 894 | 895 | function shimEmitUncaughtException () { 896 | var origEmit = process.emit; 897 | 898 | process.emit = function (type) { 899 | if (type === 'uncaughtException') { 900 | var hasStack = (arguments[1] && arguments[1].stack); 901 | var hasListeners = (this.listeners(type).length > 0); 902 | 903 | if (hasStack && !hasListeners) { 904 | return printErrorAndExit(arguments[1]); 905 | } 906 | } 907 | 908 | return origEmit.apply(this, arguments); 909 | }; 910 | } 911 | 912 | var originalRetrieveFileHandlers = retrieveFileHandlers.slice(0); 913 | var originalRetrieveMapHandlers = retrieveMapHandlers.slice(0); 914 | 915 | exports.wrapCallSite = wrapCallSite; 916 | exports.getErrorSource = getErrorSource; 917 | exports.mapSourcePosition = mapSourcePosition; 918 | exports.retrieveSourceMap = retrieveSourceMap; 919 | 920 | exports.install = function(options) { 921 | options = options || {}; 922 | 923 | if (options.environment) { 924 | environment = options.environment; 925 | if (["node", "browser", "auto"].indexOf(environment) === -1) { 926 | throw new Error("environment " + environment + " was unknown. Available options are {auto, browser, node}") 927 | } 928 | } 929 | 930 | // Allow sources to be found by methods other than reading the files 931 | // directly from disk. 932 | if (options.retrieveFile) { 933 | if (options.overrideRetrieveFile) { 934 | retrieveFileHandlers.length = 0; 935 | } 936 | 937 | retrieveFileHandlers.unshift(options.retrieveFile); 938 | } 939 | 940 | // Allow source maps to be found by methods other than reading the files 941 | // directly from disk. 942 | if (options.retrieveSourceMap) { 943 | if (options.overrideRetrieveSourceMap) { 944 | retrieveMapHandlers.length = 0; 945 | } 946 | 947 | retrieveMapHandlers.unshift(options.retrieveSourceMap); 948 | } 949 | 950 | // Support runtime transpilers that include inline source maps 951 | if (options.hookRequire && !isInBrowser()) { 952 | var Module; 953 | try { 954 | Module = __webpack_require__(282); 955 | } catch (err) { 956 | // NOP: Loading in catch block to convert webpack error to warning. 957 | } 958 | var $compile = Module.prototype._compile; 959 | 960 | if (!$compile.__sourceMapSupport) { 961 | Module.prototype._compile = function(content, filename) { 962 | fileContentsCache[filename] = content; 963 | sourceMapCache[filename] = undefined; 964 | return $compile.call(this, content, filename); 965 | }; 966 | 967 | Module.prototype._compile.__sourceMapSupport = true; 968 | } 969 | } 970 | 971 | // Configure options 972 | if (!emptyCacheBetweenOperations) { 973 | emptyCacheBetweenOperations = 'emptyCacheBetweenOperations' in options ? 974 | options.emptyCacheBetweenOperations : false; 975 | } 976 | 977 | // Install the error reformatter 978 | if (!errorFormatterInstalled) { 979 | errorFormatterInstalled = true; 980 | Error.prepareStackTrace = prepareStackTrace; 981 | } 982 | 983 | if (!uncaughtShimInstalled) { 984 | var installHandler = 'handleUncaughtExceptions' in options ? 985 | options.handleUncaughtExceptions : true; 986 | 987 | // Provide the option to not install the uncaught exception handler. This is 988 | // to support other uncaught exception handlers (in test frameworks, for 989 | // example). If this handler is not installed and there are no other uncaught 990 | // exception handlers, uncaught exceptions will be caught by node's built-in 991 | // exception handler and the process will still be terminated. However, the 992 | // generated JavaScript code will be shown above the stack trace instead of 993 | // the original source code. 994 | if (installHandler && hasGlobalProcessEventEmitter()) { 995 | uncaughtShimInstalled = true; 996 | shimEmitUncaughtException(); 997 | } 998 | } 999 | }; 1000 | 1001 | exports.resetRetrieveHandlers = function() { 1002 | retrieveFileHandlers.length = 0; 1003 | retrieveMapHandlers.length = 0; 1004 | 1005 | retrieveFileHandlers = originalRetrieveFileHandlers.slice(0); 1006 | retrieveMapHandlers = originalRetrieveMapHandlers.slice(0); 1007 | } 1008 | 1009 | 1010 | /***/ }), 1011 | 1012 | /***/ 327: 1013 | /***/ (function(__unusedmodule, exports, __webpack_require__) { 1014 | 1015 | /* -*- Mode: js; js-indent-level: 2; -*- */ 1016 | /* 1017 | * Copyright 2011 Mozilla Foundation and contributors 1018 | * Licensed under the New BSD license. See LICENSE or: 1019 | * http://opensource.org/licenses/BSD-3-Clause 1020 | */ 1021 | 1022 | var util = __webpack_require__(983); 1023 | var binarySearch = __webpack_require__(164); 1024 | var ArraySet = __webpack_require__(837).ArraySet; 1025 | var base64VLQ = __webpack_require__(215); 1026 | var quickSort = __webpack_require__(226).quickSort; 1027 | 1028 | function SourceMapConsumer(aSourceMap, aSourceMapURL) { 1029 | var sourceMap = aSourceMap; 1030 | if (typeof aSourceMap === 'string') { 1031 | sourceMap = util.parseSourceMapInput(aSourceMap); 1032 | } 1033 | 1034 | return sourceMap.sections != null 1035 | ? new IndexedSourceMapConsumer(sourceMap, aSourceMapURL) 1036 | : new BasicSourceMapConsumer(sourceMap, aSourceMapURL); 1037 | } 1038 | 1039 | SourceMapConsumer.fromSourceMap = function(aSourceMap, aSourceMapURL) { 1040 | return BasicSourceMapConsumer.fromSourceMap(aSourceMap, aSourceMapURL); 1041 | } 1042 | 1043 | /** 1044 | * The version of the source mapping spec that we are consuming. 1045 | */ 1046 | SourceMapConsumer.prototype._version = 3; 1047 | 1048 | // `__generatedMappings` and `__originalMappings` are arrays that hold the 1049 | // parsed mapping coordinates from the source map's "mappings" attribute. They 1050 | // are lazily instantiated, accessed via the `_generatedMappings` and 1051 | // `_originalMappings` getters respectively, and we only parse the mappings 1052 | // and create these arrays once queried for a source location. We jump through 1053 | // these hoops because there can be many thousands of mappings, and parsing 1054 | // them is expensive, so we only want to do it if we must. 1055 | // 1056 | // Each object in the arrays is of the form: 1057 | // 1058 | // { 1059 | // generatedLine: The line number in the generated code, 1060 | // generatedColumn: The column number in the generated code, 1061 | // source: The path to the original source file that generated this 1062 | // chunk of code, 1063 | // originalLine: The line number in the original source that 1064 | // corresponds to this chunk of generated code, 1065 | // originalColumn: The column number in the original source that 1066 | // corresponds to this chunk of generated code, 1067 | // name: The name of the original symbol which generated this chunk of 1068 | // code. 1069 | // } 1070 | // 1071 | // All properties except for `generatedLine` and `generatedColumn` can be 1072 | // `null`. 1073 | // 1074 | // `_generatedMappings` is ordered by the generated positions. 1075 | // 1076 | // `_originalMappings` is ordered by the original positions. 1077 | 1078 | SourceMapConsumer.prototype.__generatedMappings = null; 1079 | Object.defineProperty(SourceMapConsumer.prototype, '_generatedMappings', { 1080 | configurable: true, 1081 | enumerable: true, 1082 | get: function () { 1083 | if (!this.__generatedMappings) { 1084 | this._parseMappings(this._mappings, this.sourceRoot); 1085 | } 1086 | 1087 | return this.__generatedMappings; 1088 | } 1089 | }); 1090 | 1091 | SourceMapConsumer.prototype.__originalMappings = null; 1092 | Object.defineProperty(SourceMapConsumer.prototype, '_originalMappings', { 1093 | configurable: true, 1094 | enumerable: true, 1095 | get: function () { 1096 | if (!this.__originalMappings) { 1097 | this._parseMappings(this._mappings, this.sourceRoot); 1098 | } 1099 | 1100 | return this.__originalMappings; 1101 | } 1102 | }); 1103 | 1104 | SourceMapConsumer.prototype._charIsMappingSeparator = 1105 | function SourceMapConsumer_charIsMappingSeparator(aStr, index) { 1106 | var c = aStr.charAt(index); 1107 | return c === ";" || c === ","; 1108 | }; 1109 | 1110 | /** 1111 | * Parse the mappings in a string in to a data structure which we can easily 1112 | * query (the ordered arrays in the `this.__generatedMappings` and 1113 | * `this.__originalMappings` properties). 1114 | */ 1115 | SourceMapConsumer.prototype._parseMappings = 1116 | function SourceMapConsumer_parseMappings(aStr, aSourceRoot) { 1117 | throw new Error("Subclasses must implement _parseMappings"); 1118 | }; 1119 | 1120 | SourceMapConsumer.GENERATED_ORDER = 1; 1121 | SourceMapConsumer.ORIGINAL_ORDER = 2; 1122 | 1123 | SourceMapConsumer.GREATEST_LOWER_BOUND = 1; 1124 | SourceMapConsumer.LEAST_UPPER_BOUND = 2; 1125 | 1126 | /** 1127 | * Iterate over each mapping between an original source/line/column and a 1128 | * generated line/column in this source map. 1129 | * 1130 | * @param Function aCallback 1131 | * The function that is called with each mapping. 1132 | * @param Object aContext 1133 | * Optional. If specified, this object will be the value of `this` every 1134 | * time that `aCallback` is called. 1135 | * @param aOrder 1136 | * Either `SourceMapConsumer.GENERATED_ORDER` or 1137 | * `SourceMapConsumer.ORIGINAL_ORDER`. Specifies whether you want to 1138 | * iterate over the mappings sorted by the generated file's line/column 1139 | * order or the original's source/line/column order, respectively. Defaults to 1140 | * `SourceMapConsumer.GENERATED_ORDER`. 1141 | */ 1142 | SourceMapConsumer.prototype.eachMapping = 1143 | function SourceMapConsumer_eachMapping(aCallback, aContext, aOrder) { 1144 | var context = aContext || null; 1145 | var order = aOrder || SourceMapConsumer.GENERATED_ORDER; 1146 | 1147 | var mappings; 1148 | switch (order) { 1149 | case SourceMapConsumer.GENERATED_ORDER: 1150 | mappings = this._generatedMappings; 1151 | break; 1152 | case SourceMapConsumer.ORIGINAL_ORDER: 1153 | mappings = this._originalMappings; 1154 | break; 1155 | default: 1156 | throw new Error("Unknown order of iteration."); 1157 | } 1158 | 1159 | var sourceRoot = this.sourceRoot; 1160 | mappings.map(function (mapping) { 1161 | var source = mapping.source === null ? null : this._sources.at(mapping.source); 1162 | source = util.computeSourceURL(sourceRoot, source, this._sourceMapURL); 1163 | return { 1164 | source: source, 1165 | generatedLine: mapping.generatedLine, 1166 | generatedColumn: mapping.generatedColumn, 1167 | originalLine: mapping.originalLine, 1168 | originalColumn: mapping.originalColumn, 1169 | name: mapping.name === null ? null : this._names.at(mapping.name) 1170 | }; 1171 | }, this).forEach(aCallback, context); 1172 | }; 1173 | 1174 | /** 1175 | * Returns all generated line and column information for the original source, 1176 | * line, and column provided. If no column is provided, returns all mappings 1177 | * corresponding to a either the line we are searching for or the next 1178 | * closest line that has any mappings. Otherwise, returns all mappings 1179 | * corresponding to the given line and either the column we are searching for 1180 | * or the next closest column that has any offsets. 1181 | * 1182 | * The only argument is an object with the following properties: 1183 | * 1184 | * - source: The filename of the original source. 1185 | * - line: The line number in the original source. The line number is 1-based. 1186 | * - column: Optional. the column number in the original source. 1187 | * The column number is 0-based. 1188 | * 1189 | * and an array of objects is returned, each with the following properties: 1190 | * 1191 | * - line: The line number in the generated source, or null. The 1192 | * line number is 1-based. 1193 | * - column: The column number in the generated source, or null. 1194 | * The column number is 0-based. 1195 | */ 1196 | SourceMapConsumer.prototype.allGeneratedPositionsFor = 1197 | function SourceMapConsumer_allGeneratedPositionsFor(aArgs) { 1198 | var line = util.getArg(aArgs, 'line'); 1199 | 1200 | // When there is no exact match, BasicSourceMapConsumer.prototype._findMapping 1201 | // returns the index of the closest mapping less than the needle. By 1202 | // setting needle.originalColumn to 0, we thus find the last mapping for 1203 | // the given line, provided such a mapping exists. 1204 | var needle = { 1205 | source: util.getArg(aArgs, 'source'), 1206 | originalLine: line, 1207 | originalColumn: util.getArg(aArgs, 'column', 0) 1208 | }; 1209 | 1210 | needle.source = this._findSourceIndex(needle.source); 1211 | if (needle.source < 0) { 1212 | return []; 1213 | } 1214 | 1215 | var mappings = []; 1216 | 1217 | var index = this._findMapping(needle, 1218 | this._originalMappings, 1219 | "originalLine", 1220 | "originalColumn", 1221 | util.compareByOriginalPositions, 1222 | binarySearch.LEAST_UPPER_BOUND); 1223 | if (index >= 0) { 1224 | var mapping = this._originalMappings[index]; 1225 | 1226 | if (aArgs.column === undefined) { 1227 | var originalLine = mapping.originalLine; 1228 | 1229 | // Iterate until either we run out of mappings, or we run into 1230 | // a mapping for a different line than the one we found. Since 1231 | // mappings are sorted, this is guaranteed to find all mappings for 1232 | // the line we found. 1233 | while (mapping && mapping.originalLine === originalLine) { 1234 | mappings.push({ 1235 | line: util.getArg(mapping, 'generatedLine', null), 1236 | column: util.getArg(mapping, 'generatedColumn', null), 1237 | lastColumn: util.getArg(mapping, 'lastGeneratedColumn', null) 1238 | }); 1239 | 1240 | mapping = this._originalMappings[++index]; 1241 | } 1242 | } else { 1243 | var originalColumn = mapping.originalColumn; 1244 | 1245 | // Iterate until either we run out of mappings, or we run into 1246 | // a mapping for a different line than the one we were searching for. 1247 | // Since mappings are sorted, this is guaranteed to find all mappings for 1248 | // the line we are searching for. 1249 | while (mapping && 1250 | mapping.originalLine === line && 1251 | mapping.originalColumn == originalColumn) { 1252 | mappings.push({ 1253 | line: util.getArg(mapping, 'generatedLine', null), 1254 | column: util.getArg(mapping, 'generatedColumn', null), 1255 | lastColumn: util.getArg(mapping, 'lastGeneratedColumn', null) 1256 | }); 1257 | 1258 | mapping = this._originalMappings[++index]; 1259 | } 1260 | } 1261 | } 1262 | 1263 | return mappings; 1264 | }; 1265 | 1266 | exports.SourceMapConsumer = SourceMapConsumer; 1267 | 1268 | /** 1269 | * A BasicSourceMapConsumer instance represents a parsed source map which we can 1270 | * query for information about the original file positions by giving it a file 1271 | * position in the generated source. 1272 | * 1273 | * The first parameter is the raw source map (either as a JSON string, or 1274 | * already parsed to an object). According to the spec, source maps have the 1275 | * following attributes: 1276 | * 1277 | * - version: Which version of the source map spec this map is following. 1278 | * - sources: An array of URLs to the original source files. 1279 | * - names: An array of identifiers which can be referrenced by individual mappings. 1280 | * - sourceRoot: Optional. The URL root from which all sources are relative. 1281 | * - sourcesContent: Optional. An array of contents of the original source files. 1282 | * - mappings: A string of base64 VLQs which contain the actual mappings. 1283 | * - file: Optional. The generated file this source map is associated with. 1284 | * 1285 | * Here is an example source map, taken from the source map spec[0]: 1286 | * 1287 | * { 1288 | * version : 3, 1289 | * file: "out.js", 1290 | * sourceRoot : "", 1291 | * sources: ["foo.js", "bar.js"], 1292 | * names: ["src", "maps", "are", "fun"], 1293 | * mappings: "AA,AB;;ABCDE;" 1294 | * } 1295 | * 1296 | * The second parameter, if given, is a string whose value is the URL 1297 | * at which the source map was found. This URL is used to compute the 1298 | * sources array. 1299 | * 1300 | * [0]: https://docs.google.com/document/d/1U1RGAehQwRypUTovF1KRlpiOFze0b-_2gc6fAH0KY0k/edit?pli=1# 1301 | */ 1302 | function BasicSourceMapConsumer(aSourceMap, aSourceMapURL) { 1303 | var sourceMap = aSourceMap; 1304 | if (typeof aSourceMap === 'string') { 1305 | sourceMap = util.parseSourceMapInput(aSourceMap); 1306 | } 1307 | 1308 | var version = util.getArg(sourceMap, 'version'); 1309 | var sources = util.getArg(sourceMap, 'sources'); 1310 | // Sass 3.3 leaves out the 'names' array, so we deviate from the spec (which 1311 | // requires the array) to play nice here. 1312 | var names = util.getArg(sourceMap, 'names', []); 1313 | var sourceRoot = util.getArg(sourceMap, 'sourceRoot', null); 1314 | var sourcesContent = util.getArg(sourceMap, 'sourcesContent', null); 1315 | var mappings = util.getArg(sourceMap, 'mappings'); 1316 | var file = util.getArg(sourceMap, 'file', null); 1317 | 1318 | // Once again, Sass deviates from the spec and supplies the version as a 1319 | // string rather than a number, so we use loose equality checking here. 1320 | if (version != this._version) { 1321 | throw new Error('Unsupported version: ' + version); 1322 | } 1323 | 1324 | if (sourceRoot) { 1325 | sourceRoot = util.normalize(sourceRoot); 1326 | } 1327 | 1328 | sources = sources 1329 | .map(String) 1330 | // Some source maps produce relative source paths like "./foo.js" instead of 1331 | // "foo.js". Normalize these first so that future comparisons will succeed. 1332 | // See bugzil.la/1090768. 1333 | .map(util.normalize) 1334 | // Always ensure that absolute sources are internally stored relative to 1335 | // the source root, if the source root is absolute. Not doing this would 1336 | // be particularly problematic when the source root is a prefix of the 1337 | // source (valid, but why??). See github issue #199 and bugzil.la/1188982. 1338 | .map(function (source) { 1339 | return sourceRoot && util.isAbsolute(sourceRoot) && util.isAbsolute(source) 1340 | ? util.relative(sourceRoot, source) 1341 | : source; 1342 | }); 1343 | 1344 | // Pass `true` below to allow duplicate names and sources. While source maps 1345 | // are intended to be compressed and deduplicated, the TypeScript compiler 1346 | // sometimes generates source maps with duplicates in them. See Github issue 1347 | // #72 and bugzil.la/889492. 1348 | this._names = ArraySet.fromArray(names.map(String), true); 1349 | this._sources = ArraySet.fromArray(sources, true); 1350 | 1351 | this._absoluteSources = this._sources.toArray().map(function (s) { 1352 | return util.computeSourceURL(sourceRoot, s, aSourceMapURL); 1353 | }); 1354 | 1355 | this.sourceRoot = sourceRoot; 1356 | this.sourcesContent = sourcesContent; 1357 | this._mappings = mappings; 1358 | this._sourceMapURL = aSourceMapURL; 1359 | this.file = file; 1360 | } 1361 | 1362 | BasicSourceMapConsumer.prototype = Object.create(SourceMapConsumer.prototype); 1363 | BasicSourceMapConsumer.prototype.consumer = SourceMapConsumer; 1364 | 1365 | /** 1366 | * Utility function to find the index of a source. Returns -1 if not 1367 | * found. 1368 | */ 1369 | BasicSourceMapConsumer.prototype._findSourceIndex = function(aSource) { 1370 | var relativeSource = aSource; 1371 | if (this.sourceRoot != null) { 1372 | relativeSource = util.relative(this.sourceRoot, relativeSource); 1373 | } 1374 | 1375 | if (this._sources.has(relativeSource)) { 1376 | return this._sources.indexOf(relativeSource); 1377 | } 1378 | 1379 | // Maybe aSource is an absolute URL as returned by |sources|. In 1380 | // this case we can't simply undo the transform. 1381 | var i; 1382 | for (i = 0; i < this._absoluteSources.length; ++i) { 1383 | if (this._absoluteSources[i] == aSource) { 1384 | return i; 1385 | } 1386 | } 1387 | 1388 | return -1; 1389 | }; 1390 | 1391 | /** 1392 | * Create a BasicSourceMapConsumer from a SourceMapGenerator. 1393 | * 1394 | * @param SourceMapGenerator aSourceMap 1395 | * The source map that will be consumed. 1396 | * @param String aSourceMapURL 1397 | * The URL at which the source map can be found (optional) 1398 | * @returns BasicSourceMapConsumer 1399 | */ 1400 | BasicSourceMapConsumer.fromSourceMap = 1401 | function SourceMapConsumer_fromSourceMap(aSourceMap, aSourceMapURL) { 1402 | var smc = Object.create(BasicSourceMapConsumer.prototype); 1403 | 1404 | var names = smc._names = ArraySet.fromArray(aSourceMap._names.toArray(), true); 1405 | var sources = smc._sources = ArraySet.fromArray(aSourceMap._sources.toArray(), true); 1406 | smc.sourceRoot = aSourceMap._sourceRoot; 1407 | smc.sourcesContent = aSourceMap._generateSourcesContent(smc._sources.toArray(), 1408 | smc.sourceRoot); 1409 | smc.file = aSourceMap._file; 1410 | smc._sourceMapURL = aSourceMapURL; 1411 | smc._absoluteSources = smc._sources.toArray().map(function (s) { 1412 | return util.computeSourceURL(smc.sourceRoot, s, aSourceMapURL); 1413 | }); 1414 | 1415 | // Because we are modifying the entries (by converting string sources and 1416 | // names to indices into the sources and names ArraySets), we have to make 1417 | // a copy of the entry or else bad things happen. Shared mutable state 1418 | // strikes again! See github issue #191. 1419 | 1420 | var generatedMappings = aSourceMap._mappings.toArray().slice(); 1421 | var destGeneratedMappings = smc.__generatedMappings = []; 1422 | var destOriginalMappings = smc.__originalMappings = []; 1423 | 1424 | for (var i = 0, length = generatedMappings.length; i < length; i++) { 1425 | var srcMapping = generatedMappings[i]; 1426 | var destMapping = new Mapping; 1427 | destMapping.generatedLine = srcMapping.generatedLine; 1428 | destMapping.generatedColumn = srcMapping.generatedColumn; 1429 | 1430 | if (srcMapping.source) { 1431 | destMapping.source = sources.indexOf(srcMapping.source); 1432 | destMapping.originalLine = srcMapping.originalLine; 1433 | destMapping.originalColumn = srcMapping.originalColumn; 1434 | 1435 | if (srcMapping.name) { 1436 | destMapping.name = names.indexOf(srcMapping.name); 1437 | } 1438 | 1439 | destOriginalMappings.push(destMapping); 1440 | } 1441 | 1442 | destGeneratedMappings.push(destMapping); 1443 | } 1444 | 1445 | quickSort(smc.__originalMappings, util.compareByOriginalPositions); 1446 | 1447 | return smc; 1448 | }; 1449 | 1450 | /** 1451 | * The version of the source mapping spec that we are consuming. 1452 | */ 1453 | BasicSourceMapConsumer.prototype._version = 3; 1454 | 1455 | /** 1456 | * The list of original sources. 1457 | */ 1458 | Object.defineProperty(BasicSourceMapConsumer.prototype, 'sources', { 1459 | get: function () { 1460 | return this._absoluteSources.slice(); 1461 | } 1462 | }); 1463 | 1464 | /** 1465 | * Provide the JIT with a nice shape / hidden class. 1466 | */ 1467 | function Mapping() { 1468 | this.generatedLine = 0; 1469 | this.generatedColumn = 0; 1470 | this.source = null; 1471 | this.originalLine = null; 1472 | this.originalColumn = null; 1473 | this.name = null; 1474 | } 1475 | 1476 | /** 1477 | * Parse the mappings in a string in to a data structure which we can easily 1478 | * query (the ordered arrays in the `this.__generatedMappings` and 1479 | * `this.__originalMappings` properties). 1480 | */ 1481 | BasicSourceMapConsumer.prototype._parseMappings = 1482 | function SourceMapConsumer_parseMappings(aStr, aSourceRoot) { 1483 | var generatedLine = 1; 1484 | var previousGeneratedColumn = 0; 1485 | var previousOriginalLine = 0; 1486 | var previousOriginalColumn = 0; 1487 | var previousSource = 0; 1488 | var previousName = 0; 1489 | var length = aStr.length; 1490 | var index = 0; 1491 | var cachedSegments = {}; 1492 | var temp = {}; 1493 | var originalMappings = []; 1494 | var generatedMappings = []; 1495 | var mapping, str, segment, end, value; 1496 | 1497 | while (index < length) { 1498 | if (aStr.charAt(index) === ';') { 1499 | generatedLine++; 1500 | index++; 1501 | previousGeneratedColumn = 0; 1502 | } 1503 | else if (aStr.charAt(index) === ',') { 1504 | index++; 1505 | } 1506 | else { 1507 | mapping = new Mapping(); 1508 | mapping.generatedLine = generatedLine; 1509 | 1510 | // Because each offset is encoded relative to the previous one, 1511 | // many segments often have the same encoding. We can exploit this 1512 | // fact by caching the parsed variable length fields of each segment, 1513 | // allowing us to avoid a second parse if we encounter the same 1514 | // segment again. 1515 | for (end = index; end < length; end++) { 1516 | if (this._charIsMappingSeparator(aStr, end)) { 1517 | break; 1518 | } 1519 | } 1520 | str = aStr.slice(index, end); 1521 | 1522 | segment = cachedSegments[str]; 1523 | if (segment) { 1524 | index += str.length; 1525 | } else { 1526 | segment = []; 1527 | while (index < end) { 1528 | base64VLQ.decode(aStr, index, temp); 1529 | value = temp.value; 1530 | index = temp.rest; 1531 | segment.push(value); 1532 | } 1533 | 1534 | if (segment.length === 2) { 1535 | throw new Error('Found a source, but no line and column'); 1536 | } 1537 | 1538 | if (segment.length === 3) { 1539 | throw new Error('Found a source and line, but no column'); 1540 | } 1541 | 1542 | cachedSegments[str] = segment; 1543 | } 1544 | 1545 | // Generated column. 1546 | mapping.generatedColumn = previousGeneratedColumn + segment[0]; 1547 | previousGeneratedColumn = mapping.generatedColumn; 1548 | 1549 | if (segment.length > 1) { 1550 | // Original source. 1551 | mapping.source = previousSource + segment[1]; 1552 | previousSource += segment[1]; 1553 | 1554 | // Original line. 1555 | mapping.originalLine = previousOriginalLine + segment[2]; 1556 | previousOriginalLine = mapping.originalLine; 1557 | // Lines are stored 0-based 1558 | mapping.originalLine += 1; 1559 | 1560 | // Original column. 1561 | mapping.originalColumn = previousOriginalColumn + segment[3]; 1562 | previousOriginalColumn = mapping.originalColumn; 1563 | 1564 | if (segment.length > 4) { 1565 | // Original name. 1566 | mapping.name = previousName + segment[4]; 1567 | previousName += segment[4]; 1568 | } 1569 | } 1570 | 1571 | generatedMappings.push(mapping); 1572 | if (typeof mapping.originalLine === 'number') { 1573 | originalMappings.push(mapping); 1574 | } 1575 | } 1576 | } 1577 | 1578 | quickSort(generatedMappings, util.compareByGeneratedPositionsDeflated); 1579 | this.__generatedMappings = generatedMappings; 1580 | 1581 | quickSort(originalMappings, util.compareByOriginalPositions); 1582 | this.__originalMappings = originalMappings; 1583 | }; 1584 | 1585 | /** 1586 | * Find the mapping that best matches the hypothetical "needle" mapping that 1587 | * we are searching for in the given "haystack" of mappings. 1588 | */ 1589 | BasicSourceMapConsumer.prototype._findMapping = 1590 | function SourceMapConsumer_findMapping(aNeedle, aMappings, aLineName, 1591 | aColumnName, aComparator, aBias) { 1592 | // To return the position we are searching for, we must first find the 1593 | // mapping for the given position and then return the opposite position it 1594 | // points to. Because the mappings are sorted, we can use binary search to 1595 | // find the best mapping. 1596 | 1597 | if (aNeedle[aLineName] <= 0) { 1598 | throw new TypeError('Line must be greater than or equal to 1, got ' 1599 | + aNeedle[aLineName]); 1600 | } 1601 | if (aNeedle[aColumnName] < 0) { 1602 | throw new TypeError('Column must be greater than or equal to 0, got ' 1603 | + aNeedle[aColumnName]); 1604 | } 1605 | 1606 | return binarySearch.search(aNeedle, aMappings, aComparator, aBias); 1607 | }; 1608 | 1609 | /** 1610 | * Compute the last column for each generated mapping. The last column is 1611 | * inclusive. 1612 | */ 1613 | BasicSourceMapConsumer.prototype.computeColumnSpans = 1614 | function SourceMapConsumer_computeColumnSpans() { 1615 | for (var index = 0; index < this._generatedMappings.length; ++index) { 1616 | var mapping = this._generatedMappings[index]; 1617 | 1618 | // Mappings do not contain a field for the last generated columnt. We 1619 | // can come up with an optimistic estimate, however, by assuming that 1620 | // mappings are contiguous (i.e. given two consecutive mappings, the 1621 | // first mapping ends where the second one starts). 1622 | if (index + 1 < this._generatedMappings.length) { 1623 | var nextMapping = this._generatedMappings[index + 1]; 1624 | 1625 | if (mapping.generatedLine === nextMapping.generatedLine) { 1626 | mapping.lastGeneratedColumn = nextMapping.generatedColumn - 1; 1627 | continue; 1628 | } 1629 | } 1630 | 1631 | // The last mapping for each line spans the entire line. 1632 | mapping.lastGeneratedColumn = Infinity; 1633 | } 1634 | }; 1635 | 1636 | /** 1637 | * Returns the original source, line, and column information for the generated 1638 | * source's line and column positions provided. The only argument is an object 1639 | * with the following properties: 1640 | * 1641 | * - line: The line number in the generated source. The line number 1642 | * is 1-based. 1643 | * - column: The column number in the generated source. The column 1644 | * number is 0-based. 1645 | * - bias: Either 'SourceMapConsumer.GREATEST_LOWER_BOUND' or 1646 | * 'SourceMapConsumer.LEAST_UPPER_BOUND'. Specifies whether to return the 1647 | * closest element that is smaller than or greater than the one we are 1648 | * searching for, respectively, if the exact element cannot be found. 1649 | * Defaults to 'SourceMapConsumer.GREATEST_LOWER_BOUND'. 1650 | * 1651 | * and an object is returned with the following properties: 1652 | * 1653 | * - source: The original source file, or null. 1654 | * - line: The line number in the original source, or null. The 1655 | * line number is 1-based. 1656 | * - column: The column number in the original source, or null. The 1657 | * column number is 0-based. 1658 | * - name: The original identifier, or null. 1659 | */ 1660 | BasicSourceMapConsumer.prototype.originalPositionFor = 1661 | function SourceMapConsumer_originalPositionFor(aArgs) { 1662 | var needle = { 1663 | generatedLine: util.getArg(aArgs, 'line'), 1664 | generatedColumn: util.getArg(aArgs, 'column') 1665 | }; 1666 | 1667 | var index = this._findMapping( 1668 | needle, 1669 | this._generatedMappings, 1670 | "generatedLine", 1671 | "generatedColumn", 1672 | util.compareByGeneratedPositionsDeflated, 1673 | util.getArg(aArgs, 'bias', SourceMapConsumer.GREATEST_LOWER_BOUND) 1674 | ); 1675 | 1676 | if (index >= 0) { 1677 | var mapping = this._generatedMappings[index]; 1678 | 1679 | if (mapping.generatedLine === needle.generatedLine) { 1680 | var source = util.getArg(mapping, 'source', null); 1681 | if (source !== null) { 1682 | source = this._sources.at(source); 1683 | source = util.computeSourceURL(this.sourceRoot, source, this._sourceMapURL); 1684 | } 1685 | var name = util.getArg(mapping, 'name', null); 1686 | if (name !== null) { 1687 | name = this._names.at(name); 1688 | } 1689 | return { 1690 | source: source, 1691 | line: util.getArg(mapping, 'originalLine', null), 1692 | column: util.getArg(mapping, 'originalColumn', null), 1693 | name: name 1694 | }; 1695 | } 1696 | } 1697 | 1698 | return { 1699 | source: null, 1700 | line: null, 1701 | column: null, 1702 | name: null 1703 | }; 1704 | }; 1705 | 1706 | /** 1707 | * Return true if we have the source content for every source in the source 1708 | * map, false otherwise. 1709 | */ 1710 | BasicSourceMapConsumer.prototype.hasContentsOfAllSources = 1711 | function BasicSourceMapConsumer_hasContentsOfAllSources() { 1712 | if (!this.sourcesContent) { 1713 | return false; 1714 | } 1715 | return this.sourcesContent.length >= this._sources.size() && 1716 | !this.sourcesContent.some(function (sc) { return sc == null; }); 1717 | }; 1718 | 1719 | /** 1720 | * Returns the original source content. The only argument is the url of the 1721 | * original source file. Returns null if no original source content is 1722 | * available. 1723 | */ 1724 | BasicSourceMapConsumer.prototype.sourceContentFor = 1725 | function SourceMapConsumer_sourceContentFor(aSource, nullOnMissing) { 1726 | if (!this.sourcesContent) { 1727 | return null; 1728 | } 1729 | 1730 | var index = this._findSourceIndex(aSource); 1731 | if (index >= 0) { 1732 | return this.sourcesContent[index]; 1733 | } 1734 | 1735 | var relativeSource = aSource; 1736 | if (this.sourceRoot != null) { 1737 | relativeSource = util.relative(this.sourceRoot, relativeSource); 1738 | } 1739 | 1740 | var url; 1741 | if (this.sourceRoot != null 1742 | && (url = util.urlParse(this.sourceRoot))) { 1743 | // XXX: file:// URIs and absolute paths lead to unexpected behavior for 1744 | // many users. We can help them out when they expect file:// URIs to 1745 | // behave like it would if they were running a local HTTP server. See 1746 | // https://bugzilla.mozilla.org/show_bug.cgi?id=885597. 1747 | var fileUriAbsPath = relativeSource.replace(/^file:\/\//, ""); 1748 | if (url.scheme == "file" 1749 | && this._sources.has(fileUriAbsPath)) { 1750 | return this.sourcesContent[this._sources.indexOf(fileUriAbsPath)] 1751 | } 1752 | 1753 | if ((!url.path || url.path == "/") 1754 | && this._sources.has("/" + relativeSource)) { 1755 | return this.sourcesContent[this._sources.indexOf("/" + relativeSource)]; 1756 | } 1757 | } 1758 | 1759 | // This function is used recursively from 1760 | // IndexedSourceMapConsumer.prototype.sourceContentFor. In that case, we 1761 | // don't want to throw if we can't find the source - we just want to 1762 | // return null, so we provide a flag to exit gracefully. 1763 | if (nullOnMissing) { 1764 | return null; 1765 | } 1766 | else { 1767 | throw new Error('"' + relativeSource + '" is not in the SourceMap.'); 1768 | } 1769 | }; 1770 | 1771 | /** 1772 | * Returns the generated line and column information for the original source, 1773 | * line, and column positions provided. The only argument is an object with 1774 | * the following properties: 1775 | * 1776 | * - source: The filename of the original source. 1777 | * - line: The line number in the original source. The line number 1778 | * is 1-based. 1779 | * - column: The column number in the original source. The column 1780 | * number is 0-based. 1781 | * - bias: Either 'SourceMapConsumer.GREATEST_LOWER_BOUND' or 1782 | * 'SourceMapConsumer.LEAST_UPPER_BOUND'. Specifies whether to return the 1783 | * closest element that is smaller than or greater than the one we are 1784 | * searching for, respectively, if the exact element cannot be found. 1785 | * Defaults to 'SourceMapConsumer.GREATEST_LOWER_BOUND'. 1786 | * 1787 | * and an object is returned with the following properties: 1788 | * 1789 | * - line: The line number in the generated source, or null. The 1790 | * line number is 1-based. 1791 | * - column: The column number in the generated source, or null. 1792 | * The column number is 0-based. 1793 | */ 1794 | BasicSourceMapConsumer.prototype.generatedPositionFor = 1795 | function SourceMapConsumer_generatedPositionFor(aArgs) { 1796 | var source = util.getArg(aArgs, 'source'); 1797 | source = this._findSourceIndex(source); 1798 | if (source < 0) { 1799 | return { 1800 | line: null, 1801 | column: null, 1802 | lastColumn: null 1803 | }; 1804 | } 1805 | 1806 | var needle = { 1807 | source: source, 1808 | originalLine: util.getArg(aArgs, 'line'), 1809 | originalColumn: util.getArg(aArgs, 'column') 1810 | }; 1811 | 1812 | var index = this._findMapping( 1813 | needle, 1814 | this._originalMappings, 1815 | "originalLine", 1816 | "originalColumn", 1817 | util.compareByOriginalPositions, 1818 | util.getArg(aArgs, 'bias', SourceMapConsumer.GREATEST_LOWER_BOUND) 1819 | ); 1820 | 1821 | if (index >= 0) { 1822 | var mapping = this._originalMappings[index]; 1823 | 1824 | if (mapping.source === needle.source) { 1825 | return { 1826 | line: util.getArg(mapping, 'generatedLine', null), 1827 | column: util.getArg(mapping, 'generatedColumn', null), 1828 | lastColumn: util.getArg(mapping, 'lastGeneratedColumn', null) 1829 | }; 1830 | } 1831 | } 1832 | 1833 | return { 1834 | line: null, 1835 | column: null, 1836 | lastColumn: null 1837 | }; 1838 | }; 1839 | 1840 | exports.BasicSourceMapConsumer = BasicSourceMapConsumer; 1841 | 1842 | /** 1843 | * An IndexedSourceMapConsumer instance represents a parsed source map which 1844 | * we can query for information. It differs from BasicSourceMapConsumer in 1845 | * that it takes "indexed" source maps (i.e. ones with a "sections" field) as 1846 | * input. 1847 | * 1848 | * The first parameter is a raw source map (either as a JSON string, or already 1849 | * parsed to an object). According to the spec for indexed source maps, they 1850 | * have the following attributes: 1851 | * 1852 | * - version: Which version of the source map spec this map is following. 1853 | * - file: Optional. The generated file this source map is associated with. 1854 | * - sections: A list of section definitions. 1855 | * 1856 | * Each value under the "sections" field has two fields: 1857 | * - offset: The offset into the original specified at which this section 1858 | * begins to apply, defined as an object with a "line" and "column" 1859 | * field. 1860 | * - map: A source map definition. This source map could also be indexed, 1861 | * but doesn't have to be. 1862 | * 1863 | * Instead of the "map" field, it's also possible to have a "url" field 1864 | * specifying a URL to retrieve a source map from, but that's currently 1865 | * unsupported. 1866 | * 1867 | * Here's an example source map, taken from the source map spec[0], but 1868 | * modified to omit a section which uses the "url" field. 1869 | * 1870 | * { 1871 | * version : 3, 1872 | * file: "app.js", 1873 | * sections: [{ 1874 | * offset: {line:100, column:10}, 1875 | * map: { 1876 | * version : 3, 1877 | * file: "section.js", 1878 | * sources: ["foo.js", "bar.js"], 1879 | * names: ["src", "maps", "are", "fun"], 1880 | * mappings: "AAAA,E;;ABCDE;" 1881 | * } 1882 | * }], 1883 | * } 1884 | * 1885 | * The second parameter, if given, is a string whose value is the URL 1886 | * at which the source map was found. This URL is used to compute the 1887 | * sources array. 1888 | * 1889 | * [0]: https://docs.google.com/document/d/1U1RGAehQwRypUTovF1KRlpiOFze0b-_2gc6fAH0KY0k/edit#heading=h.535es3xeprgt 1890 | */ 1891 | function IndexedSourceMapConsumer(aSourceMap, aSourceMapURL) { 1892 | var sourceMap = aSourceMap; 1893 | if (typeof aSourceMap === 'string') { 1894 | sourceMap = util.parseSourceMapInput(aSourceMap); 1895 | } 1896 | 1897 | var version = util.getArg(sourceMap, 'version'); 1898 | var sections = util.getArg(sourceMap, 'sections'); 1899 | 1900 | if (version != this._version) { 1901 | throw new Error('Unsupported version: ' + version); 1902 | } 1903 | 1904 | this._sources = new ArraySet(); 1905 | this._names = new ArraySet(); 1906 | 1907 | var lastOffset = { 1908 | line: -1, 1909 | column: 0 1910 | }; 1911 | this._sections = sections.map(function (s) { 1912 | if (s.url) { 1913 | // The url field will require support for asynchronicity. 1914 | // See https://github.com/mozilla/source-map/issues/16 1915 | throw new Error('Support for url field in sections not implemented.'); 1916 | } 1917 | var offset = util.getArg(s, 'offset'); 1918 | var offsetLine = util.getArg(offset, 'line'); 1919 | var offsetColumn = util.getArg(offset, 'column'); 1920 | 1921 | if (offsetLine < lastOffset.line || 1922 | (offsetLine === lastOffset.line && offsetColumn < lastOffset.column)) { 1923 | throw new Error('Section offsets must be ordered and non-overlapping.'); 1924 | } 1925 | lastOffset = offset; 1926 | 1927 | return { 1928 | generatedOffset: { 1929 | // The offset fields are 0-based, but we use 1-based indices when 1930 | // encoding/decoding from VLQ. 1931 | generatedLine: offsetLine + 1, 1932 | generatedColumn: offsetColumn + 1 1933 | }, 1934 | consumer: new SourceMapConsumer(util.getArg(s, 'map'), aSourceMapURL) 1935 | } 1936 | }); 1937 | } 1938 | 1939 | IndexedSourceMapConsumer.prototype = Object.create(SourceMapConsumer.prototype); 1940 | IndexedSourceMapConsumer.prototype.constructor = SourceMapConsumer; 1941 | 1942 | /** 1943 | * The version of the source mapping spec that we are consuming. 1944 | */ 1945 | IndexedSourceMapConsumer.prototype._version = 3; 1946 | 1947 | /** 1948 | * The list of original sources. 1949 | */ 1950 | Object.defineProperty(IndexedSourceMapConsumer.prototype, 'sources', { 1951 | get: function () { 1952 | var sources = []; 1953 | for (var i = 0; i < this._sections.length; i++) { 1954 | for (var j = 0; j < this._sections[i].consumer.sources.length; j++) { 1955 | sources.push(this._sections[i].consumer.sources[j]); 1956 | } 1957 | } 1958 | return sources; 1959 | } 1960 | }); 1961 | 1962 | /** 1963 | * Returns the original source, line, and column information for the generated 1964 | * source's line and column positions provided. The only argument is an object 1965 | * with the following properties: 1966 | * 1967 | * - line: The line number in the generated source. The line number 1968 | * is 1-based. 1969 | * - column: The column number in the generated source. The column 1970 | * number is 0-based. 1971 | * 1972 | * and an object is returned with the following properties: 1973 | * 1974 | * - source: The original source file, or null. 1975 | * - line: The line number in the original source, or null. The 1976 | * line number is 1-based. 1977 | * - column: The column number in the original source, or null. The 1978 | * column number is 0-based. 1979 | * - name: The original identifier, or null. 1980 | */ 1981 | IndexedSourceMapConsumer.prototype.originalPositionFor = 1982 | function IndexedSourceMapConsumer_originalPositionFor(aArgs) { 1983 | var needle = { 1984 | generatedLine: util.getArg(aArgs, 'line'), 1985 | generatedColumn: util.getArg(aArgs, 'column') 1986 | }; 1987 | 1988 | // Find the section containing the generated position we're trying to map 1989 | // to an original position. 1990 | var sectionIndex = binarySearch.search(needle, this._sections, 1991 | function(needle, section) { 1992 | var cmp = needle.generatedLine - section.generatedOffset.generatedLine; 1993 | if (cmp) { 1994 | return cmp; 1995 | } 1996 | 1997 | return (needle.generatedColumn - 1998 | section.generatedOffset.generatedColumn); 1999 | }); 2000 | var section = this._sections[sectionIndex]; 2001 | 2002 | if (!section) { 2003 | return { 2004 | source: null, 2005 | line: null, 2006 | column: null, 2007 | name: null 2008 | }; 2009 | } 2010 | 2011 | return section.consumer.originalPositionFor({ 2012 | line: needle.generatedLine - 2013 | (section.generatedOffset.generatedLine - 1), 2014 | column: needle.generatedColumn - 2015 | (section.generatedOffset.generatedLine === needle.generatedLine 2016 | ? section.generatedOffset.generatedColumn - 1 2017 | : 0), 2018 | bias: aArgs.bias 2019 | }); 2020 | }; 2021 | 2022 | /** 2023 | * Return true if we have the source content for every source in the source 2024 | * map, false otherwise. 2025 | */ 2026 | IndexedSourceMapConsumer.prototype.hasContentsOfAllSources = 2027 | function IndexedSourceMapConsumer_hasContentsOfAllSources() { 2028 | return this._sections.every(function (s) { 2029 | return s.consumer.hasContentsOfAllSources(); 2030 | }); 2031 | }; 2032 | 2033 | /** 2034 | * Returns the original source content. The only argument is the url of the 2035 | * original source file. Returns null if no original source content is 2036 | * available. 2037 | */ 2038 | IndexedSourceMapConsumer.prototype.sourceContentFor = 2039 | function IndexedSourceMapConsumer_sourceContentFor(aSource, nullOnMissing) { 2040 | for (var i = 0; i < this._sections.length; i++) { 2041 | var section = this._sections[i]; 2042 | 2043 | var content = section.consumer.sourceContentFor(aSource, true); 2044 | if (content) { 2045 | return content; 2046 | } 2047 | } 2048 | if (nullOnMissing) { 2049 | return null; 2050 | } 2051 | else { 2052 | throw new Error('"' + aSource + '" is not in the SourceMap.'); 2053 | } 2054 | }; 2055 | 2056 | /** 2057 | * Returns the generated line and column information for the original source, 2058 | * line, and column positions provided. The only argument is an object with 2059 | * the following properties: 2060 | * 2061 | * - source: The filename of the original source. 2062 | * - line: The line number in the original source. The line number 2063 | * is 1-based. 2064 | * - column: The column number in the original source. The column 2065 | * number is 0-based. 2066 | * 2067 | * and an object is returned with the following properties: 2068 | * 2069 | * - line: The line number in the generated source, or null. The 2070 | * line number is 1-based. 2071 | * - column: The column number in the generated source, or null. 2072 | * The column number is 0-based. 2073 | */ 2074 | IndexedSourceMapConsumer.prototype.generatedPositionFor = 2075 | function IndexedSourceMapConsumer_generatedPositionFor(aArgs) { 2076 | for (var i = 0; i < this._sections.length; i++) { 2077 | var section = this._sections[i]; 2078 | 2079 | // Only consider this section if the requested source is in the list of 2080 | // sources of the consumer. 2081 | if (section.consumer._findSourceIndex(util.getArg(aArgs, 'source')) === -1) { 2082 | continue; 2083 | } 2084 | var generatedPosition = section.consumer.generatedPositionFor(aArgs); 2085 | if (generatedPosition) { 2086 | var ret = { 2087 | line: generatedPosition.line + 2088 | (section.generatedOffset.generatedLine - 1), 2089 | column: generatedPosition.column + 2090 | (section.generatedOffset.generatedLine === generatedPosition.line 2091 | ? section.generatedOffset.generatedColumn - 1 2092 | : 0) 2093 | }; 2094 | return ret; 2095 | } 2096 | } 2097 | 2098 | return { 2099 | line: null, 2100 | column: null 2101 | }; 2102 | }; 2103 | 2104 | /** 2105 | * Parse the mappings in a string in to a data structure which we can easily 2106 | * query (the ordered arrays in the `this.__generatedMappings` and 2107 | * `this.__originalMappings` properties). 2108 | */ 2109 | IndexedSourceMapConsumer.prototype._parseMappings = 2110 | function IndexedSourceMapConsumer_parseMappings(aStr, aSourceRoot) { 2111 | this.__generatedMappings = []; 2112 | this.__originalMappings = []; 2113 | for (var i = 0; i < this._sections.length; i++) { 2114 | var section = this._sections[i]; 2115 | var sectionMappings = section.consumer._generatedMappings; 2116 | for (var j = 0; j < sectionMappings.length; j++) { 2117 | var mapping = sectionMappings[j]; 2118 | 2119 | var source = section.consumer._sources.at(mapping.source); 2120 | source = util.computeSourceURL(section.consumer.sourceRoot, source, this._sourceMapURL); 2121 | this._sources.add(source); 2122 | source = this._sources.indexOf(source); 2123 | 2124 | var name = null; 2125 | if (mapping.name) { 2126 | name = section.consumer._names.at(mapping.name); 2127 | this._names.add(name); 2128 | name = this._names.indexOf(name); 2129 | } 2130 | 2131 | // The mappings coming from the consumer for the section have 2132 | // generated positions relative to the start of the section, so we 2133 | // need to offset them to be relative to the start of the concatenated 2134 | // generated file. 2135 | var adjustedMapping = { 2136 | source: source, 2137 | generatedLine: mapping.generatedLine + 2138 | (section.generatedOffset.generatedLine - 1), 2139 | generatedColumn: mapping.generatedColumn + 2140 | (section.generatedOffset.generatedLine === mapping.generatedLine 2141 | ? section.generatedOffset.generatedColumn - 1 2142 | : 0), 2143 | originalLine: mapping.originalLine, 2144 | originalColumn: mapping.originalColumn, 2145 | name: name 2146 | }; 2147 | 2148 | this.__generatedMappings.push(adjustedMapping); 2149 | if (typeof adjustedMapping.originalLine === 'number') { 2150 | this.__originalMappings.push(adjustedMapping); 2151 | } 2152 | } 2153 | } 2154 | 2155 | quickSort(this.__generatedMappings, util.compareByGeneratedPositionsDeflated); 2156 | quickSort(this.__originalMappings, util.compareByOriginalPositions); 2157 | }; 2158 | 2159 | exports.IndexedSourceMapConsumer = IndexedSourceMapConsumer; 2160 | 2161 | 2162 | /***/ }), 2163 | 2164 | /***/ 341: 2165 | /***/ (function(__unusedmodule, exports, __webpack_require__) { 2166 | 2167 | /* -*- Mode: js; js-indent-level: 2; -*- */ 2168 | /* 2169 | * Copyright 2011 Mozilla Foundation and contributors 2170 | * Licensed under the New BSD license. See LICENSE or: 2171 | * http://opensource.org/licenses/BSD-3-Clause 2172 | */ 2173 | 2174 | var base64VLQ = __webpack_require__(215); 2175 | var util = __webpack_require__(983); 2176 | var ArraySet = __webpack_require__(837).ArraySet; 2177 | var MappingList = __webpack_require__(740).MappingList; 2178 | 2179 | /** 2180 | * An instance of the SourceMapGenerator represents a source map which is 2181 | * being built incrementally. You may pass an object with the following 2182 | * properties: 2183 | * 2184 | * - file: The filename of the generated source. 2185 | * - sourceRoot: A root for all relative URLs in this source map. 2186 | */ 2187 | function SourceMapGenerator(aArgs) { 2188 | if (!aArgs) { 2189 | aArgs = {}; 2190 | } 2191 | this._file = util.getArg(aArgs, 'file', null); 2192 | this._sourceRoot = util.getArg(aArgs, 'sourceRoot', null); 2193 | this._skipValidation = util.getArg(aArgs, 'skipValidation', false); 2194 | this._sources = new ArraySet(); 2195 | this._names = new ArraySet(); 2196 | this._mappings = new MappingList(); 2197 | this._sourcesContents = null; 2198 | } 2199 | 2200 | SourceMapGenerator.prototype._version = 3; 2201 | 2202 | /** 2203 | * Creates a new SourceMapGenerator based on a SourceMapConsumer 2204 | * 2205 | * @param aSourceMapConsumer The SourceMap. 2206 | */ 2207 | SourceMapGenerator.fromSourceMap = 2208 | function SourceMapGenerator_fromSourceMap(aSourceMapConsumer) { 2209 | var sourceRoot = aSourceMapConsumer.sourceRoot; 2210 | var generator = new SourceMapGenerator({ 2211 | file: aSourceMapConsumer.file, 2212 | sourceRoot: sourceRoot 2213 | }); 2214 | aSourceMapConsumer.eachMapping(function (mapping) { 2215 | var newMapping = { 2216 | generated: { 2217 | line: mapping.generatedLine, 2218 | column: mapping.generatedColumn 2219 | } 2220 | }; 2221 | 2222 | if (mapping.source != null) { 2223 | newMapping.source = mapping.source; 2224 | if (sourceRoot != null) { 2225 | newMapping.source = util.relative(sourceRoot, newMapping.source); 2226 | } 2227 | 2228 | newMapping.original = { 2229 | line: mapping.originalLine, 2230 | column: mapping.originalColumn 2231 | }; 2232 | 2233 | if (mapping.name != null) { 2234 | newMapping.name = mapping.name; 2235 | } 2236 | } 2237 | 2238 | generator.addMapping(newMapping); 2239 | }); 2240 | aSourceMapConsumer.sources.forEach(function (sourceFile) { 2241 | var sourceRelative = sourceFile; 2242 | if (sourceRoot !== null) { 2243 | sourceRelative = util.relative(sourceRoot, sourceFile); 2244 | } 2245 | 2246 | if (!generator._sources.has(sourceRelative)) { 2247 | generator._sources.add(sourceRelative); 2248 | } 2249 | 2250 | var content = aSourceMapConsumer.sourceContentFor(sourceFile); 2251 | if (content != null) { 2252 | generator.setSourceContent(sourceFile, content); 2253 | } 2254 | }); 2255 | return generator; 2256 | }; 2257 | 2258 | /** 2259 | * Add a single mapping from original source line and column to the generated 2260 | * source's line and column for this source map being created. The mapping 2261 | * object should have the following properties: 2262 | * 2263 | * - generated: An object with the generated line and column positions. 2264 | * - original: An object with the original line and column positions. 2265 | * - source: The original source file (relative to the sourceRoot). 2266 | * - name: An optional original token name for this mapping. 2267 | */ 2268 | SourceMapGenerator.prototype.addMapping = 2269 | function SourceMapGenerator_addMapping(aArgs) { 2270 | var generated = util.getArg(aArgs, 'generated'); 2271 | var original = util.getArg(aArgs, 'original', null); 2272 | var source = util.getArg(aArgs, 'source', null); 2273 | var name = util.getArg(aArgs, 'name', null); 2274 | 2275 | if (!this._skipValidation) { 2276 | this._validateMapping(generated, original, source, name); 2277 | } 2278 | 2279 | if (source != null) { 2280 | source = String(source); 2281 | if (!this._sources.has(source)) { 2282 | this._sources.add(source); 2283 | } 2284 | } 2285 | 2286 | if (name != null) { 2287 | name = String(name); 2288 | if (!this._names.has(name)) { 2289 | this._names.add(name); 2290 | } 2291 | } 2292 | 2293 | this._mappings.add({ 2294 | generatedLine: generated.line, 2295 | generatedColumn: generated.column, 2296 | originalLine: original != null && original.line, 2297 | originalColumn: original != null && original.column, 2298 | source: source, 2299 | name: name 2300 | }); 2301 | }; 2302 | 2303 | /** 2304 | * Set the source content for a source file. 2305 | */ 2306 | SourceMapGenerator.prototype.setSourceContent = 2307 | function SourceMapGenerator_setSourceContent(aSourceFile, aSourceContent) { 2308 | var source = aSourceFile; 2309 | if (this._sourceRoot != null) { 2310 | source = util.relative(this._sourceRoot, source); 2311 | } 2312 | 2313 | if (aSourceContent != null) { 2314 | // Add the source content to the _sourcesContents map. 2315 | // Create a new _sourcesContents map if the property is null. 2316 | if (!this._sourcesContents) { 2317 | this._sourcesContents = Object.create(null); 2318 | } 2319 | this._sourcesContents[util.toSetString(source)] = aSourceContent; 2320 | } else if (this._sourcesContents) { 2321 | // Remove the source file from the _sourcesContents map. 2322 | // If the _sourcesContents map is empty, set the property to null. 2323 | delete this._sourcesContents[util.toSetString(source)]; 2324 | if (Object.keys(this._sourcesContents).length === 0) { 2325 | this._sourcesContents = null; 2326 | } 2327 | } 2328 | }; 2329 | 2330 | /** 2331 | * Applies the mappings of a sub-source-map for a specific source file to the 2332 | * source map being generated. Each mapping to the supplied source file is 2333 | * rewritten using the supplied source map. Note: The resolution for the 2334 | * resulting mappings is the minimium of this map and the supplied map. 2335 | * 2336 | * @param aSourceMapConsumer The source map to be applied. 2337 | * @param aSourceFile Optional. The filename of the source file. 2338 | * If omitted, SourceMapConsumer's file property will be used. 2339 | * @param aSourceMapPath Optional. The dirname of the path to the source map 2340 | * to be applied. If relative, it is relative to the SourceMapConsumer. 2341 | * This parameter is needed when the two source maps aren't in the same 2342 | * directory, and the source map to be applied contains relative source 2343 | * paths. If so, those relative source paths need to be rewritten 2344 | * relative to the SourceMapGenerator. 2345 | */ 2346 | SourceMapGenerator.prototype.applySourceMap = 2347 | function SourceMapGenerator_applySourceMap(aSourceMapConsumer, aSourceFile, aSourceMapPath) { 2348 | var sourceFile = aSourceFile; 2349 | // If aSourceFile is omitted, we will use the file property of the SourceMap 2350 | if (aSourceFile == null) { 2351 | if (aSourceMapConsumer.file == null) { 2352 | throw new Error( 2353 | 'SourceMapGenerator.prototype.applySourceMap requires either an explicit source file, ' + 2354 | 'or the source map\'s "file" property. Both were omitted.' 2355 | ); 2356 | } 2357 | sourceFile = aSourceMapConsumer.file; 2358 | } 2359 | var sourceRoot = this._sourceRoot; 2360 | // Make "sourceFile" relative if an absolute Url is passed. 2361 | if (sourceRoot != null) { 2362 | sourceFile = util.relative(sourceRoot, sourceFile); 2363 | } 2364 | // Applying the SourceMap can add and remove items from the sources and 2365 | // the names array. 2366 | var newSources = new ArraySet(); 2367 | var newNames = new ArraySet(); 2368 | 2369 | // Find mappings for the "sourceFile" 2370 | this._mappings.unsortedForEach(function (mapping) { 2371 | if (mapping.source === sourceFile && mapping.originalLine != null) { 2372 | // Check if it can be mapped by the source map, then update the mapping. 2373 | var original = aSourceMapConsumer.originalPositionFor({ 2374 | line: mapping.originalLine, 2375 | column: mapping.originalColumn 2376 | }); 2377 | if (original.source != null) { 2378 | // Copy mapping 2379 | mapping.source = original.source; 2380 | if (aSourceMapPath != null) { 2381 | mapping.source = util.join(aSourceMapPath, mapping.source) 2382 | } 2383 | if (sourceRoot != null) { 2384 | mapping.source = util.relative(sourceRoot, mapping.source); 2385 | } 2386 | mapping.originalLine = original.line; 2387 | mapping.originalColumn = original.column; 2388 | if (original.name != null) { 2389 | mapping.name = original.name; 2390 | } 2391 | } 2392 | } 2393 | 2394 | var source = mapping.source; 2395 | if (source != null && !newSources.has(source)) { 2396 | newSources.add(source); 2397 | } 2398 | 2399 | var name = mapping.name; 2400 | if (name != null && !newNames.has(name)) { 2401 | newNames.add(name); 2402 | } 2403 | 2404 | }, this); 2405 | this._sources = newSources; 2406 | this._names = newNames; 2407 | 2408 | // Copy sourcesContents of applied map. 2409 | aSourceMapConsumer.sources.forEach(function (sourceFile) { 2410 | var content = aSourceMapConsumer.sourceContentFor(sourceFile); 2411 | if (content != null) { 2412 | if (aSourceMapPath != null) { 2413 | sourceFile = util.join(aSourceMapPath, sourceFile); 2414 | } 2415 | if (sourceRoot != null) { 2416 | sourceFile = util.relative(sourceRoot, sourceFile); 2417 | } 2418 | this.setSourceContent(sourceFile, content); 2419 | } 2420 | }, this); 2421 | }; 2422 | 2423 | /** 2424 | * A mapping can have one of the three levels of data: 2425 | * 2426 | * 1. Just the generated position. 2427 | * 2. The Generated position, original position, and original source. 2428 | * 3. Generated and original position, original source, as well as a name 2429 | * token. 2430 | * 2431 | * To maintain consistency, we validate that any new mapping being added falls 2432 | * in to one of these categories. 2433 | */ 2434 | SourceMapGenerator.prototype._validateMapping = 2435 | function SourceMapGenerator_validateMapping(aGenerated, aOriginal, aSource, 2436 | aName) { 2437 | // When aOriginal is truthy but has empty values for .line and .column, 2438 | // it is most likely a programmer error. In this case we throw a very 2439 | // specific error message to try to guide them the right way. 2440 | // For example: https://github.com/Polymer/polymer-bundler/pull/519 2441 | if (aOriginal && typeof aOriginal.line !== 'number' && typeof aOriginal.column !== 'number') { 2442 | throw new Error( 2443 | 'original.line and original.column are not numbers -- you probably meant to omit ' + 2444 | 'the original mapping entirely and only map the generated position. If so, pass ' + 2445 | 'null for the original mapping instead of an object with empty or null values.' 2446 | ); 2447 | } 2448 | 2449 | if (aGenerated && 'line' in aGenerated && 'column' in aGenerated 2450 | && aGenerated.line > 0 && aGenerated.column >= 0 2451 | && !aOriginal && !aSource && !aName) { 2452 | // Case 1. 2453 | return; 2454 | } 2455 | else if (aGenerated && 'line' in aGenerated && 'column' in aGenerated 2456 | && aOriginal && 'line' in aOriginal && 'column' in aOriginal 2457 | && aGenerated.line > 0 && aGenerated.column >= 0 2458 | && aOriginal.line > 0 && aOriginal.column >= 0 2459 | && aSource) { 2460 | // Cases 2 and 3. 2461 | return; 2462 | } 2463 | else { 2464 | throw new Error('Invalid mapping: ' + JSON.stringify({ 2465 | generated: aGenerated, 2466 | source: aSource, 2467 | original: aOriginal, 2468 | name: aName 2469 | })); 2470 | } 2471 | }; 2472 | 2473 | /** 2474 | * Serialize the accumulated mappings in to the stream of base 64 VLQs 2475 | * specified by the source map format. 2476 | */ 2477 | SourceMapGenerator.prototype._serializeMappings = 2478 | function SourceMapGenerator_serializeMappings() { 2479 | var previousGeneratedColumn = 0; 2480 | var previousGeneratedLine = 1; 2481 | var previousOriginalColumn = 0; 2482 | var previousOriginalLine = 0; 2483 | var previousName = 0; 2484 | var previousSource = 0; 2485 | var result = ''; 2486 | var next; 2487 | var mapping; 2488 | var nameIdx; 2489 | var sourceIdx; 2490 | 2491 | var mappings = this._mappings.toArray(); 2492 | for (var i = 0, len = mappings.length; i < len; i++) { 2493 | mapping = mappings[i]; 2494 | next = '' 2495 | 2496 | if (mapping.generatedLine !== previousGeneratedLine) { 2497 | previousGeneratedColumn = 0; 2498 | while (mapping.generatedLine !== previousGeneratedLine) { 2499 | next += ';'; 2500 | previousGeneratedLine++; 2501 | } 2502 | } 2503 | else { 2504 | if (i > 0) { 2505 | if (!util.compareByGeneratedPositionsInflated(mapping, mappings[i - 1])) { 2506 | continue; 2507 | } 2508 | next += ','; 2509 | } 2510 | } 2511 | 2512 | next += base64VLQ.encode(mapping.generatedColumn 2513 | - previousGeneratedColumn); 2514 | previousGeneratedColumn = mapping.generatedColumn; 2515 | 2516 | if (mapping.source != null) { 2517 | sourceIdx = this._sources.indexOf(mapping.source); 2518 | next += base64VLQ.encode(sourceIdx - previousSource); 2519 | previousSource = sourceIdx; 2520 | 2521 | // lines are stored 0-based in SourceMap spec version 3 2522 | next += base64VLQ.encode(mapping.originalLine - 1 2523 | - previousOriginalLine); 2524 | previousOriginalLine = mapping.originalLine - 1; 2525 | 2526 | next += base64VLQ.encode(mapping.originalColumn 2527 | - previousOriginalColumn); 2528 | previousOriginalColumn = mapping.originalColumn; 2529 | 2530 | if (mapping.name != null) { 2531 | nameIdx = this._names.indexOf(mapping.name); 2532 | next += base64VLQ.encode(nameIdx - previousName); 2533 | previousName = nameIdx; 2534 | } 2535 | } 2536 | 2537 | result += next; 2538 | } 2539 | 2540 | return result; 2541 | }; 2542 | 2543 | SourceMapGenerator.prototype._generateSourcesContent = 2544 | function SourceMapGenerator_generateSourcesContent(aSources, aSourceRoot) { 2545 | return aSources.map(function (source) { 2546 | if (!this._sourcesContents) { 2547 | return null; 2548 | } 2549 | if (aSourceRoot != null) { 2550 | source = util.relative(aSourceRoot, source); 2551 | } 2552 | var key = util.toSetString(source); 2553 | return Object.prototype.hasOwnProperty.call(this._sourcesContents, key) 2554 | ? this._sourcesContents[key] 2555 | : null; 2556 | }, this); 2557 | }; 2558 | 2559 | /** 2560 | * Externalize the source map. 2561 | */ 2562 | SourceMapGenerator.prototype.toJSON = 2563 | function SourceMapGenerator_toJSON() { 2564 | var map = { 2565 | version: this._version, 2566 | sources: this._sources.toArray(), 2567 | names: this._names.toArray(), 2568 | mappings: this._serializeMappings() 2569 | }; 2570 | if (this._file != null) { 2571 | map.file = this._file; 2572 | } 2573 | if (this._sourceRoot != null) { 2574 | map.sourceRoot = this._sourceRoot; 2575 | } 2576 | if (this._sourcesContents) { 2577 | map.sourcesContent = this._generateSourcesContent(map.sources, map.sourceRoot); 2578 | } 2579 | 2580 | return map; 2581 | }; 2582 | 2583 | /** 2584 | * Render the source map being generated to a string. 2585 | */ 2586 | SourceMapGenerator.prototype.toString = 2587 | function SourceMapGenerator_toString() { 2588 | return JSON.stringify(this.toJSON()); 2589 | }; 2590 | 2591 | exports.SourceMapGenerator = SourceMapGenerator; 2592 | 2593 | 2594 | /***/ }), 2595 | 2596 | /***/ 537: 2597 | /***/ (function(__unusedmodule, exports) { 2598 | 2599 | /* -*- Mode: js; js-indent-level: 2; -*- */ 2600 | /* 2601 | * Copyright 2011 Mozilla Foundation and contributors 2602 | * Licensed under the New BSD license. See LICENSE or: 2603 | * http://opensource.org/licenses/BSD-3-Clause 2604 | */ 2605 | 2606 | var intToCharMap = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'.split(''); 2607 | 2608 | /** 2609 | * Encode an integer in the range of 0 to 63 to a single base 64 digit. 2610 | */ 2611 | exports.encode = function (number) { 2612 | if (0 <= number && number < intToCharMap.length) { 2613 | return intToCharMap[number]; 2614 | } 2615 | throw new TypeError("Must be between 0 and 63: " + number); 2616 | }; 2617 | 2618 | /** 2619 | * Decode a single base 64 character code digit to an integer. Returns -1 on 2620 | * failure. 2621 | */ 2622 | exports.decode = function (charCode) { 2623 | var bigA = 65; // 'A' 2624 | var bigZ = 90; // 'Z' 2625 | 2626 | var littleA = 97; // 'a' 2627 | var littleZ = 122; // 'z' 2628 | 2629 | var zero = 48; // '0' 2630 | var nine = 57; // '9' 2631 | 2632 | var plus = 43; // '+' 2633 | var slash = 47; // '/' 2634 | 2635 | var littleOffset = 26; 2636 | var numberOffset = 52; 2637 | 2638 | // 0 - 25: ABCDEFGHIJKLMNOPQRSTUVWXYZ 2639 | if (bigA <= charCode && charCode <= bigZ) { 2640 | return (charCode - bigA); 2641 | } 2642 | 2643 | // 26 - 51: abcdefghijklmnopqrstuvwxyz 2644 | if (littleA <= charCode && charCode <= littleZ) { 2645 | return (charCode - littleA + littleOffset); 2646 | } 2647 | 2648 | // 52 - 61: 0123456789 2649 | if (zero <= charCode && charCode <= nine) { 2650 | return (charCode - zero + numberOffset); 2651 | } 2652 | 2653 | // 62: + 2654 | if (charCode == plus) { 2655 | return 62; 2656 | } 2657 | 2658 | // 63: / 2659 | if (charCode == slash) { 2660 | return 63; 2661 | } 2662 | 2663 | // Invalid base64 digit. 2664 | return -1; 2665 | }; 2666 | 2667 | 2668 | /***/ }), 2669 | 2670 | /***/ 596: 2671 | /***/ (function(__unusedmodule, exports, __webpack_require__) { 2672 | 2673 | /* 2674 | * Copyright 2009-2011 Mozilla Foundation and contributors 2675 | * Licensed under the New BSD license. See LICENSE.txt or: 2676 | * http://opensource.org/licenses/BSD-3-Clause 2677 | */ 2678 | exports.SourceMapGenerator = __webpack_require__(341).SourceMapGenerator; 2679 | exports.SourceMapConsumer = __webpack_require__(327).SourceMapConsumer; 2680 | exports.SourceNode = __webpack_require__(990).SourceNode; 2681 | 2682 | 2683 | /***/ }), 2684 | 2685 | /***/ 622: 2686 | /***/ (function(module) { 2687 | 2688 | module.exports = require("path"); 2689 | 2690 | /***/ }), 2691 | 2692 | /***/ 645: 2693 | /***/ (function(__unusedmodule, __unusedexports, __webpack_require__) { 2694 | 2695 | __webpack_require__(284).install(); 2696 | 2697 | 2698 | /***/ }), 2699 | 2700 | /***/ 650: 2701 | /***/ (function(module) { 2702 | 2703 | var toString = Object.prototype.toString 2704 | 2705 | var isModern = ( 2706 | typeof Buffer.alloc === 'function' && 2707 | typeof Buffer.allocUnsafe === 'function' && 2708 | typeof Buffer.from === 'function' 2709 | ) 2710 | 2711 | function isArrayBuffer (input) { 2712 | return toString.call(input).slice(8, -1) === 'ArrayBuffer' 2713 | } 2714 | 2715 | function fromArrayBuffer (obj, byteOffset, length) { 2716 | byteOffset >>>= 0 2717 | 2718 | var maxLength = obj.byteLength - byteOffset 2719 | 2720 | if (maxLength < 0) { 2721 | throw new RangeError("'offset' is out of bounds") 2722 | } 2723 | 2724 | if (length === undefined) { 2725 | length = maxLength 2726 | } else { 2727 | length >>>= 0 2728 | 2729 | if (length > maxLength) { 2730 | throw new RangeError("'length' is out of bounds") 2731 | } 2732 | } 2733 | 2734 | return isModern 2735 | ? Buffer.from(obj.slice(byteOffset, byteOffset + length)) 2736 | : new Buffer(new Uint8Array(obj.slice(byteOffset, byteOffset + length))) 2737 | } 2738 | 2739 | function fromString (string, encoding) { 2740 | if (typeof encoding !== 'string' || encoding === '') { 2741 | encoding = 'utf8' 2742 | } 2743 | 2744 | if (!Buffer.isEncoding(encoding)) { 2745 | throw new TypeError('"encoding" must be a valid string encoding') 2746 | } 2747 | 2748 | return isModern 2749 | ? Buffer.from(string, encoding) 2750 | : new Buffer(string, encoding) 2751 | } 2752 | 2753 | function bufferFrom (value, encodingOrOffset, length) { 2754 | if (typeof value === 'number') { 2755 | throw new TypeError('"value" argument must not be a number') 2756 | } 2757 | 2758 | if (isArrayBuffer(value)) { 2759 | return fromArrayBuffer(value, encodingOrOffset, length) 2760 | } 2761 | 2762 | if (typeof value === 'string') { 2763 | return fromString(value, encodingOrOffset) 2764 | } 2765 | 2766 | return isModern 2767 | ? Buffer.from(value) 2768 | : new Buffer(value) 2769 | } 2770 | 2771 | module.exports = bufferFrom 2772 | 2773 | 2774 | /***/ }), 2775 | 2776 | /***/ 740: 2777 | /***/ (function(__unusedmodule, exports, __webpack_require__) { 2778 | 2779 | /* -*- Mode: js; js-indent-level: 2; -*- */ 2780 | /* 2781 | * Copyright 2014 Mozilla Foundation and contributors 2782 | * Licensed under the New BSD license. See LICENSE or: 2783 | * http://opensource.org/licenses/BSD-3-Clause 2784 | */ 2785 | 2786 | var util = __webpack_require__(983); 2787 | 2788 | /** 2789 | * Determine whether mappingB is after mappingA with respect to generated 2790 | * position. 2791 | */ 2792 | function generatedPositionAfter(mappingA, mappingB) { 2793 | // Optimized for most common case 2794 | var lineA = mappingA.generatedLine; 2795 | var lineB = mappingB.generatedLine; 2796 | var columnA = mappingA.generatedColumn; 2797 | var columnB = mappingB.generatedColumn; 2798 | return lineB > lineA || lineB == lineA && columnB >= columnA || 2799 | util.compareByGeneratedPositionsInflated(mappingA, mappingB) <= 0; 2800 | } 2801 | 2802 | /** 2803 | * A data structure to provide a sorted view of accumulated mappings in a 2804 | * performance conscious manner. It trades a neglibable overhead in general 2805 | * case for a large speedup in case of mappings being added in order. 2806 | */ 2807 | function MappingList() { 2808 | this._array = []; 2809 | this._sorted = true; 2810 | // Serves as infimum 2811 | this._last = {generatedLine: -1, generatedColumn: 0}; 2812 | } 2813 | 2814 | /** 2815 | * Iterate through internal items. This method takes the same arguments that 2816 | * `Array.prototype.forEach` takes. 2817 | * 2818 | * NOTE: The order of the mappings is NOT guaranteed. 2819 | */ 2820 | MappingList.prototype.unsortedForEach = 2821 | function MappingList_forEach(aCallback, aThisArg) { 2822 | this._array.forEach(aCallback, aThisArg); 2823 | }; 2824 | 2825 | /** 2826 | * Add the given source mapping. 2827 | * 2828 | * @param Object aMapping 2829 | */ 2830 | MappingList.prototype.add = function MappingList_add(aMapping) { 2831 | if (generatedPositionAfter(this._last, aMapping)) { 2832 | this._last = aMapping; 2833 | this._array.push(aMapping); 2834 | } else { 2835 | this._sorted = false; 2836 | this._array.push(aMapping); 2837 | } 2838 | }; 2839 | 2840 | /** 2841 | * Returns the flat, sorted array of mappings. The mappings are sorted by 2842 | * generated position. 2843 | * 2844 | * WARNING: This method returns internal data without copying, for 2845 | * performance. The return value must NOT be mutated, and should be treated as 2846 | * an immutable borrow. If you want to take ownership, you must make your own 2847 | * copy. 2848 | */ 2849 | MappingList.prototype.toArray = function MappingList_toArray() { 2850 | if (!this._sorted) { 2851 | this._array.sort(util.compareByGeneratedPositionsInflated); 2852 | this._sorted = true; 2853 | } 2854 | return this._array; 2855 | }; 2856 | 2857 | exports.MappingList = MappingList; 2858 | 2859 | 2860 | /***/ }), 2861 | 2862 | /***/ 747: 2863 | /***/ (function(module) { 2864 | 2865 | module.exports = require("fs"); 2866 | 2867 | /***/ }), 2868 | 2869 | /***/ 837: 2870 | /***/ (function(__unusedmodule, exports, __webpack_require__) { 2871 | 2872 | /* -*- Mode: js; js-indent-level: 2; -*- */ 2873 | /* 2874 | * Copyright 2011 Mozilla Foundation and contributors 2875 | * Licensed under the New BSD license. See LICENSE or: 2876 | * http://opensource.org/licenses/BSD-3-Clause 2877 | */ 2878 | 2879 | var util = __webpack_require__(983); 2880 | var has = Object.prototype.hasOwnProperty; 2881 | var hasNativeMap = typeof Map !== "undefined"; 2882 | 2883 | /** 2884 | * A data structure which is a combination of an array and a set. Adding a new 2885 | * member is O(1), testing for membership is O(1), and finding the index of an 2886 | * element is O(1). Removing elements from the set is not supported. Only 2887 | * strings are supported for membership. 2888 | */ 2889 | function ArraySet() { 2890 | this._array = []; 2891 | this._set = hasNativeMap ? new Map() : Object.create(null); 2892 | } 2893 | 2894 | /** 2895 | * Static method for creating ArraySet instances from an existing array. 2896 | */ 2897 | ArraySet.fromArray = function ArraySet_fromArray(aArray, aAllowDuplicates) { 2898 | var set = new ArraySet(); 2899 | for (var i = 0, len = aArray.length; i < len; i++) { 2900 | set.add(aArray[i], aAllowDuplicates); 2901 | } 2902 | return set; 2903 | }; 2904 | 2905 | /** 2906 | * Return how many unique items are in this ArraySet. If duplicates have been 2907 | * added, than those do not count towards the size. 2908 | * 2909 | * @returns Number 2910 | */ 2911 | ArraySet.prototype.size = function ArraySet_size() { 2912 | return hasNativeMap ? this._set.size : Object.getOwnPropertyNames(this._set).length; 2913 | }; 2914 | 2915 | /** 2916 | * Add the given string to this set. 2917 | * 2918 | * @param String aStr 2919 | */ 2920 | ArraySet.prototype.add = function ArraySet_add(aStr, aAllowDuplicates) { 2921 | var sStr = hasNativeMap ? aStr : util.toSetString(aStr); 2922 | var isDuplicate = hasNativeMap ? this.has(aStr) : has.call(this._set, sStr); 2923 | var idx = this._array.length; 2924 | if (!isDuplicate || aAllowDuplicates) { 2925 | this._array.push(aStr); 2926 | } 2927 | if (!isDuplicate) { 2928 | if (hasNativeMap) { 2929 | this._set.set(aStr, idx); 2930 | } else { 2931 | this._set[sStr] = idx; 2932 | } 2933 | } 2934 | }; 2935 | 2936 | /** 2937 | * Is the given string a member of this set? 2938 | * 2939 | * @param String aStr 2940 | */ 2941 | ArraySet.prototype.has = function ArraySet_has(aStr) { 2942 | if (hasNativeMap) { 2943 | return this._set.has(aStr); 2944 | } else { 2945 | var sStr = util.toSetString(aStr); 2946 | return has.call(this._set, sStr); 2947 | } 2948 | }; 2949 | 2950 | /** 2951 | * What is the index of the given string in the array? 2952 | * 2953 | * @param String aStr 2954 | */ 2955 | ArraySet.prototype.indexOf = function ArraySet_indexOf(aStr) { 2956 | if (hasNativeMap) { 2957 | var idx = this._set.get(aStr); 2958 | if (idx >= 0) { 2959 | return idx; 2960 | } 2961 | } else { 2962 | var sStr = util.toSetString(aStr); 2963 | if (has.call(this._set, sStr)) { 2964 | return this._set[sStr]; 2965 | } 2966 | } 2967 | 2968 | throw new Error('"' + aStr + '" is not in the set.'); 2969 | }; 2970 | 2971 | /** 2972 | * What is the element at the given index? 2973 | * 2974 | * @param Number aIdx 2975 | */ 2976 | ArraySet.prototype.at = function ArraySet_at(aIdx) { 2977 | if (aIdx >= 0 && aIdx < this._array.length) { 2978 | return this._array[aIdx]; 2979 | } 2980 | throw new Error('No element indexed by ' + aIdx); 2981 | }; 2982 | 2983 | /** 2984 | * Returns the array representation of this set (which has the proper indices 2985 | * indicated by indexOf). Note that this is a copy of the internal array used 2986 | * for storing the members so that no one can mess with internal state. 2987 | */ 2988 | ArraySet.prototype.toArray = function ArraySet_toArray() { 2989 | return this._array.slice(); 2990 | }; 2991 | 2992 | exports.ArraySet = ArraySet; 2993 | 2994 | 2995 | /***/ }), 2996 | 2997 | /***/ 983: 2998 | /***/ (function(__unusedmodule, exports) { 2999 | 3000 | /* -*- Mode: js; js-indent-level: 2; -*- */ 3001 | /* 3002 | * Copyright 2011 Mozilla Foundation and contributors 3003 | * Licensed under the New BSD license. See LICENSE or: 3004 | * http://opensource.org/licenses/BSD-3-Clause 3005 | */ 3006 | 3007 | /** 3008 | * This is a helper function for getting values from parameter/options 3009 | * objects. 3010 | * 3011 | * @param args The object we are extracting values from 3012 | * @param name The name of the property we are getting. 3013 | * @param defaultValue An optional value to return if the property is missing 3014 | * from the object. If this is not specified and the property is missing, an 3015 | * error will be thrown. 3016 | */ 3017 | function getArg(aArgs, aName, aDefaultValue) { 3018 | if (aName in aArgs) { 3019 | return aArgs[aName]; 3020 | } else if (arguments.length === 3) { 3021 | return aDefaultValue; 3022 | } else { 3023 | throw new Error('"' + aName + '" is a required argument.'); 3024 | } 3025 | } 3026 | exports.getArg = getArg; 3027 | 3028 | var urlRegexp = /^(?:([\w+\-.]+):)?\/\/(?:(\w+:\w+)@)?([\w.-]*)(?::(\d+))?(.*)$/; 3029 | var dataUrlRegexp = /^data:.+\,.+$/; 3030 | 3031 | function urlParse(aUrl) { 3032 | var match = aUrl.match(urlRegexp); 3033 | if (!match) { 3034 | return null; 3035 | } 3036 | return { 3037 | scheme: match[1], 3038 | auth: match[2], 3039 | host: match[3], 3040 | port: match[4], 3041 | path: match[5] 3042 | }; 3043 | } 3044 | exports.urlParse = urlParse; 3045 | 3046 | function urlGenerate(aParsedUrl) { 3047 | var url = ''; 3048 | if (aParsedUrl.scheme) { 3049 | url += aParsedUrl.scheme + ':'; 3050 | } 3051 | url += '//'; 3052 | if (aParsedUrl.auth) { 3053 | url += aParsedUrl.auth + '@'; 3054 | } 3055 | if (aParsedUrl.host) { 3056 | url += aParsedUrl.host; 3057 | } 3058 | if (aParsedUrl.port) { 3059 | url += ":" + aParsedUrl.port 3060 | } 3061 | if (aParsedUrl.path) { 3062 | url += aParsedUrl.path; 3063 | } 3064 | return url; 3065 | } 3066 | exports.urlGenerate = urlGenerate; 3067 | 3068 | /** 3069 | * Normalizes a path, or the path portion of a URL: 3070 | * 3071 | * - Replaces consecutive slashes with one slash. 3072 | * - Removes unnecessary '.' parts. 3073 | * - Removes unnecessary '/..' parts. 3074 | * 3075 | * Based on code in the Node.js 'path' core module. 3076 | * 3077 | * @param aPath The path or url to normalize. 3078 | */ 3079 | function normalize(aPath) { 3080 | var path = aPath; 3081 | var url = urlParse(aPath); 3082 | if (url) { 3083 | if (!url.path) { 3084 | return aPath; 3085 | } 3086 | path = url.path; 3087 | } 3088 | var isAbsolute = exports.isAbsolute(path); 3089 | 3090 | var parts = path.split(/\/+/); 3091 | for (var part, up = 0, i = parts.length - 1; i >= 0; i--) { 3092 | part = parts[i]; 3093 | if (part === '.') { 3094 | parts.splice(i, 1); 3095 | } else if (part === '..') { 3096 | up++; 3097 | } else if (up > 0) { 3098 | if (part === '') { 3099 | // The first part is blank if the path is absolute. Trying to go 3100 | // above the root is a no-op. Therefore we can remove all '..' parts 3101 | // directly after the root. 3102 | parts.splice(i + 1, up); 3103 | up = 0; 3104 | } else { 3105 | parts.splice(i, 2); 3106 | up--; 3107 | } 3108 | } 3109 | } 3110 | path = parts.join('/'); 3111 | 3112 | if (path === '') { 3113 | path = isAbsolute ? '/' : '.'; 3114 | } 3115 | 3116 | if (url) { 3117 | url.path = path; 3118 | return urlGenerate(url); 3119 | } 3120 | return path; 3121 | } 3122 | exports.normalize = normalize; 3123 | 3124 | /** 3125 | * Joins two paths/URLs. 3126 | * 3127 | * @param aRoot The root path or URL. 3128 | * @param aPath The path or URL to be joined with the root. 3129 | * 3130 | * - If aPath is a URL or a data URI, aPath is returned, unless aPath is a 3131 | * scheme-relative URL: Then the scheme of aRoot, if any, is prepended 3132 | * first. 3133 | * - Otherwise aPath is a path. If aRoot is a URL, then its path portion 3134 | * is updated with the result and aRoot is returned. Otherwise the result 3135 | * is returned. 3136 | * - If aPath is absolute, the result is aPath. 3137 | * - Otherwise the two paths are joined with a slash. 3138 | * - Joining for example 'http://' and 'www.example.com' is also supported. 3139 | */ 3140 | function join(aRoot, aPath) { 3141 | if (aRoot === "") { 3142 | aRoot = "."; 3143 | } 3144 | if (aPath === "") { 3145 | aPath = "."; 3146 | } 3147 | var aPathUrl = urlParse(aPath); 3148 | var aRootUrl = urlParse(aRoot); 3149 | if (aRootUrl) { 3150 | aRoot = aRootUrl.path || '/'; 3151 | } 3152 | 3153 | // `join(foo, '//www.example.org')` 3154 | if (aPathUrl && !aPathUrl.scheme) { 3155 | if (aRootUrl) { 3156 | aPathUrl.scheme = aRootUrl.scheme; 3157 | } 3158 | return urlGenerate(aPathUrl); 3159 | } 3160 | 3161 | if (aPathUrl || aPath.match(dataUrlRegexp)) { 3162 | return aPath; 3163 | } 3164 | 3165 | // `join('http://', 'www.example.com')` 3166 | if (aRootUrl && !aRootUrl.host && !aRootUrl.path) { 3167 | aRootUrl.host = aPath; 3168 | return urlGenerate(aRootUrl); 3169 | } 3170 | 3171 | var joined = aPath.charAt(0) === '/' 3172 | ? aPath 3173 | : normalize(aRoot.replace(/\/+$/, '') + '/' + aPath); 3174 | 3175 | if (aRootUrl) { 3176 | aRootUrl.path = joined; 3177 | return urlGenerate(aRootUrl); 3178 | } 3179 | return joined; 3180 | } 3181 | exports.join = join; 3182 | 3183 | exports.isAbsolute = function (aPath) { 3184 | return aPath.charAt(0) === '/' || urlRegexp.test(aPath); 3185 | }; 3186 | 3187 | /** 3188 | * Make a path relative to a URL or another path. 3189 | * 3190 | * @param aRoot The root path or URL. 3191 | * @param aPath The path or URL to be made relative to aRoot. 3192 | */ 3193 | function relative(aRoot, aPath) { 3194 | if (aRoot === "") { 3195 | aRoot = "."; 3196 | } 3197 | 3198 | aRoot = aRoot.replace(/\/$/, ''); 3199 | 3200 | // It is possible for the path to be above the root. In this case, simply 3201 | // checking whether the root is a prefix of the path won't work. Instead, we 3202 | // need to remove components from the root one by one, until either we find 3203 | // a prefix that fits, or we run out of components to remove. 3204 | var level = 0; 3205 | while (aPath.indexOf(aRoot + '/') !== 0) { 3206 | var index = aRoot.lastIndexOf("/"); 3207 | if (index < 0) { 3208 | return aPath; 3209 | } 3210 | 3211 | // If the only part of the root that is left is the scheme (i.e. http://, 3212 | // file:///, etc.), one or more slashes (/), or simply nothing at all, we 3213 | // have exhausted all components, so the path is not relative to the root. 3214 | aRoot = aRoot.slice(0, index); 3215 | if (aRoot.match(/^([^\/]+:\/)?\/*$/)) { 3216 | return aPath; 3217 | } 3218 | 3219 | ++level; 3220 | } 3221 | 3222 | // Make sure we add a "../" for each component we removed from the root. 3223 | return Array(level + 1).join("../") + aPath.substr(aRoot.length + 1); 3224 | } 3225 | exports.relative = relative; 3226 | 3227 | var supportsNullProto = (function () { 3228 | var obj = Object.create(null); 3229 | return !('__proto__' in obj); 3230 | }()); 3231 | 3232 | function identity (s) { 3233 | return s; 3234 | } 3235 | 3236 | /** 3237 | * Because behavior goes wacky when you set `__proto__` on objects, we 3238 | * have to prefix all the strings in our set with an arbitrary character. 3239 | * 3240 | * See https://github.com/mozilla/source-map/pull/31 and 3241 | * https://github.com/mozilla/source-map/issues/30 3242 | * 3243 | * @param String aStr 3244 | */ 3245 | function toSetString(aStr) { 3246 | if (isProtoString(aStr)) { 3247 | return '$' + aStr; 3248 | } 3249 | 3250 | return aStr; 3251 | } 3252 | exports.toSetString = supportsNullProto ? identity : toSetString; 3253 | 3254 | function fromSetString(aStr) { 3255 | if (isProtoString(aStr)) { 3256 | return aStr.slice(1); 3257 | } 3258 | 3259 | return aStr; 3260 | } 3261 | exports.fromSetString = supportsNullProto ? identity : fromSetString; 3262 | 3263 | function isProtoString(s) { 3264 | if (!s) { 3265 | return false; 3266 | } 3267 | 3268 | var length = s.length; 3269 | 3270 | if (length < 9 /* "__proto__".length */) { 3271 | return false; 3272 | } 3273 | 3274 | if (s.charCodeAt(length - 1) !== 95 /* '_' */ || 3275 | s.charCodeAt(length - 2) !== 95 /* '_' */ || 3276 | s.charCodeAt(length - 3) !== 111 /* 'o' */ || 3277 | s.charCodeAt(length - 4) !== 116 /* 't' */ || 3278 | s.charCodeAt(length - 5) !== 111 /* 'o' */ || 3279 | s.charCodeAt(length - 6) !== 114 /* 'r' */ || 3280 | s.charCodeAt(length - 7) !== 112 /* 'p' */ || 3281 | s.charCodeAt(length - 8) !== 95 /* '_' */ || 3282 | s.charCodeAt(length - 9) !== 95 /* '_' */) { 3283 | return false; 3284 | } 3285 | 3286 | for (var i = length - 10; i >= 0; i--) { 3287 | if (s.charCodeAt(i) !== 36 /* '$' */) { 3288 | return false; 3289 | } 3290 | } 3291 | 3292 | return true; 3293 | } 3294 | 3295 | /** 3296 | * Comparator between two mappings where the original positions are compared. 3297 | * 3298 | * Optionally pass in `true` as `onlyCompareGenerated` to consider two 3299 | * mappings with the same original source/line/column, but different generated 3300 | * line and column the same. Useful when searching for a mapping with a 3301 | * stubbed out mapping. 3302 | */ 3303 | function compareByOriginalPositions(mappingA, mappingB, onlyCompareOriginal) { 3304 | var cmp = strcmp(mappingA.source, mappingB.source); 3305 | if (cmp !== 0) { 3306 | return cmp; 3307 | } 3308 | 3309 | cmp = mappingA.originalLine - mappingB.originalLine; 3310 | if (cmp !== 0) { 3311 | return cmp; 3312 | } 3313 | 3314 | cmp = mappingA.originalColumn - mappingB.originalColumn; 3315 | if (cmp !== 0 || onlyCompareOriginal) { 3316 | return cmp; 3317 | } 3318 | 3319 | cmp = mappingA.generatedColumn - mappingB.generatedColumn; 3320 | if (cmp !== 0) { 3321 | return cmp; 3322 | } 3323 | 3324 | cmp = mappingA.generatedLine - mappingB.generatedLine; 3325 | if (cmp !== 0) { 3326 | return cmp; 3327 | } 3328 | 3329 | return strcmp(mappingA.name, mappingB.name); 3330 | } 3331 | exports.compareByOriginalPositions = compareByOriginalPositions; 3332 | 3333 | /** 3334 | * Comparator between two mappings with deflated source and name indices where 3335 | * the generated positions are compared. 3336 | * 3337 | * Optionally pass in `true` as `onlyCompareGenerated` to consider two 3338 | * mappings with the same generated line and column, but different 3339 | * source/name/original line and column the same. Useful when searching for a 3340 | * mapping with a stubbed out mapping. 3341 | */ 3342 | function compareByGeneratedPositionsDeflated(mappingA, mappingB, onlyCompareGenerated) { 3343 | var cmp = mappingA.generatedLine - mappingB.generatedLine; 3344 | if (cmp !== 0) { 3345 | return cmp; 3346 | } 3347 | 3348 | cmp = mappingA.generatedColumn - mappingB.generatedColumn; 3349 | if (cmp !== 0 || onlyCompareGenerated) { 3350 | return cmp; 3351 | } 3352 | 3353 | cmp = strcmp(mappingA.source, mappingB.source); 3354 | if (cmp !== 0) { 3355 | return cmp; 3356 | } 3357 | 3358 | cmp = mappingA.originalLine - mappingB.originalLine; 3359 | if (cmp !== 0) { 3360 | return cmp; 3361 | } 3362 | 3363 | cmp = mappingA.originalColumn - mappingB.originalColumn; 3364 | if (cmp !== 0) { 3365 | return cmp; 3366 | } 3367 | 3368 | return strcmp(mappingA.name, mappingB.name); 3369 | } 3370 | exports.compareByGeneratedPositionsDeflated = compareByGeneratedPositionsDeflated; 3371 | 3372 | function strcmp(aStr1, aStr2) { 3373 | if (aStr1 === aStr2) { 3374 | return 0; 3375 | } 3376 | 3377 | if (aStr1 === null) { 3378 | return 1; // aStr2 !== null 3379 | } 3380 | 3381 | if (aStr2 === null) { 3382 | return -1; // aStr1 !== null 3383 | } 3384 | 3385 | if (aStr1 > aStr2) { 3386 | return 1; 3387 | } 3388 | 3389 | return -1; 3390 | } 3391 | 3392 | /** 3393 | * Comparator between two mappings with inflated source and name strings where 3394 | * the generated positions are compared. 3395 | */ 3396 | function compareByGeneratedPositionsInflated(mappingA, mappingB) { 3397 | var cmp = mappingA.generatedLine - mappingB.generatedLine; 3398 | if (cmp !== 0) { 3399 | return cmp; 3400 | } 3401 | 3402 | cmp = mappingA.generatedColumn - mappingB.generatedColumn; 3403 | if (cmp !== 0) { 3404 | return cmp; 3405 | } 3406 | 3407 | cmp = strcmp(mappingA.source, mappingB.source); 3408 | if (cmp !== 0) { 3409 | return cmp; 3410 | } 3411 | 3412 | cmp = mappingA.originalLine - mappingB.originalLine; 3413 | if (cmp !== 0) { 3414 | return cmp; 3415 | } 3416 | 3417 | cmp = mappingA.originalColumn - mappingB.originalColumn; 3418 | if (cmp !== 0) { 3419 | return cmp; 3420 | } 3421 | 3422 | return strcmp(mappingA.name, mappingB.name); 3423 | } 3424 | exports.compareByGeneratedPositionsInflated = compareByGeneratedPositionsInflated; 3425 | 3426 | /** 3427 | * Strip any JSON XSSI avoidance prefix from the string (as documented 3428 | * in the source maps specification), and then parse the string as 3429 | * JSON. 3430 | */ 3431 | function parseSourceMapInput(str) { 3432 | return JSON.parse(str.replace(/^\)]}'[^\n]*\n/, '')); 3433 | } 3434 | exports.parseSourceMapInput = parseSourceMapInput; 3435 | 3436 | /** 3437 | * Compute the URL of a source given the the source root, the source's 3438 | * URL, and the source map's URL. 3439 | */ 3440 | function computeSourceURL(sourceRoot, sourceURL, sourceMapURL) { 3441 | sourceURL = sourceURL || ''; 3442 | 3443 | if (sourceRoot) { 3444 | // This follows what Chrome does. 3445 | if (sourceRoot[sourceRoot.length - 1] !== '/' && sourceURL[0] !== '/') { 3446 | sourceRoot += '/'; 3447 | } 3448 | // The spec says: 3449 | // Line 4: An optional source root, useful for relocating source 3450 | // files on a server or removing repeated values in the 3451 | // “sources” entry. This value is prepended to the individual 3452 | // entries in the “source” field. 3453 | sourceURL = sourceRoot + sourceURL; 3454 | } 3455 | 3456 | // Historically, SourceMapConsumer did not take the sourceMapURL as 3457 | // a parameter. This mode is still somewhat supported, which is why 3458 | // this code block is conditional. However, it's preferable to pass 3459 | // the source map URL to SourceMapConsumer, so that this function 3460 | // can implement the source URL resolution algorithm as outlined in 3461 | // the spec. This block is basically the equivalent of: 3462 | // new URL(sourceURL, sourceMapURL).toString() 3463 | // ... except it avoids using URL, which wasn't available in the 3464 | // older releases of node still supported by this library. 3465 | // 3466 | // The spec says: 3467 | // If the sources are not absolute URLs after prepending of the 3468 | // “sourceRoot”, the sources are resolved relative to the 3469 | // SourceMap (like resolving script src in a html document). 3470 | if (sourceMapURL) { 3471 | var parsed = urlParse(sourceMapURL); 3472 | if (!parsed) { 3473 | throw new Error("sourceMapURL could not be parsed"); 3474 | } 3475 | if (parsed.path) { 3476 | // Strip the last path component, but keep the "/". 3477 | var index = parsed.path.lastIndexOf('/'); 3478 | if (index >= 0) { 3479 | parsed.path = parsed.path.substring(0, index + 1); 3480 | } 3481 | } 3482 | sourceURL = join(urlGenerate(parsed), sourceURL); 3483 | } 3484 | 3485 | return normalize(sourceURL); 3486 | } 3487 | exports.computeSourceURL = computeSourceURL; 3488 | 3489 | 3490 | /***/ }), 3491 | 3492 | /***/ 990: 3493 | /***/ (function(__unusedmodule, exports, __webpack_require__) { 3494 | 3495 | /* -*- Mode: js; js-indent-level: 2; -*- */ 3496 | /* 3497 | * Copyright 2011 Mozilla Foundation and contributors 3498 | * Licensed under the New BSD license. See LICENSE or: 3499 | * http://opensource.org/licenses/BSD-3-Clause 3500 | */ 3501 | 3502 | var SourceMapGenerator = __webpack_require__(341).SourceMapGenerator; 3503 | var util = __webpack_require__(983); 3504 | 3505 | // Matches a Windows-style `\r\n` newline or a `\n` newline used by all other 3506 | // operating systems these days (capturing the result). 3507 | var REGEX_NEWLINE = /(\r?\n)/; 3508 | 3509 | // Newline character code for charCodeAt() comparisons 3510 | var NEWLINE_CODE = 10; 3511 | 3512 | // Private symbol for identifying `SourceNode`s when multiple versions of 3513 | // the source-map library are loaded. This MUST NOT CHANGE across 3514 | // versions! 3515 | var isSourceNode = "$$$isSourceNode$$$"; 3516 | 3517 | /** 3518 | * SourceNodes provide a way to abstract over interpolating/concatenating 3519 | * snippets of generated JavaScript source code while maintaining the line and 3520 | * column information associated with the original source code. 3521 | * 3522 | * @param aLine The original line number. 3523 | * @param aColumn The original column number. 3524 | * @param aSource The original source's filename. 3525 | * @param aChunks Optional. An array of strings which are snippets of 3526 | * generated JS, or other SourceNodes. 3527 | * @param aName The original identifier. 3528 | */ 3529 | function SourceNode(aLine, aColumn, aSource, aChunks, aName) { 3530 | this.children = []; 3531 | this.sourceContents = {}; 3532 | this.line = aLine == null ? null : aLine; 3533 | this.column = aColumn == null ? null : aColumn; 3534 | this.source = aSource == null ? null : aSource; 3535 | this.name = aName == null ? null : aName; 3536 | this[isSourceNode] = true; 3537 | if (aChunks != null) this.add(aChunks); 3538 | } 3539 | 3540 | /** 3541 | * Creates a SourceNode from generated code and a SourceMapConsumer. 3542 | * 3543 | * @param aGeneratedCode The generated code 3544 | * @param aSourceMapConsumer The SourceMap for the generated code 3545 | * @param aRelativePath Optional. The path that relative sources in the 3546 | * SourceMapConsumer should be relative to. 3547 | */ 3548 | SourceNode.fromStringWithSourceMap = 3549 | function SourceNode_fromStringWithSourceMap(aGeneratedCode, aSourceMapConsumer, aRelativePath) { 3550 | // The SourceNode we want to fill with the generated code 3551 | // and the SourceMap 3552 | var node = new SourceNode(); 3553 | 3554 | // All even indices of this array are one line of the generated code, 3555 | // while all odd indices are the newlines between two adjacent lines 3556 | // (since `REGEX_NEWLINE` captures its match). 3557 | // Processed fragments are accessed by calling `shiftNextLine`. 3558 | var remainingLines = aGeneratedCode.split(REGEX_NEWLINE); 3559 | var remainingLinesIndex = 0; 3560 | var shiftNextLine = function() { 3561 | var lineContents = getNextLine(); 3562 | // The last line of a file might not have a newline. 3563 | var newLine = getNextLine() || ""; 3564 | return lineContents + newLine; 3565 | 3566 | function getNextLine() { 3567 | return remainingLinesIndex < remainingLines.length ? 3568 | remainingLines[remainingLinesIndex++] : undefined; 3569 | } 3570 | }; 3571 | 3572 | // We need to remember the position of "remainingLines" 3573 | var lastGeneratedLine = 1, lastGeneratedColumn = 0; 3574 | 3575 | // The generate SourceNodes we need a code range. 3576 | // To extract it current and last mapping is used. 3577 | // Here we store the last mapping. 3578 | var lastMapping = null; 3579 | 3580 | aSourceMapConsumer.eachMapping(function (mapping) { 3581 | if (lastMapping !== null) { 3582 | // We add the code from "lastMapping" to "mapping": 3583 | // First check if there is a new line in between. 3584 | if (lastGeneratedLine < mapping.generatedLine) { 3585 | // Associate first line with "lastMapping" 3586 | addMappingWithCode(lastMapping, shiftNextLine()); 3587 | lastGeneratedLine++; 3588 | lastGeneratedColumn = 0; 3589 | // The remaining code is added without mapping 3590 | } else { 3591 | // There is no new line in between. 3592 | // Associate the code between "lastGeneratedColumn" and 3593 | // "mapping.generatedColumn" with "lastMapping" 3594 | var nextLine = remainingLines[remainingLinesIndex] || ''; 3595 | var code = nextLine.substr(0, mapping.generatedColumn - 3596 | lastGeneratedColumn); 3597 | remainingLines[remainingLinesIndex] = nextLine.substr(mapping.generatedColumn - 3598 | lastGeneratedColumn); 3599 | lastGeneratedColumn = mapping.generatedColumn; 3600 | addMappingWithCode(lastMapping, code); 3601 | // No more remaining code, continue 3602 | lastMapping = mapping; 3603 | return; 3604 | } 3605 | } 3606 | // We add the generated code until the first mapping 3607 | // to the SourceNode without any mapping. 3608 | // Each line is added as separate string. 3609 | while (lastGeneratedLine < mapping.generatedLine) { 3610 | node.add(shiftNextLine()); 3611 | lastGeneratedLine++; 3612 | } 3613 | if (lastGeneratedColumn < mapping.generatedColumn) { 3614 | var nextLine = remainingLines[remainingLinesIndex] || ''; 3615 | node.add(nextLine.substr(0, mapping.generatedColumn)); 3616 | remainingLines[remainingLinesIndex] = nextLine.substr(mapping.generatedColumn); 3617 | lastGeneratedColumn = mapping.generatedColumn; 3618 | } 3619 | lastMapping = mapping; 3620 | }, this); 3621 | // We have processed all mappings. 3622 | if (remainingLinesIndex < remainingLines.length) { 3623 | if (lastMapping) { 3624 | // Associate the remaining code in the current line with "lastMapping" 3625 | addMappingWithCode(lastMapping, shiftNextLine()); 3626 | } 3627 | // and add the remaining lines without any mapping 3628 | node.add(remainingLines.splice(remainingLinesIndex).join("")); 3629 | } 3630 | 3631 | // Copy sourcesContent into SourceNode 3632 | aSourceMapConsumer.sources.forEach(function (sourceFile) { 3633 | var content = aSourceMapConsumer.sourceContentFor(sourceFile); 3634 | if (content != null) { 3635 | if (aRelativePath != null) { 3636 | sourceFile = util.join(aRelativePath, sourceFile); 3637 | } 3638 | node.setSourceContent(sourceFile, content); 3639 | } 3640 | }); 3641 | 3642 | return node; 3643 | 3644 | function addMappingWithCode(mapping, code) { 3645 | if (mapping === null || mapping.source === undefined) { 3646 | node.add(code); 3647 | } else { 3648 | var source = aRelativePath 3649 | ? util.join(aRelativePath, mapping.source) 3650 | : mapping.source; 3651 | node.add(new SourceNode(mapping.originalLine, 3652 | mapping.originalColumn, 3653 | source, 3654 | code, 3655 | mapping.name)); 3656 | } 3657 | } 3658 | }; 3659 | 3660 | /** 3661 | * Add a chunk of generated JS to this source node. 3662 | * 3663 | * @param aChunk A string snippet of generated JS code, another instance of 3664 | * SourceNode, or an array where each member is one of those things. 3665 | */ 3666 | SourceNode.prototype.add = function SourceNode_add(aChunk) { 3667 | if (Array.isArray(aChunk)) { 3668 | aChunk.forEach(function (chunk) { 3669 | this.add(chunk); 3670 | }, this); 3671 | } 3672 | else if (aChunk[isSourceNode] || typeof aChunk === "string") { 3673 | if (aChunk) { 3674 | this.children.push(aChunk); 3675 | } 3676 | } 3677 | else { 3678 | throw new TypeError( 3679 | "Expected a SourceNode, string, or an array of SourceNodes and strings. Got " + aChunk 3680 | ); 3681 | } 3682 | return this; 3683 | }; 3684 | 3685 | /** 3686 | * Add a chunk of generated JS to the beginning of this source node. 3687 | * 3688 | * @param aChunk A string snippet of generated JS code, another instance of 3689 | * SourceNode, or an array where each member is one of those things. 3690 | */ 3691 | SourceNode.prototype.prepend = function SourceNode_prepend(aChunk) { 3692 | if (Array.isArray(aChunk)) { 3693 | for (var i = aChunk.length-1; i >= 0; i--) { 3694 | this.prepend(aChunk[i]); 3695 | } 3696 | } 3697 | else if (aChunk[isSourceNode] || typeof aChunk === "string") { 3698 | this.children.unshift(aChunk); 3699 | } 3700 | else { 3701 | throw new TypeError( 3702 | "Expected a SourceNode, string, or an array of SourceNodes and strings. Got " + aChunk 3703 | ); 3704 | } 3705 | return this; 3706 | }; 3707 | 3708 | /** 3709 | * Walk over the tree of JS snippets in this node and its children. The 3710 | * walking function is called once for each snippet of JS and is passed that 3711 | * snippet and the its original associated source's line/column location. 3712 | * 3713 | * @param aFn The traversal function. 3714 | */ 3715 | SourceNode.prototype.walk = function SourceNode_walk(aFn) { 3716 | var chunk; 3717 | for (var i = 0, len = this.children.length; i < len; i++) { 3718 | chunk = this.children[i]; 3719 | if (chunk[isSourceNode]) { 3720 | chunk.walk(aFn); 3721 | } 3722 | else { 3723 | if (chunk !== '') { 3724 | aFn(chunk, { source: this.source, 3725 | line: this.line, 3726 | column: this.column, 3727 | name: this.name }); 3728 | } 3729 | } 3730 | } 3731 | }; 3732 | 3733 | /** 3734 | * Like `String.prototype.join` except for SourceNodes. Inserts `aStr` between 3735 | * each of `this.children`. 3736 | * 3737 | * @param aSep The separator. 3738 | */ 3739 | SourceNode.prototype.join = function SourceNode_join(aSep) { 3740 | var newChildren; 3741 | var i; 3742 | var len = this.children.length; 3743 | if (len > 0) { 3744 | newChildren = []; 3745 | for (i = 0; i < len-1; i++) { 3746 | newChildren.push(this.children[i]); 3747 | newChildren.push(aSep); 3748 | } 3749 | newChildren.push(this.children[i]); 3750 | this.children = newChildren; 3751 | } 3752 | return this; 3753 | }; 3754 | 3755 | /** 3756 | * Call String.prototype.replace on the very right-most source snippet. Useful 3757 | * for trimming whitespace from the end of a source node, etc. 3758 | * 3759 | * @param aPattern The pattern to replace. 3760 | * @param aReplacement The thing to replace the pattern with. 3761 | */ 3762 | SourceNode.prototype.replaceRight = function SourceNode_replaceRight(aPattern, aReplacement) { 3763 | var lastChild = this.children[this.children.length - 1]; 3764 | if (lastChild[isSourceNode]) { 3765 | lastChild.replaceRight(aPattern, aReplacement); 3766 | } 3767 | else if (typeof lastChild === 'string') { 3768 | this.children[this.children.length - 1] = lastChild.replace(aPattern, aReplacement); 3769 | } 3770 | else { 3771 | this.children.push(''.replace(aPattern, aReplacement)); 3772 | } 3773 | return this; 3774 | }; 3775 | 3776 | /** 3777 | * Set the source content for a source file. This will be added to the SourceMapGenerator 3778 | * in the sourcesContent field. 3779 | * 3780 | * @param aSourceFile The filename of the source file 3781 | * @param aSourceContent The content of the source file 3782 | */ 3783 | SourceNode.prototype.setSourceContent = 3784 | function SourceNode_setSourceContent(aSourceFile, aSourceContent) { 3785 | this.sourceContents[util.toSetString(aSourceFile)] = aSourceContent; 3786 | }; 3787 | 3788 | /** 3789 | * Walk over the tree of SourceNodes. The walking function is called for each 3790 | * source file content and is passed the filename and source content. 3791 | * 3792 | * @param aFn The traversal function. 3793 | */ 3794 | SourceNode.prototype.walkSourceContents = 3795 | function SourceNode_walkSourceContents(aFn) { 3796 | for (var i = 0, len = this.children.length; i < len; i++) { 3797 | if (this.children[i][isSourceNode]) { 3798 | this.children[i].walkSourceContents(aFn); 3799 | } 3800 | } 3801 | 3802 | var sources = Object.keys(this.sourceContents); 3803 | for (var i = 0, len = sources.length; i < len; i++) { 3804 | aFn(util.fromSetString(sources[i]), this.sourceContents[sources[i]]); 3805 | } 3806 | }; 3807 | 3808 | /** 3809 | * Return the string representation of this source node. Walks over the tree 3810 | * and concatenates all the various snippets together to one string. 3811 | */ 3812 | SourceNode.prototype.toString = function SourceNode_toString() { 3813 | var str = ""; 3814 | this.walk(function (chunk) { 3815 | str += chunk; 3816 | }); 3817 | return str; 3818 | }; 3819 | 3820 | /** 3821 | * Returns the string representation of this source node along with a source 3822 | * map. 3823 | */ 3824 | SourceNode.prototype.toStringWithSourceMap = function SourceNode_toStringWithSourceMap(aArgs) { 3825 | var generated = { 3826 | code: "", 3827 | line: 1, 3828 | column: 0 3829 | }; 3830 | var map = new SourceMapGenerator(aArgs); 3831 | var sourceMappingActive = false; 3832 | var lastOriginalSource = null; 3833 | var lastOriginalLine = null; 3834 | var lastOriginalColumn = null; 3835 | var lastOriginalName = null; 3836 | this.walk(function (chunk, original) { 3837 | generated.code += chunk; 3838 | if (original.source !== null 3839 | && original.line !== null 3840 | && original.column !== null) { 3841 | if(lastOriginalSource !== original.source 3842 | || lastOriginalLine !== original.line 3843 | || lastOriginalColumn !== original.column 3844 | || lastOriginalName !== original.name) { 3845 | map.addMapping({ 3846 | source: original.source, 3847 | original: { 3848 | line: original.line, 3849 | column: original.column 3850 | }, 3851 | generated: { 3852 | line: generated.line, 3853 | column: generated.column 3854 | }, 3855 | name: original.name 3856 | }); 3857 | } 3858 | lastOriginalSource = original.source; 3859 | lastOriginalLine = original.line; 3860 | lastOriginalColumn = original.column; 3861 | lastOriginalName = original.name; 3862 | sourceMappingActive = true; 3863 | } else if (sourceMappingActive) { 3864 | map.addMapping({ 3865 | generated: { 3866 | line: generated.line, 3867 | column: generated.column 3868 | } 3869 | }); 3870 | lastOriginalSource = null; 3871 | sourceMappingActive = false; 3872 | } 3873 | for (var idx = 0, length = chunk.length; idx < length; idx++) { 3874 | if (chunk.charCodeAt(idx) === NEWLINE_CODE) { 3875 | generated.line++; 3876 | generated.column = 0; 3877 | // Mappings end at eol 3878 | if (idx + 1 === length) { 3879 | lastOriginalSource = null; 3880 | sourceMappingActive = false; 3881 | } else if (sourceMappingActive) { 3882 | map.addMapping({ 3883 | source: original.source, 3884 | original: { 3885 | line: original.line, 3886 | column: original.column 3887 | }, 3888 | generated: { 3889 | line: generated.line, 3890 | column: generated.column 3891 | }, 3892 | name: original.name 3893 | }); 3894 | } 3895 | } else { 3896 | generated.column++; 3897 | } 3898 | } 3899 | }); 3900 | this.walkSourceContents(function (sourceFile, sourceContent) { 3901 | map.setSourceContent(sourceFile, sourceContent); 3902 | }); 3903 | 3904 | return { code: generated.code, map: map }; 3905 | }; 3906 | 3907 | exports.SourceNode = SourceNode; 3908 | 3909 | 3910 | /***/ }) 3911 | 3912 | /******/ }); -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | clearMocks: true, 3 | moduleFileExtensions: ['js', 'ts'], 4 | testEnvironment: 'node', 5 | testMatch: ['**/*.test.ts'], 6 | testRunner: 'jest-circus/runner', 7 | transform: { 8 | '^.+\\.ts$': 'ts-jest', 9 | }, 10 | verbose: true, 11 | }; 12 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "action-setup-waypoint", 3 | "version": "1.0.0", 4 | "private": true, 5 | "description": "setup waypoint action", 6 | "main": "lib/main.js", 7 | "scripts": { 8 | "build": "tsc", 9 | "format": "prettier --write **/*.ts", 10 | "format-check": "prettier --check **/*.ts", 11 | "lint": "eslint src/**/*.ts", 12 | "package": "ncc build --source-map --license licenses.txt", 13 | "test": "jest", 14 | "all": "npm run build && npm run format && npm run lint && npm run package && npm test" 15 | }, 16 | "repository": { 17 | "type": "git", 18 | "url": "git+https://github.com/actions/typescript-action.git" 19 | }, 20 | "keywords": [ 21 | "actions", 22 | "waypoint", 23 | "setup" 24 | ], 25 | "author": "", 26 | "license": "MIT", 27 | "dependencies": { 28 | "@actions/core": "^1.2.5", 29 | "@actions/github": "^4.0.0", 30 | "@actions/http-client": "^1.0.8", 31 | "@actions/io": "^1.0.2", 32 | "@actions/tool-cache": "^1.6.0", 33 | "@grpc/grpc-js": "^1.1.6", 34 | "@octokit/webhooks": "^7.11.2", 35 | "@types/semver": "^7.3.3", 36 | "api-common-protos": "file:../api-common-protos", 37 | "nock": "^13.0.4", 38 | "semver": "^7.3.2" 39 | }, 40 | "peerDependencies": {}, 41 | "devDependencies": { 42 | "@types/jest": "^26.0.10", 43 | "@types/node": "^14.6.0", 44 | "@typescript-eslint/parser": "^3.10.1", 45 | "@vercel/ncc": "^0.23.0", 46 | "eslint": "^7.7.0", 47 | "eslint-plugin-github": "^4.1.1", 48 | "eslint-plugin-jest": "^23.20.0", 49 | "jest": "^24.9.0", 50 | "jest-circus": "^26.4.2", 51 | "js-yaml": "^3.14.0", 52 | "prettier": "2.1.1", 53 | "ts-jest": "^24.3.0", 54 | "typescript": "^4.0.2" 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/handler.ts: -------------------------------------------------------------------------------- 1 | import { EventPayloads } from '@octokit/webhooks'; 2 | import { Ctx } from './setup'; 3 | import { exec, ExecOptions } from '@actions/exec'; 4 | import * as core from '@actions/core'; 5 | 6 | const LABEL_PREFIX = 'common'; 7 | const URL_REGEX = /(?<=Deployment URL: )[^\n]+/; 8 | const WAIT_FOR_BUILD = 8000; 9 | 10 | // The GitHub state, unfortunately have to do this as we cannot just pass a string value to 11 | // the commit status API 12 | enum githubState { 13 | Error = 'error', 14 | Pending = 'pending', 15 | Success = 'success', 16 | Failure = 'failure', 17 | } 18 | 19 | enum githubDeploymentState { 20 | Error = 'error', 21 | Pending = 'pending', 22 | Success = 'success', 23 | Failure = 'failure', 24 | } 25 | 26 | async function updateCommitStatus(ctx: Ctx, status: githubState, url?: string): Promise { 27 | let description = ''; 28 | let state = githubState.Pending; 29 | const context = `waypoint/${ctx.operation}`; 30 | 31 | core.info(`updating commit status to: ${status}`); 32 | 33 | switch (status) { 34 | case githubState.Error: { 35 | state = githubState.Error; 36 | description = `The ${ctx.operation} encountered an error`; 37 | break; 38 | } 39 | case githubState.Pending: { 40 | state = githubState.Pending; 41 | description = `The ${ctx.operation} has started running`; 42 | break; 43 | } 44 | case githubState.Success: { 45 | state = githubState.Success; 46 | description = `The ${ctx.operation} has completed successfully`; 47 | break; 48 | } 49 | } 50 | 51 | try { 52 | await ctx.octokit.request('POST /repos/:owner/:repo/statuses/:sha', { 53 | owner: ctx.context.repo.owner, 54 | repo: ctx.context.repo.repo, 55 | sha: ctx.context.sha, 56 | state, 57 | description, 58 | context, 59 | target_url: ctx.uiAppUrl || undefined, 60 | }); 61 | } catch (e) { 62 | throw new Error(`failed to create commit status ${e}`); 63 | } 64 | } 65 | 66 | /* eslint-expect-error-next-line @typescript-eslint/no-explicit-any */ 67 | async function createDeployment(ctx: Ctx): Promise { 68 | core.info(`creating github deployment`); 69 | 70 | try { 71 | const deployment = await ctx.octokit.request('POST /repos/:owner/:repo/deployments', { 72 | owner: ctx.context.repo.owner, 73 | repo: ctx.context.repo.repo, 74 | ref: ctx.context.sha, 75 | environment: ctx.workspace, 76 | auto_merge: false, 77 | required_contexts: [], 78 | }); 79 | 80 | /* eslint-expect-error-next-line @typescript-eslint/no-explicit-any */ 81 | const responseData: any = deployment.data; 82 | return responseData; 83 | } catch (e) { 84 | throw new Error(`failed to create deployment ${e}`); 85 | } 86 | } 87 | 88 | async function createDeploymentStatus( 89 | ctx: Ctx, 90 | deploymentId: number, 91 | status: githubDeploymentState, 92 | url?: string 93 | ): Promise { 94 | let state = githubDeploymentState.Pending; 95 | 96 | switch (status) { 97 | case githubDeploymentState.Pending: { 98 | state = githubDeploymentState.Pending; 99 | break; 100 | } 101 | case githubDeploymentState.Failure: { 102 | state = githubDeploymentState.Failure; 103 | break; 104 | } 105 | case githubDeploymentState.Success: { 106 | state = githubDeploymentState.Success; 107 | break; 108 | } 109 | } 110 | 111 | core.info(`update github deployment status to ${status}`); 112 | 113 | try { 114 | await ctx.octokit.request('POST /repos/:owner/:repo/deployments/:deployment_id/statuses', { 115 | owner: ctx.context.repo.owner, 116 | repo: ctx.context.repo.repo, 117 | ref: ctx.context.sha, 118 | deployment_id: deploymentId, 119 | state, 120 | target_url: ctx.uiAppUrl || undefined, 121 | }); 122 | } catch (e) { 123 | throw new Error(`failed to create deployment status ${e}`); 124 | } 125 | } 126 | 127 | // CLI options for all commands, for labeling and determing the workspace 128 | export async function getCliOptions(ctx: Ctx, payload: EventPayloads.WebhookPayloadPush): Promise { 129 | const commit = await ctx.octokit.request('GET /repos/:owner/:repo/commits/:ref', { 130 | owner: ctx.context.repo.owner, 131 | repo: ctx.context.repo.repo, 132 | ref: payload.after, 133 | }); 134 | 135 | return [ 136 | '-workspace', 137 | ctx.workspace, 138 | '-label', 139 | `${LABEL_PREFIX}/vcs-ref=${ctx.context.ref}`, 140 | '-label', 141 | `${LABEL_PREFIX}/vcs-sha=${payload.after}`, 142 | '-label', 143 | `${LABEL_PREFIX}/vcs-url=${commit.data.html_url}`, 144 | '-label', 145 | `${LABEL_PREFIX}/vcs-run-id=${ctx.context.runId}`, 146 | ]; 147 | } 148 | 149 | export async function initWaypoint(ctx: Ctx): Promise { 150 | // Run init quietly 151 | const options: ExecOptions = {}; 152 | core.info(`running Waypoint init`); 153 | 154 | try { 155 | const buildCode = await exec('waypoint', ['init', '-workspace', ctx.workspace], options); 156 | if (buildCode !== 0) { 157 | throw new Error(`init failed with exit code ${buildCode}`); 158 | } 159 | } catch (e) { 160 | throw new Error(`init failed: ${e}`); 161 | } 162 | } 163 | 164 | export async function handleBuild(ctx: Ctx, payload: EventPayloads.WebhookPayloadPush): Promise { 165 | const waypointOptions = await getCliOptions(ctx, payload); 166 | 167 | // Set status to pending 168 | await updateCommitStatus(ctx, githubState.Pending); 169 | 170 | // Run init 171 | await initWaypoint(ctx); 172 | 173 | // Run the build 174 | try { 175 | const buildCode = await exec('waypoint', ['build', ...waypointOptions]); 176 | if (buildCode !== 0) { 177 | throw new Error(`build failed with exit code ${buildCode}`); 178 | } 179 | } catch (e) { 180 | // Set status to error 181 | await updateCommitStatus(ctx, githubState.Error); 182 | throw new Error(`build failed: ${e}`); 183 | } 184 | 185 | // Set status to success 186 | await updateCommitStatus(ctx, githubState.Success); 187 | } 188 | 189 | export async function handleDeploy(ctx: Ctx, payload: EventPayloads.WebhookPayloadPush): Promise { 190 | const waypointOptions = await getCliOptions(ctx, payload); 191 | 192 | // Set status to pending 193 | await updateCommitStatus(ctx, githubState.Pending); 194 | 195 | // Create a github deployment, which also updates the status 196 | const deploy = await createDeployment(ctx); 197 | 198 | // Update the status of the deployment 199 | await createDeploymentStatus(ctx, deploy.id, githubDeploymentState.Pending); 200 | 201 | // This is pretty unfortunate, but if you run `waypoint deploy` too soon 202 | // after `waypoint build` you might not get the recently built artifact. So 203 | // we just naively wait. 204 | await new Promise((resolve) => { 205 | setTimeout(resolve, WAIT_FOR_BUILD); 206 | }); 207 | 208 | // Run init 209 | await initWaypoint(ctx); 210 | 211 | let output = ''; 212 | const options: ExecOptions = {}; 213 | options.listeners = { 214 | stdout: (data: Buffer) => { 215 | // Store a copy out of the output so we can 216 | // search for a deployment URL after 217 | output += data.toString(); 218 | core.info(output); 219 | }, 220 | }; 221 | 222 | await createDeploymentStatus(ctx, deploy.id, githubDeploymentState.Pending); 223 | 224 | // Run the deploy 225 | try { 226 | const buildCode = await exec('waypoint', ['deploy', ...waypointOptions], options); 227 | if (buildCode !== 0) { 228 | throw new Error(`deploy failed with exit code ${buildCode}`); 229 | } 230 | } catch (e) { 231 | await updateCommitStatus(ctx, githubState.Error); 232 | await createDeploymentStatus(ctx, deploy.id, githubDeploymentState.Failure); 233 | throw new Error(`deploy failed: ${e}`); 234 | } 235 | 236 | let deployUrl = undefined; 237 | const matches = URL_REGEX.exec(output); 238 | if (matches?.length === 1) { 239 | deployUrl = matches[0]; 240 | core.info(`got deployment url from output: ${deployUrl}`); 241 | } 242 | 243 | // Update the commit status 244 | await updateCommitStatus(ctx, githubState.Success, deployUrl); 245 | await createDeploymentStatus(ctx, deploy.id, githubDeploymentState.Success); 246 | } 247 | 248 | export async function handleRelease(ctx: Ctx, payload: EventPayloads.WebhookPayloadPush): Promise { 249 | const waypointOptions = await getCliOptions(ctx, payload); 250 | 251 | // Set status to pending 252 | await updateCommitStatus(ctx, githubState.Pending); 253 | 254 | // Run init 255 | await initWaypoint(ctx); 256 | 257 | try { 258 | const releaseCode = await exec('waypoint', ['release', ...waypointOptions]); 259 | if (releaseCode !== 0) { 260 | await updateCommitStatus(ctx, githubState.Error); 261 | throw new Error(`release failed with exit code ${releaseCode}`); 262 | } 263 | } catch (e) { 264 | throw new Error(`release failed: ${e}`); 265 | } 266 | 267 | // Update the commit status to success 268 | await updateCommitStatus(ctx, githubState.Success); 269 | } 270 | -------------------------------------------------------------------------------- /src/install.ts: -------------------------------------------------------------------------------- 1 | import * as tc from '@actions/tool-cache'; 2 | import * as core from '@actions/core'; 3 | import * as semver from 'semver'; 4 | import * as httpm from '@actions/http-client'; 5 | import os from 'os'; 6 | 7 | const DEFAULT_RELEASES_URL = 'https://releases.hashicorp.com'; 8 | 9 | interface Build { 10 | arch: string; 11 | filename: string; 12 | name: string; 13 | os: string; 14 | url: string; 15 | version: string; 16 | } 17 | 18 | interface Version { 19 | name: string; 20 | shasums: string; 21 | shasums_signature: string; 22 | version: string; 23 | 24 | builds: Build[]; 25 | } 26 | 27 | interface MetadataIndex { 28 | name: string; 29 | versions: Versions; 30 | } 31 | 32 | interface Versions { 33 | [version: string]: Version; 34 | } 35 | 36 | export function releasesUrl(): string { 37 | return core.getInput('releases_url') || DEFAULT_RELEASES_URL; 38 | } 39 | 40 | async function getMetadata(product: string): Promise { 41 | const http = new httpm.HttpClient('action-setup-wapoint', [], { 42 | allowRetries: true, 43 | maxRetries: 5, 44 | }); 45 | 46 | try { 47 | const resp = await http.getJson(`${releasesUrl()}/${product}/index.json`); 48 | 49 | return resp.result || undefined; 50 | } catch (err) { 51 | throw new Error(`Failed to fetch version metadata file ${err}`); 52 | } 53 | } 54 | 55 | /** 56 | * @param versionSpec The version defined by a user in a semver compatible format 57 | * @param versions A list of available versions for the product 58 | * 59 | * @returns The most relevant version based on the supplied version selector 60 | */ 61 | function matchVersion(versionSpec: string, versions: string[]): string { 62 | // from @actions/tool-cache 63 | let version = ''; 64 | 65 | versions = versions.sort((a, b) => { 66 | if (semver.gt(a, b)) { 67 | return 1; 68 | } 69 | return -1; 70 | }); 71 | 72 | for (let i = versions.length - 1; i >= 0; i--) { 73 | const potential: string = versions[i]; 74 | const satisfied: boolean = semver.satisfies(potential, versionSpec); 75 | if (satisfied) { 76 | version = potential; 77 | break; 78 | } 79 | } 80 | 81 | if (version) { 82 | core.debug(`found version match: ${version}`); 83 | } else { 84 | core.debug(`version match not found for ${version}`); 85 | } 86 | 87 | return version; 88 | } 89 | 90 | /** 91 | * @param versionSpec The version defined by a user in a semver compatible format 92 | * 93 | * @returns Metadata about a version found by matching the semver spec against 94 | * available versions on the release URL 95 | */ 96 | async function getVersion(product: string, versionSpec: string): Promise { 97 | core.debug('downloading release metadata to determine latest version'); 98 | 99 | // Our lowest possible release value 100 | const meta = await getMetadata(product); 101 | 102 | const versions: string[] = []; 103 | 104 | if (!meta?.versions) { 105 | core.setFailed(`response does not contain versions. ${meta?.versions}`); 106 | return; 107 | } 108 | 109 | // Populate versions array 110 | for (const version of Object.values(meta.versions)) { 111 | versions.push(version.version); 112 | } 113 | 114 | // Match a version based on the version spec 115 | const version = matchVersion(versionSpec, versions); 116 | 117 | return meta.versions[version]; 118 | } 119 | 120 | /** 121 | * @param configuredVersion The version defined by a user in a semver compatible format 122 | * 123 | * @returns The toolpath where the binary is stored after being downloaded based 124 | * on the version 125 | */ 126 | export async function getBinary(product: string, configuredVersion: string): Promise { 127 | const version = await getVersion(product, configuredVersion); 128 | 129 | if (!version?.version) { 130 | throw new Error(`${product} version '${configuredVersion}' does not exist`); 131 | } 132 | 133 | // Tool path caches based on version 134 | let toolPath: string; 135 | toolPath = tc.find(product, version.version, os.arch()); 136 | 137 | if (toolPath) { 138 | // If the toolpath exists, return it instead of download the product 139 | core.info(`found in cache: ${toolPath}`); 140 | return toolPath; 141 | } 142 | 143 | // Determine the environment platform and architecture 144 | const platform: string = os.platform(); 145 | const arch: string = os.arch(); 146 | 147 | // Golang arch and platform (and as a result the product binaries) do not match 148 | // naming returned by the os package, so translate those 149 | const goArch = (): string => { 150 | switch (arch) { 151 | case 'x64': 152 | return 'amd64'; 153 | case 'x32': 154 | return '386'; 155 | default: 156 | return arch; 157 | } 158 | }; 159 | 160 | const goPlatform = (): string => { 161 | switch (platform) { 162 | case 'win32': 163 | return 'windows'; 164 | default: 165 | return platform; 166 | } 167 | }; 168 | 169 | core.info(`downloading ${version.version} from ${releasesUrl()}`); 170 | 171 | try { 172 | // Download the product 173 | toolPath = await tc.downloadTool( 174 | `${releasesUrl()}/${product}/${version?.version}/${product}_${ 175 | version?.version 176 | }_${goPlatform()}_${goArch()}.zip` 177 | ); 178 | } catch (error) { 179 | core.debug(error); 180 | } 181 | 182 | // Extract the zip 183 | const extractedPath = await tc.extractZip(toolPath); 184 | 185 | // Installs into the tool cachedir 186 | const dir = await tc.cacheDir(extractedPath, product, version.version, os.arch()); 187 | 188 | return dir; 189 | } 190 | -------------------------------------------------------------------------------- /src/main.ts: -------------------------------------------------------------------------------- 1 | import * as core from '@actions/core'; 2 | import * as github from '@actions/github'; 3 | import { exec } from '@actions/exec'; 4 | import { Ctx } from './setup'; 5 | import * as setup from './setup'; 6 | import * as handler from './handler'; 7 | import { getBinary } from './install'; 8 | import { EventPayloads } from '@octokit/webhooks'; 9 | 10 | export const PRODUCT_NAME = 'waypoint'; 11 | 12 | export async function run(): Promise { 13 | try { 14 | // The version is the version of Waypoint we want to 15 | // download and install 16 | const version = core.getInput('version'); 17 | 18 | // Download or return the cached path for the specified version 19 | const path = await getBinary(PRODUCT_NAME, version); 20 | 21 | // Make command available for future commands or actions 22 | core.addPath(path); 23 | 24 | // Populates user inputs and configuration 25 | const ctx = new Ctx(); 26 | 27 | // Validate the installation of Waypoint, will error if 28 | // not valid 29 | await setup.validateWaypoint(); 30 | 31 | // Create context, will error in failure 32 | await setup.createContextConfig(ctx); 33 | 34 | // We only deal with push events so return on everything else we are sent 35 | if (github.context.eventName !== 'push') { 36 | return; 37 | } 38 | 39 | // Get the event context 40 | const payload = github.context.payload as EventPayloads.WebhookPayloadPush; 41 | 42 | // Get the second argument to the script. If none is supplied it will return 43 | const operation = core.getInput('operation'); 44 | 45 | if (operation === 'build') { 46 | await handler.handleBuild(ctx, payload); 47 | } else if (operation === 'deploy') { 48 | await handler.handleDeploy(ctx, payload); 49 | } else if (operation === 'release') { 50 | await handler.handleRelease(ctx, payload); 51 | } 52 | } catch (error) { 53 | core.setFailed(error.message); 54 | } 55 | } 56 | 57 | run(); 58 | -------------------------------------------------------------------------------- /src/setup-waypoint.ts: -------------------------------------------------------------------------------- 1 | import { run } from './main'; 2 | 3 | run(); 4 | -------------------------------------------------------------------------------- /src/setup.ts: -------------------------------------------------------------------------------- 1 | import * as core from '@actions/core'; 2 | import { exec, ExecOptions } from '@actions/exec'; 3 | import { Context } from '@actions/github/lib/context'; 4 | import { getOctokit, context } from '@actions/github'; 5 | import { Octokit } from '@octokit/core'; 6 | import { CallCredentials, ChannelCredentials, Metadata } from '@grpc/grpc-js'; 7 | import { readFileSync } from 'fs'; 8 | 9 | const DEFAULT_WORKSPACE = 'default'; 10 | const PROECT_REGEX = /(?<=project = ")[^"]+/; 11 | const APP_REGEX = /(?<=app ")[^"]+/; 12 | 13 | export class Ctx { 14 | // The GitHub token to use, should be passed from the SECRETS value 15 | github_token: string; 16 | 17 | // An instance of ocotkit that is configured 18 | octokit: Octokit; 19 | 20 | // The workspace for waypoint operations 21 | workspace: string; 22 | 23 | // The project for waypoint operations 24 | project?: string; 25 | // The app for waypoint operations 26 | app?: string; 27 | 28 | // The operation we're running 29 | operation: string; 30 | 31 | waypointToken: string; 32 | waypointAddress: string; 33 | waypointAddressUi: string; 34 | 35 | // The associated context 36 | context: Context; 37 | 38 | constructor() { 39 | const githubToken = process.env.GITHUB_TOKEN || core.getInput('github_token', { required: true }); 40 | 41 | this.workspace = core.getInput('workspace') || DEFAULT_WORKSPACE; 42 | this.github_token = githubToken; 43 | this.octokit = getOctokit(githubToken); 44 | this.context = context; 45 | this.operation = core.getInput('operation'); 46 | 47 | this.waypointToken = 48 | process.env.WAYPOINT_SERVER_TOKEN || core.getInput('waypoint_server_token', { required: true }); 49 | this.waypointAddress = 50 | process.env.WAYPOINT_SERVER_ADDR || core.getInput('waypoint_server_address', { required: true }); 51 | 52 | this.waypointAddressUi = process.env.WAYPOINT_SERVER_UI || core.getInput('waypoint_server_ui'); 53 | 54 | // Make this available for waypoint exec 55 | core.exportVariable('WAYPOINT_SERVER_TOKEN', this.waypointToken); 56 | core.exportVariable('WAYPOINT_SERVER_ADDR', this.waypointAddress); 57 | core.exportVariable('WAYPOINT_SERVER_UI', this.waypointAddressUi); 58 | core.exportVariable('WAYPOINT_SERVER_TLS', '1'); 59 | core.exportVariable('WAYPOINT_SERVER_TLS_SKIP_VERIFY', '1'); 60 | 61 | // Ensure the Waypoint token is masked from logs 62 | core.setSecret(this.waypointToken); 63 | 64 | // Currently a well-known waypoint configuration location. This is 65 | // a hack until we can talk to Waypoint via API. 66 | const data = readFileSync('waypoint.hcl', 'utf8'); 67 | const project = PROECT_REGEX.exec(data); 68 | const app = APP_REGEX.exec(data); 69 | 70 | if (project && project.length) { 71 | this.project = project[0]; 72 | } 73 | 74 | if (app && app.length) { 75 | this.app = app[0]; 76 | } 77 | 78 | // const creds = createPerRpcChannelCredentials(waypointToken); 79 | // this.waypoint = new WaypointClient(waypointAddress, creds); 80 | } 81 | 82 | get uiAppUrl(): string { 83 | if (this.project && this.app && this.waypointAddressUi) { 84 | return `${this.waypointAddressUi}/${this.workspace}/${this.project}/app/${this.app}`; 85 | } 86 | return ''; 87 | } 88 | } 89 | 90 | export function createPerRpcChannelCredentials(token: string): ChannelCredentials { 91 | const verifyOptions = { 92 | checkServerIdentity() { 93 | // Don't check 94 | return undefined; 95 | }, 96 | }; 97 | const creds = ChannelCredentials.createSsl(null, null, null, verifyOptions); 98 | const metadata = new Metadata(); 99 | metadata.add('authorization', token); 100 | 101 | const perRPCCreds = CallCredentials.createFromMetadataGenerator((args, callback) => { 102 | callback(null, metadata); 103 | }); 104 | 105 | return creds.compose(perRPCCreds); 106 | } 107 | 108 | export async function validateWaypoint(): Promise { 109 | const options: ExecOptions = { silent: true }; 110 | 111 | core.info('validating Waypoint installation'); 112 | 113 | // Output the version 114 | const versionCode = await exec('waypoint', ['version'], options); 115 | 116 | if (versionCode !== 0) { 117 | throw new Error( 118 | `Attempt to output Waypoint version failed (exit code ${versionCode}). Waypoint may not be installed. Please 119 | see instructions in the REAMDE for utilizing the setup-waypoint action.` 120 | ); 121 | } 122 | 123 | let statusError = ''; 124 | options.listeners = { 125 | stdout: () => { 126 | // Do nothing. We do not want to show the status output and only 127 | // the error output if this fails 128 | }, 129 | stderr: (data: Buffer) => { 130 | statusError += data.toString(); 131 | }, 132 | }; 133 | 134 | // todo: replace with upcoming `status` command so a failure 135 | // can help debug 136 | const statusCode = await exec('waypoint', ['version'], options); 137 | 138 | if (statusCode !== 0) { 139 | throw new Error( 140 | `The 'waypoint status' command failed. This could mean that Waypoint 141 | is misconfigured. Below is the output returned from Waypoint: 142 | 143 | ${statusError}` 144 | ); 145 | } 146 | } 147 | 148 | export async function createContextConfig(ctx: Ctx): Promise { 149 | core.info('creating Waypoint context configuration'); 150 | 151 | const contextCode = await exec('waypoint', [ 152 | 'context', 153 | 'create', 154 | '-server-addr', 155 | ctx.waypointAddress, 156 | '-server-auth-token', 157 | ctx.waypointToken, 158 | '-server-tls-skip-verify', 159 | '-set-default', 160 | '-server-require-auth', 161 | 'action', 162 | ]); 163 | 164 | if (contextCode !== 0) { 165 | throw new Error(`Failed to setup context for Waypoint to communicate with the server.`); 166 | } 167 | } 168 | -------------------------------------------------------------------------------- /test-html/index.html: -------------------------------------------------------------------------------- 1 | Test application 2 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es6" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'. */, 4 | "module": "commonjs" /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */, 5 | "outDir": "./lib" /* Redirect output structure to the directory. */, 6 | "rootDir": "./src" /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */, 7 | "strict": true /* Enable all strict type-checking options. */, 8 | "noImplicitAny": true /* Raise error on expressions and declarations with an implied 'any' type. */, 9 | "esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */ 10 | }, 11 | "exclude": ["node_modules", "**/*.test.ts", "./action-setup-waypoint"] 12 | } 13 | -------------------------------------------------------------------------------- /waypoint.hcl: -------------------------------------------------------------------------------- 1 | project = "example-nginx" 2 | 3 | app "example-nginx" { 4 | labels = { 5 | "service" = "example-nginx", 6 | "env" = "dev" 7 | } 8 | 9 | build { 10 | use "docker" {} 11 | } 12 | 13 | deploy { 14 | use "docker" {} 15 | } 16 | } 17 | --------------------------------------------------------------------------------