├── .github └── workflows │ ├── release.yml │ └── test.yml ├── .gitignore ├── CODE_OF_CONDUCT.md ├── LICENSE ├── README.md ├── action.yml ├── dist └── index.js ├── index.js ├── package-lock.json └── package.json /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | on: 2 | push: 3 | branches: 4 | - master 5 | name: release 6 | jobs: 7 | release: 8 | name: release 9 | runs-on: ubuntu-latest 10 | steps: 11 | - uses: actions/checkout@master 12 | - uses: actions/setup-node@v1 13 | with: 14 | node-version: "12.x" 15 | - run: npm ci 16 | - run: npm run build 17 | - run: npx semantic-release 18 | env: 19 | GITHUB_TOKEN: ${{ secrets.GR2M_PAT_FOR_SEMANTIC_RELEASE }} 20 | - run: "git push https://x-access-token:${GITHUB_TOKEN}@github.com/${GITHUB_REPOSITORY}.git HEAD:refs/heads/v1.x" 21 | env: 22 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 23 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | on: 2 | push: 3 | branches: 4 | - master 5 | - "greenkeeper/**" 6 | pull_request: 7 | types: [opened, synchronize] 8 | name: Test 9 | jobs: 10 | readmeExample: 11 | name: "[TEST] README example" 12 | runs-on: ubuntu-latest 13 | steps: 14 | - uses: actions/checkout@master 15 | - uses: actions/setup-node@v1 16 | with: 17 | node-version: "12.x" 18 | - run: "npm ci" 19 | - run: "npm run build" 20 | - id: action_with_json_output 21 | run: 'node -p "require(''@actions/core'').setOutput(''data'', JSON.stringify({foo: {bar: ''baz''}}))"' 22 | - id: result 23 | uses: ./ 24 | with: 25 | json: ${{ steps.action_with_json_output.outputs.data }} 26 | bar: "foo.bar" 27 | - run: 'node -e "assert.equal(''baz'', ''${{ steps.result.outputs.bar }}'')"' 28 | readmeRequestActionExample: 29 | name: "[TEST] README octokit/request-action@v2.x example" 30 | runs-on: ubuntu-latest 31 | steps: 32 | - uses: actions/checkout@master 33 | - uses: actions/setup-node@v1 34 | with: 35 | node-version: "12.x" 36 | - run: "npm ci" 37 | - run: "npm run build" 38 | - id: request 39 | uses: octokit/request-action@v2.x 40 | with: 41 | route: GET /repos/:owner/:repo/releases/latest 42 | owner: gr2m 43 | repo: get-json-paths-action 44 | env: 45 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 46 | - id: result 47 | uses: ./ 48 | with: 49 | json: ${{ steps.request.outputs.data }} 50 | name: "name" 51 | tag_name: "tag_name" 52 | created_by: "author.login" 53 | - run: 'node -e "assert.equal(''gr2m'', ''${{ steps.result.outputs.created_by }}'')"' 54 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. 6 | 7 | ## Our Standards 8 | 9 | Examples of behavior that contributes to creating a positive environment include: 10 | 11 | - Using welcoming and inclusive language 12 | - Being respectful of differing viewpoints and experiences 13 | - Gracefully accepting constructive criticism 14 | - Focusing on what is best for the community 15 | - Showing empathy towards other community members 16 | 17 | Examples of unacceptable behavior by participants include: 18 | 19 | - The use of sexualized language or imagery and unwelcome sexual attention or advances 20 | - Trolling, insulting/derogatory comments, and personal or political attacks 21 | - Public or private harassment 22 | - Publishing others' private information, such as a physical or electronic address, without explicit permission 23 | - Other conduct which could reasonably be considered inappropriate in a professional setting 24 | 25 | ## Our Responsibilities 26 | 27 | Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. 28 | 29 | Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. 30 | 31 | ## Scope 32 | 33 | This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. 34 | 35 | ## Enforcement 36 | 37 | Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at coc@martynus.net. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. 38 | 39 | Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. 40 | 41 | ## Attribution 42 | 43 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version] 44 | 45 | [homepage]: http://contributor-covenant.org 46 | [version]: http://contributor-covenant.org/version/1/4/ 47 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Gregor Martynus 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 💁‍♂️ This action is now obsolete 2 | 3 | Use the built-in [`fromJSON(value)`](https://help.github.com/en/actions/reference/context-and-expression-syntax-for-github-actions#fromjson) function instead 4 | 5 | # Get JSON paths action 6 | 7 | > A GitHub Action to access deep values of JSON strings 8 | 9 | [![Build Status](https://github.com/gr2m/get-json-paths-action/workflows/Test/badge.svg)](https://github.com/gr2m/get-json-paths-action/actions) 10 | [![Greenkeeper](https://badges.greenkeeper.io/gr2m/get-json-paths-action.svg)](https://greenkeeper.io/) 11 | 12 | ## Usage 13 | 14 | Minimal example 15 | 16 | ```yml 17 | Name: Minimal example 18 | on: [push] 19 | 20 | jobs: 21 | minimal_example: 22 | runs-on: ubuntu-latest 23 | steps: 24 | - id: action_with_json_output 25 | run: 'echo ::set-output name=data::{ "foo": { "bar":"baz" } }' 26 | - id: data 27 | uses: gr2m/get-json-paths-action@v1.x 28 | with: 29 | json: ${{ steps.action_with_json_output.outputs.data }} 30 | bar: "foo.bar" 31 | - run: "echo bar is ${{ steps.data.outputs.bar }}" 32 | ``` 33 | 34 | Example with [`octokit/request-action`](https://github.com/octokit/request-action/) 35 | 36 | ```yml 37 | Name: Request example 38 | on: 39 | push: 40 | branches: 41 | - master 42 | 43 | jobs: 44 | request_example: 45 | runs-on: ubuntu-latest 46 | steps: 47 | - id: request 48 | uses: octokit/request-action@v2.x 49 | with: 50 | route: GET /repos/:owner/:repo/releases/latest 51 | owner: gr2m 52 | repo: get-json-paths-action 53 | env: 54 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 55 | - id: result 56 | uses: gr2m/get-json-paths-action@v1.x 57 | with: 58 | json: ${{ steps.request.outputs.data }} 59 | name: "name" 60 | tag_name: "tag_name" 61 | created_by: "author.login" 62 | - run: "echo latest release: ${{ steps.result.outputs.name }} (${{ steps.result.outputs.tag_name }}) by ${{ ${{ steps.result.outputs.login }}" 63 | ``` 64 | 65 | ## Debugging 66 | 67 | To see additional debug logs, create a secret with the name: `ACTIONS_STEP_DEBUG` and value `true`. 68 | 69 | ## How it works 70 | 71 | `get-json-paths-action` is using [`lodash.get`](https://lodash.com/docs/4.17.15#get) to access deep properties at the provided path. `json` is the only required `input`. All other inputs are turned into equally named outputs with the value at the given paths. 72 | 73 | ## License 74 | 75 | [MIT](LICENSE) 76 | -------------------------------------------------------------------------------- /action.yml: -------------------------------------------------------------------------------- 1 | name: Get JSON paths 2 | description: "A GitHub Action to access deep values of JSON strings" 3 | branding: 4 | icon: "box" 5 | color: gray-dark 6 | inputs: 7 | json: 8 | description: "JSON string" 9 | required: true 10 | runs: 11 | using: "node12" 12 | main: "dist/index.js" 13 | -------------------------------------------------------------------------------- /dist/index.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 | /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); 23 | /******/ 24 | /******/ // Flag the module as loaded 25 | /******/ module.l = true; 26 | /******/ 27 | /******/ // Return the exports of the module 28 | /******/ return module.exports; 29 | /******/ } 30 | /******/ 31 | /******/ 32 | /******/ __webpack_require__.ab = __dirname + "/"; 33 | /******/ 34 | /******/ // the startup function 35 | /******/ function startup() { 36 | /******/ // Load entry module and return exports 37 | /******/ return __webpack_require__(104); 38 | /******/ }; 39 | /******/ 40 | /******/ // run startup 41 | /******/ return startup(); 42 | /******/ }) 43 | /************************************************************************/ 44 | /******/ ({ 45 | 46 | /***/ 87: 47 | /***/ (function(module) { 48 | 49 | module.exports = require("os"); 50 | 51 | /***/ }), 52 | 53 | /***/ 104: 54 | /***/ (function(__unusedmodule, __unusedexports, __webpack_require__) { 55 | 56 | const { inspect } = __webpack_require__(669); 57 | 58 | const get = __webpack_require__(854); 59 | const core = __webpack_require__(470); 60 | 61 | const { json, ...paths } = getAllInputs(); 62 | const jsonParsed = JSON.parse(json); 63 | 64 | try { 65 | core.debug(`json input: ${inspect(jsonParsed)}`); 66 | core.debug(`paths inputs: ${inspect(paths)}`); 67 | 68 | for (const [name, path] of Object.entries(paths)) { 69 | const value = get(jsonParsed, path); 70 | core.debug(`setting output ${name} to ${value} using "${path}"`); 71 | core.setOutput(name, value); 72 | } 73 | } catch (error) { 74 | core.setFailed(error); 75 | process.exit(1); 76 | } 77 | 78 | function getAllInputs() { 79 | return Object.entries(process.env).reduce((result, [key, value]) => { 80 | if (!/^INPUT_/.test(key)) return result; 81 | 82 | const inputName = key.substr("INPUT_".length).toLowerCase(); 83 | result[inputName] = value; 84 | return result; 85 | }, {}); 86 | } 87 | 88 | 89 | /***/ }), 90 | 91 | /***/ 431: 92 | /***/ (function(__unusedmodule, exports, __webpack_require__) { 93 | 94 | "use strict"; 95 | 96 | Object.defineProperty(exports, "__esModule", { value: true }); 97 | const os = __webpack_require__(87); 98 | /** 99 | * Commands 100 | * 101 | * Command Format: 102 | * ##[name key=value;key=value]message 103 | * 104 | * Examples: 105 | * ##[warning]This is the user warning message 106 | * ##[set-secret name=mypassword]definitelyNotAPassword! 107 | */ 108 | function issueCommand(command, properties, message) { 109 | const cmd = new Command(command, properties, message); 110 | process.stdout.write(cmd.toString() + os.EOL); 111 | } 112 | exports.issueCommand = issueCommand; 113 | function issue(name, message = '') { 114 | issueCommand(name, {}, message); 115 | } 116 | exports.issue = issue; 117 | const CMD_STRING = '::'; 118 | class Command { 119 | constructor(command, properties, message) { 120 | if (!command) { 121 | command = 'missing.command'; 122 | } 123 | this.command = command; 124 | this.properties = properties; 125 | this.message = message; 126 | } 127 | toString() { 128 | let cmdStr = CMD_STRING + this.command; 129 | if (this.properties && Object.keys(this.properties).length > 0) { 130 | cmdStr += ' '; 131 | for (const key in this.properties) { 132 | if (this.properties.hasOwnProperty(key)) { 133 | const val = this.properties[key]; 134 | if (val) { 135 | // safely append the val - avoid blowing up when attempting to 136 | // call .replace() if message is not a string for some reason 137 | cmdStr += `${key}=${escape(`${val || ''}`)},`; 138 | } 139 | } 140 | } 141 | } 142 | cmdStr += CMD_STRING; 143 | // safely append the message - avoid blowing up when attempting to 144 | // call .replace() if message is not a string for some reason 145 | const message = `${this.message || ''}`; 146 | cmdStr += escapeData(message); 147 | return cmdStr; 148 | } 149 | } 150 | function escapeData(s) { 151 | return s.replace(/\r/g, '%0D').replace(/\n/g, '%0A'); 152 | } 153 | function escape(s) { 154 | return s 155 | .replace(/\r/g, '%0D') 156 | .replace(/\n/g, '%0A') 157 | .replace(/]/g, '%5D') 158 | .replace(/;/g, '%3B'); 159 | } 160 | //# sourceMappingURL=command.js.map 161 | 162 | /***/ }), 163 | 164 | /***/ 470: 165 | /***/ (function(__unusedmodule, exports, __webpack_require__) { 166 | 167 | "use strict"; 168 | 169 | var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { 170 | function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } 171 | return new (P || (P = Promise))(function (resolve, reject) { 172 | function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } 173 | function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } 174 | function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } 175 | step((generator = generator.apply(thisArg, _arguments || [])).next()); 176 | }); 177 | }; 178 | Object.defineProperty(exports, "__esModule", { value: true }); 179 | const command_1 = __webpack_require__(431); 180 | const os = __webpack_require__(87); 181 | const path = __webpack_require__(622); 182 | /** 183 | * The code to exit an action 184 | */ 185 | var ExitCode; 186 | (function (ExitCode) { 187 | /** 188 | * A code indicating that the action was successful 189 | */ 190 | ExitCode[ExitCode["Success"] = 0] = "Success"; 191 | /** 192 | * A code indicating that the action was a failure 193 | */ 194 | ExitCode[ExitCode["Failure"] = 1] = "Failure"; 195 | })(ExitCode = exports.ExitCode || (exports.ExitCode = {})); 196 | //----------------------------------------------------------------------- 197 | // Variables 198 | //----------------------------------------------------------------------- 199 | /** 200 | * Sets env variable for this action and future actions in the job 201 | * @param name the name of the variable to set 202 | * @param val the value of the variable 203 | */ 204 | function exportVariable(name, val) { 205 | process.env[name] = val; 206 | command_1.issueCommand('set-env', { name }, val); 207 | } 208 | exports.exportVariable = exportVariable; 209 | /** 210 | * Registers a secret which will get masked from logs 211 | * @param secret value of the secret 212 | */ 213 | function setSecret(secret) { 214 | command_1.issueCommand('add-mask', {}, secret); 215 | } 216 | exports.setSecret = setSecret; 217 | /** 218 | * Prepends inputPath to the PATH (for this action and future actions) 219 | * @param inputPath 220 | */ 221 | function addPath(inputPath) { 222 | command_1.issueCommand('add-path', {}, inputPath); 223 | process.env['PATH'] = `${inputPath}${path.delimiter}${process.env['PATH']}`; 224 | } 225 | exports.addPath = addPath; 226 | /** 227 | * Gets the value of an input. The value is also trimmed. 228 | * 229 | * @param name name of the input to get 230 | * @param options optional. See InputOptions. 231 | * @returns string 232 | */ 233 | function getInput(name, options) { 234 | const val = process.env[`INPUT_${name.replace(/ /g, '_').toUpperCase()}`] || ''; 235 | if (options && options.required && !val) { 236 | throw new Error(`Input required and not supplied: ${name}`); 237 | } 238 | return val.trim(); 239 | } 240 | exports.getInput = getInput; 241 | /** 242 | * Sets the value of an output. 243 | * 244 | * @param name name of the output to set 245 | * @param value value to store 246 | */ 247 | function setOutput(name, value) { 248 | command_1.issueCommand('set-output', { name }, value); 249 | } 250 | exports.setOutput = setOutput; 251 | //----------------------------------------------------------------------- 252 | // Results 253 | //----------------------------------------------------------------------- 254 | /** 255 | * Sets the action status to failed. 256 | * When the action exits it will be with an exit code of 1 257 | * @param message add error issue message 258 | */ 259 | function setFailed(message) { 260 | process.exitCode = ExitCode.Failure; 261 | error(message); 262 | } 263 | exports.setFailed = setFailed; 264 | //----------------------------------------------------------------------- 265 | // Logging Commands 266 | //----------------------------------------------------------------------- 267 | /** 268 | * Writes debug message to user log 269 | * @param message debug message 270 | */ 271 | function debug(message) { 272 | command_1.issueCommand('debug', {}, message); 273 | } 274 | exports.debug = debug; 275 | /** 276 | * Adds an error issue 277 | * @param message error issue message 278 | */ 279 | function error(message) { 280 | command_1.issue('error', message); 281 | } 282 | exports.error = error; 283 | /** 284 | * Adds an warning issue 285 | * @param message warning issue message 286 | */ 287 | function warning(message) { 288 | command_1.issue('warning', message); 289 | } 290 | exports.warning = warning; 291 | /** 292 | * Writes info to log with console.log. 293 | * @param message info message 294 | */ 295 | function info(message) { 296 | process.stdout.write(message + os.EOL); 297 | } 298 | exports.info = info; 299 | /** 300 | * Begin an output group. 301 | * 302 | * Output until the next `groupEnd` will be foldable in this group 303 | * 304 | * @param name The name of the output group 305 | */ 306 | function startGroup(name) { 307 | command_1.issue('group', name); 308 | } 309 | exports.startGroup = startGroup; 310 | /** 311 | * End an output group. 312 | */ 313 | function endGroup() { 314 | command_1.issue('endgroup'); 315 | } 316 | exports.endGroup = endGroup; 317 | /** 318 | * Wrap an asynchronous function call in a group. 319 | * 320 | * Returns the same type as the function itself. 321 | * 322 | * @param name The name of the group 323 | * @param fn The function to wrap in the group 324 | */ 325 | function group(name, fn) { 326 | return __awaiter(this, void 0, void 0, function* () { 327 | startGroup(name); 328 | let result; 329 | try { 330 | result = yield fn(); 331 | } 332 | finally { 333 | endGroup(); 334 | } 335 | return result; 336 | }); 337 | } 338 | exports.group = group; 339 | //# sourceMappingURL=core.js.map 340 | 341 | /***/ }), 342 | 343 | /***/ 622: 344 | /***/ (function(module) { 345 | 346 | module.exports = require("path"); 347 | 348 | /***/ }), 349 | 350 | /***/ 669: 351 | /***/ (function(module) { 352 | 353 | module.exports = require("util"); 354 | 355 | /***/ }), 356 | 357 | /***/ 854: 358 | /***/ (function(module) { 359 | 360 | /** 361 | * lodash (Custom Build) 362 | * Build: `lodash modularize exports="npm" -o ./` 363 | * Copyright jQuery Foundation and other contributors 364 | * Released under MIT license 365 | * Based on Underscore.js 1.8.3 366 | * Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors 367 | */ 368 | 369 | /** Used as the `TypeError` message for "Functions" methods. */ 370 | var FUNC_ERROR_TEXT = 'Expected a function'; 371 | 372 | /** Used to stand-in for `undefined` hash values. */ 373 | var HASH_UNDEFINED = '__lodash_hash_undefined__'; 374 | 375 | /** Used as references for various `Number` constants. */ 376 | var INFINITY = 1 / 0; 377 | 378 | /** `Object#toString` result references. */ 379 | var funcTag = '[object Function]', 380 | genTag = '[object GeneratorFunction]', 381 | symbolTag = '[object Symbol]'; 382 | 383 | /** Used to match property names within property paths. */ 384 | var reIsDeepProp = /\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\\]|\\.)*?\1)\]/, 385 | reIsPlainProp = /^\w*$/, 386 | reLeadingDot = /^\./, 387 | rePropName = /[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]|(?=(?:\.|\[\])(?:\.|\[\]|$))/g; 388 | 389 | /** 390 | * Used to match `RegExp` 391 | * [syntax characters](http://ecma-international.org/ecma-262/7.0/#sec-patterns). 392 | */ 393 | var reRegExpChar = /[\\^$.*+?()[\]{}|]/g; 394 | 395 | /** Used to match backslashes in property paths. */ 396 | var reEscapeChar = /\\(\\)?/g; 397 | 398 | /** Used to detect host constructors (Safari). */ 399 | var reIsHostCtor = /^\[object .+?Constructor\]$/; 400 | 401 | /** Detect free variable `global` from Node.js. */ 402 | var freeGlobal = typeof global == 'object' && global && global.Object === Object && global; 403 | 404 | /** Detect free variable `self`. */ 405 | var freeSelf = typeof self == 'object' && self && self.Object === Object && self; 406 | 407 | /** Used as a reference to the global object. */ 408 | var root = freeGlobal || freeSelf || Function('return this')(); 409 | 410 | /** 411 | * Gets the value at `key` of `object`. 412 | * 413 | * @private 414 | * @param {Object} [object] The object to query. 415 | * @param {string} key The key of the property to get. 416 | * @returns {*} Returns the property value. 417 | */ 418 | function getValue(object, key) { 419 | return object == null ? undefined : object[key]; 420 | } 421 | 422 | /** 423 | * Checks if `value` is a host object in IE < 9. 424 | * 425 | * @private 426 | * @param {*} value The value to check. 427 | * @returns {boolean} Returns `true` if `value` is a host object, else `false`. 428 | */ 429 | function isHostObject(value) { 430 | // Many host objects are `Object` objects that can coerce to strings 431 | // despite having improperly defined `toString` methods. 432 | var result = false; 433 | if (value != null && typeof value.toString != 'function') { 434 | try { 435 | result = !!(value + ''); 436 | } catch (e) {} 437 | } 438 | return result; 439 | } 440 | 441 | /** Used for built-in method references. */ 442 | var arrayProto = Array.prototype, 443 | funcProto = Function.prototype, 444 | objectProto = Object.prototype; 445 | 446 | /** Used to detect overreaching core-js shims. */ 447 | var coreJsData = root['__core-js_shared__']; 448 | 449 | /** Used to detect methods masquerading as native. */ 450 | var maskSrcKey = (function() { 451 | var uid = /[^.]+$/.exec(coreJsData && coreJsData.keys && coreJsData.keys.IE_PROTO || ''); 452 | return uid ? ('Symbol(src)_1.' + uid) : ''; 453 | }()); 454 | 455 | /** Used to resolve the decompiled source of functions. */ 456 | var funcToString = funcProto.toString; 457 | 458 | /** Used to check objects for own properties. */ 459 | var hasOwnProperty = objectProto.hasOwnProperty; 460 | 461 | /** 462 | * Used to resolve the 463 | * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring) 464 | * of values. 465 | */ 466 | var objectToString = objectProto.toString; 467 | 468 | /** Used to detect if a method is native. */ 469 | var reIsNative = RegExp('^' + 470 | funcToString.call(hasOwnProperty).replace(reRegExpChar, '\\$&') 471 | .replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g, '$1.*?') + '$' 472 | ); 473 | 474 | /** Built-in value references. */ 475 | var Symbol = root.Symbol, 476 | splice = arrayProto.splice; 477 | 478 | /* Built-in method references that are verified to be native. */ 479 | var Map = getNative(root, 'Map'), 480 | nativeCreate = getNative(Object, 'create'); 481 | 482 | /** Used to convert symbols to primitives and strings. */ 483 | var symbolProto = Symbol ? Symbol.prototype : undefined, 484 | symbolToString = symbolProto ? symbolProto.toString : undefined; 485 | 486 | /** 487 | * Creates a hash object. 488 | * 489 | * @private 490 | * @constructor 491 | * @param {Array} [entries] The key-value pairs to cache. 492 | */ 493 | function Hash(entries) { 494 | var index = -1, 495 | length = entries ? entries.length : 0; 496 | 497 | this.clear(); 498 | while (++index < length) { 499 | var entry = entries[index]; 500 | this.set(entry[0], entry[1]); 501 | } 502 | } 503 | 504 | /** 505 | * Removes all key-value entries from the hash. 506 | * 507 | * @private 508 | * @name clear 509 | * @memberOf Hash 510 | */ 511 | function hashClear() { 512 | this.__data__ = nativeCreate ? nativeCreate(null) : {}; 513 | } 514 | 515 | /** 516 | * Removes `key` and its value from the hash. 517 | * 518 | * @private 519 | * @name delete 520 | * @memberOf Hash 521 | * @param {Object} hash The hash to modify. 522 | * @param {string} key The key of the value to remove. 523 | * @returns {boolean} Returns `true` if the entry was removed, else `false`. 524 | */ 525 | function hashDelete(key) { 526 | return this.has(key) && delete this.__data__[key]; 527 | } 528 | 529 | /** 530 | * Gets the hash value for `key`. 531 | * 532 | * @private 533 | * @name get 534 | * @memberOf Hash 535 | * @param {string} key The key of the value to get. 536 | * @returns {*} Returns the entry value. 537 | */ 538 | function hashGet(key) { 539 | var data = this.__data__; 540 | if (nativeCreate) { 541 | var result = data[key]; 542 | return result === HASH_UNDEFINED ? undefined : result; 543 | } 544 | return hasOwnProperty.call(data, key) ? data[key] : undefined; 545 | } 546 | 547 | /** 548 | * Checks if a hash value for `key` exists. 549 | * 550 | * @private 551 | * @name has 552 | * @memberOf Hash 553 | * @param {string} key The key of the entry to check. 554 | * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`. 555 | */ 556 | function hashHas(key) { 557 | var data = this.__data__; 558 | return nativeCreate ? data[key] !== undefined : hasOwnProperty.call(data, key); 559 | } 560 | 561 | /** 562 | * Sets the hash `key` to `value`. 563 | * 564 | * @private 565 | * @name set 566 | * @memberOf Hash 567 | * @param {string} key The key of the value to set. 568 | * @param {*} value The value to set. 569 | * @returns {Object} Returns the hash instance. 570 | */ 571 | function hashSet(key, value) { 572 | var data = this.__data__; 573 | data[key] = (nativeCreate && value === undefined) ? HASH_UNDEFINED : value; 574 | return this; 575 | } 576 | 577 | // Add methods to `Hash`. 578 | Hash.prototype.clear = hashClear; 579 | Hash.prototype['delete'] = hashDelete; 580 | Hash.prototype.get = hashGet; 581 | Hash.prototype.has = hashHas; 582 | Hash.prototype.set = hashSet; 583 | 584 | /** 585 | * Creates an list cache object. 586 | * 587 | * @private 588 | * @constructor 589 | * @param {Array} [entries] The key-value pairs to cache. 590 | */ 591 | function ListCache(entries) { 592 | var index = -1, 593 | length = entries ? entries.length : 0; 594 | 595 | this.clear(); 596 | while (++index < length) { 597 | var entry = entries[index]; 598 | this.set(entry[0], entry[1]); 599 | } 600 | } 601 | 602 | /** 603 | * Removes all key-value entries from the list cache. 604 | * 605 | * @private 606 | * @name clear 607 | * @memberOf ListCache 608 | */ 609 | function listCacheClear() { 610 | this.__data__ = []; 611 | } 612 | 613 | /** 614 | * Removes `key` and its value from the list cache. 615 | * 616 | * @private 617 | * @name delete 618 | * @memberOf ListCache 619 | * @param {string} key The key of the value to remove. 620 | * @returns {boolean} Returns `true` if the entry was removed, else `false`. 621 | */ 622 | function listCacheDelete(key) { 623 | var data = this.__data__, 624 | index = assocIndexOf(data, key); 625 | 626 | if (index < 0) { 627 | return false; 628 | } 629 | var lastIndex = data.length - 1; 630 | if (index == lastIndex) { 631 | data.pop(); 632 | } else { 633 | splice.call(data, index, 1); 634 | } 635 | return true; 636 | } 637 | 638 | /** 639 | * Gets the list cache value for `key`. 640 | * 641 | * @private 642 | * @name get 643 | * @memberOf ListCache 644 | * @param {string} key The key of the value to get. 645 | * @returns {*} Returns the entry value. 646 | */ 647 | function listCacheGet(key) { 648 | var data = this.__data__, 649 | index = assocIndexOf(data, key); 650 | 651 | return index < 0 ? undefined : data[index][1]; 652 | } 653 | 654 | /** 655 | * Checks if a list cache value for `key` exists. 656 | * 657 | * @private 658 | * @name has 659 | * @memberOf ListCache 660 | * @param {string} key The key of the entry to check. 661 | * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`. 662 | */ 663 | function listCacheHas(key) { 664 | return assocIndexOf(this.__data__, key) > -1; 665 | } 666 | 667 | /** 668 | * Sets the list cache `key` to `value`. 669 | * 670 | * @private 671 | * @name set 672 | * @memberOf ListCache 673 | * @param {string} key The key of the value to set. 674 | * @param {*} value The value to set. 675 | * @returns {Object} Returns the list cache instance. 676 | */ 677 | function listCacheSet(key, value) { 678 | var data = this.__data__, 679 | index = assocIndexOf(data, key); 680 | 681 | if (index < 0) { 682 | data.push([key, value]); 683 | } else { 684 | data[index][1] = value; 685 | } 686 | return this; 687 | } 688 | 689 | // Add methods to `ListCache`. 690 | ListCache.prototype.clear = listCacheClear; 691 | ListCache.prototype['delete'] = listCacheDelete; 692 | ListCache.prototype.get = listCacheGet; 693 | ListCache.prototype.has = listCacheHas; 694 | ListCache.prototype.set = listCacheSet; 695 | 696 | /** 697 | * Creates a map cache object to store key-value pairs. 698 | * 699 | * @private 700 | * @constructor 701 | * @param {Array} [entries] The key-value pairs to cache. 702 | */ 703 | function MapCache(entries) { 704 | var index = -1, 705 | length = entries ? entries.length : 0; 706 | 707 | this.clear(); 708 | while (++index < length) { 709 | var entry = entries[index]; 710 | this.set(entry[0], entry[1]); 711 | } 712 | } 713 | 714 | /** 715 | * Removes all key-value entries from the map. 716 | * 717 | * @private 718 | * @name clear 719 | * @memberOf MapCache 720 | */ 721 | function mapCacheClear() { 722 | this.__data__ = { 723 | 'hash': new Hash, 724 | 'map': new (Map || ListCache), 725 | 'string': new Hash 726 | }; 727 | } 728 | 729 | /** 730 | * Removes `key` and its value from the map. 731 | * 732 | * @private 733 | * @name delete 734 | * @memberOf MapCache 735 | * @param {string} key The key of the value to remove. 736 | * @returns {boolean} Returns `true` if the entry was removed, else `false`. 737 | */ 738 | function mapCacheDelete(key) { 739 | return getMapData(this, key)['delete'](key); 740 | } 741 | 742 | /** 743 | * Gets the map value for `key`. 744 | * 745 | * @private 746 | * @name get 747 | * @memberOf MapCache 748 | * @param {string} key The key of the value to get. 749 | * @returns {*} Returns the entry value. 750 | */ 751 | function mapCacheGet(key) { 752 | return getMapData(this, key).get(key); 753 | } 754 | 755 | /** 756 | * Checks if a map value for `key` exists. 757 | * 758 | * @private 759 | * @name has 760 | * @memberOf MapCache 761 | * @param {string} key The key of the entry to check. 762 | * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`. 763 | */ 764 | function mapCacheHas(key) { 765 | return getMapData(this, key).has(key); 766 | } 767 | 768 | /** 769 | * Sets the map `key` to `value`. 770 | * 771 | * @private 772 | * @name set 773 | * @memberOf MapCache 774 | * @param {string} key The key of the value to set. 775 | * @param {*} value The value to set. 776 | * @returns {Object} Returns the map cache instance. 777 | */ 778 | function mapCacheSet(key, value) { 779 | getMapData(this, key).set(key, value); 780 | return this; 781 | } 782 | 783 | // Add methods to `MapCache`. 784 | MapCache.prototype.clear = mapCacheClear; 785 | MapCache.prototype['delete'] = mapCacheDelete; 786 | MapCache.prototype.get = mapCacheGet; 787 | MapCache.prototype.has = mapCacheHas; 788 | MapCache.prototype.set = mapCacheSet; 789 | 790 | /** 791 | * Gets the index at which the `key` is found in `array` of key-value pairs. 792 | * 793 | * @private 794 | * @param {Array} array The array to inspect. 795 | * @param {*} key The key to search for. 796 | * @returns {number} Returns the index of the matched value, else `-1`. 797 | */ 798 | function assocIndexOf(array, key) { 799 | var length = array.length; 800 | while (length--) { 801 | if (eq(array[length][0], key)) { 802 | return length; 803 | } 804 | } 805 | return -1; 806 | } 807 | 808 | /** 809 | * The base implementation of `_.get` without support for default values. 810 | * 811 | * @private 812 | * @param {Object} object The object to query. 813 | * @param {Array|string} path The path of the property to get. 814 | * @returns {*} Returns the resolved value. 815 | */ 816 | function baseGet(object, path) { 817 | path = isKey(path, object) ? [path] : castPath(path); 818 | 819 | var index = 0, 820 | length = path.length; 821 | 822 | while (object != null && index < length) { 823 | object = object[toKey(path[index++])]; 824 | } 825 | return (index && index == length) ? object : undefined; 826 | } 827 | 828 | /** 829 | * The base implementation of `_.isNative` without bad shim checks. 830 | * 831 | * @private 832 | * @param {*} value The value to check. 833 | * @returns {boolean} Returns `true` if `value` is a native function, 834 | * else `false`. 835 | */ 836 | function baseIsNative(value) { 837 | if (!isObject(value) || isMasked(value)) { 838 | return false; 839 | } 840 | var pattern = (isFunction(value) || isHostObject(value)) ? reIsNative : reIsHostCtor; 841 | return pattern.test(toSource(value)); 842 | } 843 | 844 | /** 845 | * The base implementation of `_.toString` which doesn't convert nullish 846 | * values to empty strings. 847 | * 848 | * @private 849 | * @param {*} value The value to process. 850 | * @returns {string} Returns the string. 851 | */ 852 | function baseToString(value) { 853 | // Exit early for strings to avoid a performance hit in some environments. 854 | if (typeof value == 'string') { 855 | return value; 856 | } 857 | if (isSymbol(value)) { 858 | return symbolToString ? symbolToString.call(value) : ''; 859 | } 860 | var result = (value + ''); 861 | return (result == '0' && (1 / value) == -INFINITY) ? '-0' : result; 862 | } 863 | 864 | /** 865 | * Casts `value` to a path array if it's not one. 866 | * 867 | * @private 868 | * @param {*} value The value to inspect. 869 | * @returns {Array} Returns the cast property path array. 870 | */ 871 | function castPath(value) { 872 | return isArray(value) ? value : stringToPath(value); 873 | } 874 | 875 | /** 876 | * Gets the data for `map`. 877 | * 878 | * @private 879 | * @param {Object} map The map to query. 880 | * @param {string} key The reference key. 881 | * @returns {*} Returns the map data. 882 | */ 883 | function getMapData(map, key) { 884 | var data = map.__data__; 885 | return isKeyable(key) 886 | ? data[typeof key == 'string' ? 'string' : 'hash'] 887 | : data.map; 888 | } 889 | 890 | /** 891 | * Gets the native function at `key` of `object`. 892 | * 893 | * @private 894 | * @param {Object} object The object to query. 895 | * @param {string} key The key of the method to get. 896 | * @returns {*} Returns the function if it's native, else `undefined`. 897 | */ 898 | function getNative(object, key) { 899 | var value = getValue(object, key); 900 | return baseIsNative(value) ? value : undefined; 901 | } 902 | 903 | /** 904 | * Checks if `value` is a property name and not a property path. 905 | * 906 | * @private 907 | * @param {*} value The value to check. 908 | * @param {Object} [object] The object to query keys on. 909 | * @returns {boolean} Returns `true` if `value` is a property name, else `false`. 910 | */ 911 | function isKey(value, object) { 912 | if (isArray(value)) { 913 | return false; 914 | } 915 | var type = typeof value; 916 | if (type == 'number' || type == 'symbol' || type == 'boolean' || 917 | value == null || isSymbol(value)) { 918 | return true; 919 | } 920 | return reIsPlainProp.test(value) || !reIsDeepProp.test(value) || 921 | (object != null && value in Object(object)); 922 | } 923 | 924 | /** 925 | * Checks if `value` is suitable for use as unique object key. 926 | * 927 | * @private 928 | * @param {*} value The value to check. 929 | * @returns {boolean} Returns `true` if `value` is suitable, else `false`. 930 | */ 931 | function isKeyable(value) { 932 | var type = typeof value; 933 | return (type == 'string' || type == 'number' || type == 'symbol' || type == 'boolean') 934 | ? (value !== '__proto__') 935 | : (value === null); 936 | } 937 | 938 | /** 939 | * Checks if `func` has its source masked. 940 | * 941 | * @private 942 | * @param {Function} func The function to check. 943 | * @returns {boolean} Returns `true` if `func` is masked, else `false`. 944 | */ 945 | function isMasked(func) { 946 | return !!maskSrcKey && (maskSrcKey in func); 947 | } 948 | 949 | /** 950 | * Converts `string` to a property path array. 951 | * 952 | * @private 953 | * @param {string} string The string to convert. 954 | * @returns {Array} Returns the property path array. 955 | */ 956 | var stringToPath = memoize(function(string) { 957 | string = toString(string); 958 | 959 | var result = []; 960 | if (reLeadingDot.test(string)) { 961 | result.push(''); 962 | } 963 | string.replace(rePropName, function(match, number, quote, string) { 964 | result.push(quote ? string.replace(reEscapeChar, '$1') : (number || match)); 965 | }); 966 | return result; 967 | }); 968 | 969 | /** 970 | * Converts `value` to a string key if it's not a string or symbol. 971 | * 972 | * @private 973 | * @param {*} value The value to inspect. 974 | * @returns {string|symbol} Returns the key. 975 | */ 976 | function toKey(value) { 977 | if (typeof value == 'string' || isSymbol(value)) { 978 | return value; 979 | } 980 | var result = (value + ''); 981 | return (result == '0' && (1 / value) == -INFINITY) ? '-0' : result; 982 | } 983 | 984 | /** 985 | * Converts `func` to its source code. 986 | * 987 | * @private 988 | * @param {Function} func The function to process. 989 | * @returns {string} Returns the source code. 990 | */ 991 | function toSource(func) { 992 | if (func != null) { 993 | try { 994 | return funcToString.call(func); 995 | } catch (e) {} 996 | try { 997 | return (func + ''); 998 | } catch (e) {} 999 | } 1000 | return ''; 1001 | } 1002 | 1003 | /** 1004 | * Creates a function that memoizes the result of `func`. If `resolver` is 1005 | * provided, it determines the cache key for storing the result based on the 1006 | * arguments provided to the memoized function. By default, the first argument 1007 | * provided to the memoized function is used as the map cache key. The `func` 1008 | * is invoked with the `this` binding of the memoized function. 1009 | * 1010 | * **Note:** The cache is exposed as the `cache` property on the memoized 1011 | * function. Its creation may be customized by replacing the `_.memoize.Cache` 1012 | * constructor with one whose instances implement the 1013 | * [`Map`](http://ecma-international.org/ecma-262/7.0/#sec-properties-of-the-map-prototype-object) 1014 | * method interface of `delete`, `get`, `has`, and `set`. 1015 | * 1016 | * @static 1017 | * @memberOf _ 1018 | * @since 0.1.0 1019 | * @category Function 1020 | * @param {Function} func The function to have its output memoized. 1021 | * @param {Function} [resolver] The function to resolve the cache key. 1022 | * @returns {Function} Returns the new memoized function. 1023 | * @example 1024 | * 1025 | * var object = { 'a': 1, 'b': 2 }; 1026 | * var other = { 'c': 3, 'd': 4 }; 1027 | * 1028 | * var values = _.memoize(_.values); 1029 | * values(object); 1030 | * // => [1, 2] 1031 | * 1032 | * values(other); 1033 | * // => [3, 4] 1034 | * 1035 | * object.a = 2; 1036 | * values(object); 1037 | * // => [1, 2] 1038 | * 1039 | * // Modify the result cache. 1040 | * values.cache.set(object, ['a', 'b']); 1041 | * values(object); 1042 | * // => ['a', 'b'] 1043 | * 1044 | * // Replace `_.memoize.Cache`. 1045 | * _.memoize.Cache = WeakMap; 1046 | */ 1047 | function memoize(func, resolver) { 1048 | if (typeof func != 'function' || (resolver && typeof resolver != 'function')) { 1049 | throw new TypeError(FUNC_ERROR_TEXT); 1050 | } 1051 | var memoized = function() { 1052 | var args = arguments, 1053 | key = resolver ? resolver.apply(this, args) : args[0], 1054 | cache = memoized.cache; 1055 | 1056 | if (cache.has(key)) { 1057 | return cache.get(key); 1058 | } 1059 | var result = func.apply(this, args); 1060 | memoized.cache = cache.set(key, result); 1061 | return result; 1062 | }; 1063 | memoized.cache = new (memoize.Cache || MapCache); 1064 | return memoized; 1065 | } 1066 | 1067 | // Assign cache to `_.memoize`. 1068 | memoize.Cache = MapCache; 1069 | 1070 | /** 1071 | * Performs a 1072 | * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) 1073 | * comparison between two values to determine if they are equivalent. 1074 | * 1075 | * @static 1076 | * @memberOf _ 1077 | * @since 4.0.0 1078 | * @category Lang 1079 | * @param {*} value The value to compare. 1080 | * @param {*} other The other value to compare. 1081 | * @returns {boolean} Returns `true` if the values are equivalent, else `false`. 1082 | * @example 1083 | * 1084 | * var object = { 'a': 1 }; 1085 | * var other = { 'a': 1 }; 1086 | * 1087 | * _.eq(object, object); 1088 | * // => true 1089 | * 1090 | * _.eq(object, other); 1091 | * // => false 1092 | * 1093 | * _.eq('a', 'a'); 1094 | * // => true 1095 | * 1096 | * _.eq('a', Object('a')); 1097 | * // => false 1098 | * 1099 | * _.eq(NaN, NaN); 1100 | * // => true 1101 | */ 1102 | function eq(value, other) { 1103 | return value === other || (value !== value && other !== other); 1104 | } 1105 | 1106 | /** 1107 | * Checks if `value` is classified as an `Array` object. 1108 | * 1109 | * @static 1110 | * @memberOf _ 1111 | * @since 0.1.0 1112 | * @category Lang 1113 | * @param {*} value The value to check. 1114 | * @returns {boolean} Returns `true` if `value` is an array, else `false`. 1115 | * @example 1116 | * 1117 | * _.isArray([1, 2, 3]); 1118 | * // => true 1119 | * 1120 | * _.isArray(document.body.children); 1121 | * // => false 1122 | * 1123 | * _.isArray('abc'); 1124 | * // => false 1125 | * 1126 | * _.isArray(_.noop); 1127 | * // => false 1128 | */ 1129 | var isArray = Array.isArray; 1130 | 1131 | /** 1132 | * Checks if `value` is classified as a `Function` object. 1133 | * 1134 | * @static 1135 | * @memberOf _ 1136 | * @since 0.1.0 1137 | * @category Lang 1138 | * @param {*} value The value to check. 1139 | * @returns {boolean} Returns `true` if `value` is a function, else `false`. 1140 | * @example 1141 | * 1142 | * _.isFunction(_); 1143 | * // => true 1144 | * 1145 | * _.isFunction(/abc/); 1146 | * // => false 1147 | */ 1148 | function isFunction(value) { 1149 | // The use of `Object#toString` avoids issues with the `typeof` operator 1150 | // in Safari 8-9 which returns 'object' for typed array and other constructors. 1151 | var tag = isObject(value) ? objectToString.call(value) : ''; 1152 | return tag == funcTag || tag == genTag; 1153 | } 1154 | 1155 | /** 1156 | * Checks if `value` is the 1157 | * [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types) 1158 | * of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`) 1159 | * 1160 | * @static 1161 | * @memberOf _ 1162 | * @since 0.1.0 1163 | * @category Lang 1164 | * @param {*} value The value to check. 1165 | * @returns {boolean} Returns `true` if `value` is an object, else `false`. 1166 | * @example 1167 | * 1168 | * _.isObject({}); 1169 | * // => true 1170 | * 1171 | * _.isObject([1, 2, 3]); 1172 | * // => true 1173 | * 1174 | * _.isObject(_.noop); 1175 | * // => true 1176 | * 1177 | * _.isObject(null); 1178 | * // => false 1179 | */ 1180 | function isObject(value) { 1181 | var type = typeof value; 1182 | return !!value && (type == 'object' || type == 'function'); 1183 | } 1184 | 1185 | /** 1186 | * Checks if `value` is object-like. A value is object-like if it's not `null` 1187 | * and has a `typeof` result of "object". 1188 | * 1189 | * @static 1190 | * @memberOf _ 1191 | * @since 4.0.0 1192 | * @category Lang 1193 | * @param {*} value The value to check. 1194 | * @returns {boolean} Returns `true` if `value` is object-like, else `false`. 1195 | * @example 1196 | * 1197 | * _.isObjectLike({}); 1198 | * // => true 1199 | * 1200 | * _.isObjectLike([1, 2, 3]); 1201 | * // => true 1202 | * 1203 | * _.isObjectLike(_.noop); 1204 | * // => false 1205 | * 1206 | * _.isObjectLike(null); 1207 | * // => false 1208 | */ 1209 | function isObjectLike(value) { 1210 | return !!value && typeof value == 'object'; 1211 | } 1212 | 1213 | /** 1214 | * Checks if `value` is classified as a `Symbol` primitive or object. 1215 | * 1216 | * @static 1217 | * @memberOf _ 1218 | * @since 4.0.0 1219 | * @category Lang 1220 | * @param {*} value The value to check. 1221 | * @returns {boolean} Returns `true` if `value` is a symbol, else `false`. 1222 | * @example 1223 | * 1224 | * _.isSymbol(Symbol.iterator); 1225 | * // => true 1226 | * 1227 | * _.isSymbol('abc'); 1228 | * // => false 1229 | */ 1230 | function isSymbol(value) { 1231 | return typeof value == 'symbol' || 1232 | (isObjectLike(value) && objectToString.call(value) == symbolTag); 1233 | } 1234 | 1235 | /** 1236 | * Converts `value` to a string. An empty string is returned for `null` 1237 | * and `undefined` values. The sign of `-0` is preserved. 1238 | * 1239 | * @static 1240 | * @memberOf _ 1241 | * @since 4.0.0 1242 | * @category Lang 1243 | * @param {*} value The value to process. 1244 | * @returns {string} Returns the string. 1245 | * @example 1246 | * 1247 | * _.toString(null); 1248 | * // => '' 1249 | * 1250 | * _.toString(-0); 1251 | * // => '-0' 1252 | * 1253 | * _.toString([1, 2, 3]); 1254 | * // => '1,2,3' 1255 | */ 1256 | function toString(value) { 1257 | return value == null ? '' : baseToString(value); 1258 | } 1259 | 1260 | /** 1261 | * Gets the value at `path` of `object`. If the resolved value is 1262 | * `undefined`, the `defaultValue` is returned in its place. 1263 | * 1264 | * @static 1265 | * @memberOf _ 1266 | * @since 3.7.0 1267 | * @category Object 1268 | * @param {Object} object The object to query. 1269 | * @param {Array|string} path The path of the property to get. 1270 | * @param {*} [defaultValue] The value returned for `undefined` resolved values. 1271 | * @returns {*} Returns the resolved value. 1272 | * @example 1273 | * 1274 | * var object = { 'a': [{ 'b': { 'c': 3 } }] }; 1275 | * 1276 | * _.get(object, 'a[0].b.c'); 1277 | * // => 3 1278 | * 1279 | * _.get(object, ['a', '0', 'b', 'c']); 1280 | * // => 3 1281 | * 1282 | * _.get(object, 'a.b.c', 'default'); 1283 | * // => 'default' 1284 | */ 1285 | function get(object, path, defaultValue) { 1286 | var result = object == null ? undefined : baseGet(object, path); 1287 | return result === undefined ? defaultValue : result; 1288 | } 1289 | 1290 | module.exports = get; 1291 | 1292 | 1293 | /***/ }) 1294 | 1295 | /******/ }); -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | const { inspect } = require("util"); 2 | 3 | const get = require("lodash.get"); 4 | const core = require("@actions/core"); 5 | 6 | const { json, ...paths } = getAllInputs(); 7 | const jsonParsed = JSON.parse(json); 8 | 9 | try { 10 | core.debug(`json input: ${inspect(jsonParsed)}`); 11 | core.debug(`paths inputs: ${inspect(paths)}`); 12 | 13 | for (const [name, path] of Object.entries(paths)) { 14 | const value = get(jsonParsed, path); 15 | core.debug(`setting output ${name} to ${value} using "${path}"`); 16 | core.setOutput(name, value); 17 | } 18 | } catch (error) { 19 | core.setFailed(error); 20 | process.exit(1); 21 | } 22 | 23 | function getAllInputs() { 24 | return Object.entries(process.env).reduce((result, [key, value]) => { 25 | if (!/^INPUT_/.test(key)) return result; 26 | 27 | const inputName = key.substr("INPUT_".length).toLowerCase(); 28 | result[inputName] = value; 29 | return result; 30 | }, {}); 31 | } 32 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "get-json-paths-action", 3 | "private": true, 4 | "version": "0.0.0-development", 5 | "description": "A GitHub Action to access deep values of a JSON output", 6 | "main": "dist/index.js", 7 | "scripts": { 8 | "build": "ncc build index.js -o dist" 9 | }, 10 | "repository": "https://github.com/gr2m/get-json-paths-action", 11 | "keywords": [ 12 | "github-action" 13 | ], 14 | "author": "Gregor Martynus (https://twitter.com/gr2m)", 15 | "license": "MIT", 16 | "dependencies": { 17 | "@actions/core": "^1.1.3", 18 | "lodash.get": "^4.4.2" 19 | }, 20 | "devDependencies": { 21 | "@semantic-release/git": "^9.0.0", 22 | "@zeit/ncc": "^0.22.0", 23 | "semantic-release": "^17.0.0" 24 | }, 25 | "release": { 26 | "plugins": [ 27 | "@semantic-release/commit-analyzer", 28 | "@semantic-release/release-notes-generator", 29 | [ 30 | "@semantic-release/git", 31 | { 32 | "assets": [ 33 | "dist/index.js" 34 | ], 35 | "message": "build(release): compiled action for ${nextRelease.version}\n\n[skip ci]" 36 | } 37 | ], 38 | "@semantic-release/github" 39 | ] 40 | } 41 | } 42 | --------------------------------------------------------------------------------