├── .eslintrc ├── .github ├── FUNDING.yml ├── config │ └── codeql.yml └── workflows │ └── codeql-analysis.yml ├── .gitignore ├── .travis.yml ├── CNAME ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── SECURITY.md ├── bower.json ├── docs ├── .eslintrc ├── docco.css ├── favicon.ico ├── images │ ├── background.png │ └── underscore.png ├── linked-esm.jst ├── main.js ├── modules │ ├── _baseCreate.html │ ├── _baseIteratee.html │ ├── _cb.html │ ├── _chainResult.html │ ├── _collectNonEnumProps.html │ ├── _createAssigner.html │ ├── _createEscaper.html │ ├── _createIndexFinder.html │ ├── _createPredicateIndexFinder.html │ ├── _createReduce.html │ ├── _createSizePropertyCheck.html │ ├── _deepGet.html │ ├── _escapeMap.html │ ├── _executeBound.html │ ├── _flatten.html │ ├── _getByteLength.html │ ├── _getLength.html │ ├── _group.html │ ├── _has.html │ ├── _hasObjectTag.html │ ├── _isArrayLike.html │ ├── _isBufferLike.html │ ├── _keyInObj.html │ ├── _methodFingerprint.html │ ├── _optimizeCb.html │ ├── _setup.html │ ├── _shallowProperty.html │ ├── _stringTagBug.html │ ├── _tagTester.html │ ├── _toBufferView.html │ ├── _toPath.html │ ├── _unescapeMap.html │ ├── after.html │ ├── allKeys.html │ ├── before.html │ ├── bind.html │ ├── bindAll.html │ ├── chain.html │ ├── chunk.html │ ├── clone.html │ ├── compact.html │ ├── compose.html │ ├── constant.html │ ├── contains.html │ ├── countBy.html │ ├── create.html │ ├── debounce.html │ ├── defaults.html │ ├── defer.html │ ├── delay.html │ ├── difference.html │ ├── each.html │ ├── escape.html │ ├── every.html │ ├── extend.html │ ├── extendOwn.html │ ├── filter.html │ ├── find.html │ ├── findIndex.html │ ├── findKey.html │ ├── findLastIndex.html │ ├── findWhere.html │ ├── first.html │ ├── flatten.html │ ├── functions.html │ ├── get.html │ ├── groupBy.html │ ├── has.html │ ├── identity.html │ ├── index-all.html │ ├── index-default.html │ ├── index.html │ ├── indexBy.html │ ├── indexOf.html │ ├── initial.html │ ├── intersection.html │ ├── invert.html │ ├── invoke.html │ ├── isArguments.html │ ├── isArray.html │ ├── isArrayBuffer.html │ ├── isBoolean.html │ ├── isDataView.html │ ├── isDate.html │ ├── isElement.html │ ├── isEmpty.html │ ├── isEqual.html │ ├── isError.html │ ├── isFinite.html │ ├── isFunction.html │ ├── isMap.html │ ├── isMatch.html │ ├── isNaN.html │ ├── isNull.html │ ├── isNumber.html │ ├── isObject.html │ ├── isRegExp.html │ ├── isSet.html │ ├── isString.html │ ├── isSymbol.html │ ├── isTypedArray.html │ ├── isUndefined.html │ ├── isWeakMap.html │ ├── isWeakSet.html │ ├── iteratee.html │ ├── keys.html │ ├── last.html │ ├── lastIndexOf.html │ ├── map.html │ ├── mapObject.html │ ├── matcher.html │ ├── max.html │ ├── memoize.html │ ├── min.html │ ├── mixin.html │ ├── negate.html │ ├── noop.html │ ├── now.html │ ├── object.html │ ├── omit.html │ ├── once.html │ ├── pairs.html │ ├── partial.html │ ├── partition.html │ ├── pick.html │ ├── pluck.html │ ├── property.html │ ├── propertyOf.html │ ├── random.html │ ├── range.html │ ├── reduce.html │ ├── reduceRight.html │ ├── reject.html │ ├── rest.html │ ├── restArguments.html │ ├── result.html │ ├── sample.html │ ├── shuffle.html │ ├── size.html │ ├── some.html │ ├── sortBy.html │ ├── sortedIndex.html │ ├── tap.html │ ├── template.html │ ├── templateSettings.html │ ├── throttle.html │ ├── times.html │ ├── toArray.html │ ├── toPath.html │ ├── underscore-array-methods.html │ ├── underscore.html │ ├── unescape.html │ ├── union.html │ ├── uniq.html │ ├── uniqueId.html │ ├── unzip.html │ ├── values.html │ ├── where.html │ ├── without.html │ ├── wrap.html │ └── zip.html ├── public │ ├── fonts │ │ ├── aller-bold.eot │ │ ├── aller-bold.ttf │ │ ├── aller-bold.woff │ │ ├── aller-light.eot │ │ ├── aller-light.ttf │ │ ├── aller-light.woff │ │ ├── roboto-black.eot │ │ ├── roboto-black.ttf │ │ └── roboto-black.woff │ └── stylesheets │ │ └── normalize.css └── underscore-esm.html ├── favicon.ico ├── index.html ├── karma.conf-sauce.js ├── karma.conf.js ├── modules ├── .eslintrc ├── _baseCreate.js ├── _baseIteratee.js ├── _cb.js ├── _chainResult.js ├── _collectNonEnumProps.js ├── _createAssigner.js ├── _createEscaper.js ├── _createIndexFinder.js ├── _createPredicateIndexFinder.js ├── _createReduce.js ├── _createSizePropertyCheck.js ├── _deepGet.js ├── _escapeMap.js ├── _executeBound.js ├── _flatten.js ├── _getByteLength.js ├── _getLength.js ├── _group.js ├── _has.js ├── _hasObjectTag.js ├── _isArrayLike.js ├── _isBufferLike.js ├── _keyInObj.js ├── _methodFingerprint.js ├── _optimizeCb.js ├── _setup.js ├── _shallowProperty.js ├── _stringTagBug.js ├── _tagTester.js ├── _toBufferView.js ├── _toPath.js ├── _unescapeMap.js ├── after.js ├── allKeys.js ├── before.js ├── bind.js ├── bindAll.js ├── chain.js ├── chunk.js ├── clone.js ├── compact.js ├── compose.js ├── constant.js ├── contains.js ├── countBy.js ├── create.js ├── debounce.js ├── defaults.js ├── defer.js ├── delay.js ├── difference.js ├── each.js ├── escape.js ├── every.js ├── extend.js ├── extendOwn.js ├── filter.js ├── find.js ├── findIndex.js ├── findKey.js ├── findLastIndex.js ├── findWhere.js ├── first.js ├── flatten.js ├── functions.js ├── get.js ├── groupBy.js ├── has.js ├── identity.js ├── index-all.js ├── index-default.js ├── index.js ├── indexBy.js ├── indexOf.js ├── initial.js ├── intersection.js ├── invert.js ├── invoke.js ├── isArguments.js ├── isArray.js ├── isArrayBuffer.js ├── isBoolean.js ├── isDataView.js ├── isDate.js ├── isElement.js ├── isEmpty.js ├── isEqual.js ├── isError.js ├── isFinite.js ├── isFunction.js ├── isMap.js ├── isMatch.js ├── isNaN.js ├── isNull.js ├── isNumber.js ├── isObject.js ├── isRegExp.js ├── isSet.js ├── isString.js ├── isSymbol.js ├── isTypedArray.js ├── isUndefined.js ├── isWeakMap.js ├── isWeakSet.js ├── iteratee.js ├── keys.js ├── last.js ├── lastIndexOf.js ├── map.js ├── mapObject.js ├── matcher.js ├── max.js ├── memoize.js ├── min.js ├── mixin.js ├── negate.js ├── noop.js ├── now.js ├── object.js ├── omit.js ├── once.js ├── package.json ├── pairs.js ├── partial.js ├── partition.js ├── pick.js ├── pluck.js ├── property.js ├── propertyOf.js ├── random.js ├── range.js ├── reduce.js ├── reduceRight.js ├── reject.js ├── rest.js ├── restArguments.js ├── result.js ├── sample.js ├── shuffle.js ├── size.js ├── some.js ├── sortBy.js ├── sortedIndex.js ├── tap.js ├── template.js ├── templateSettings.js ├── throttle.js ├── times.js ├── toArray.js ├── toPath.js ├── underscore-array-methods.js ├── underscore.js ├── unescape.js ├── union.js ├── uniq.js ├── uniqueId.js ├── unzip.js ├── values.js ├── where.js ├── without.js ├── wrap.js └── zip.js ├── package-lock.json ├── package.json ├── patches └── docco+0.8.0.patch ├── rollup.common.js ├── rollup.config.js ├── rollup.config2.js ├── test-treeshake ├── map.js ├── rollup.config.js └── template.js ├── test ├── .eslintrc ├── arrays.js ├── chaining.js ├── collections.js ├── cross-document.js ├── functions.js ├── index.html ├── objects.js ├── overrides.js ├── qunit-setup.js ├── treeshake.js ├── utility.js └── vendor │ ├── qunit.css │ └── qunit.js ├── underscore-esm-min.js ├── underscore-esm-min.js.map ├── underscore-esm.js ├── underscore-esm.js.map ├── underscore-min.js ├── underscore-min.js.map ├── underscore-node-f.cjs ├── underscore-node-f.cjs.map ├── underscore-node.cjs ├── underscore-node.cjs.map ├── underscore-node.mjs ├── underscore-node.mjs.map ├── underscore-umd-min.js ├── underscore-umd-min.js.map ├── underscore-umd.js ├── underscore-umd.js.map └── underscore.js /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "browser": true, 4 | "node": true, 5 | "amd": true 6 | }, 7 | "parserOptions": { 8 | "ecmaVersion": 3 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | tidelift: "npm/underscore" 2 | patreon: juliangonggrijp 3 | github: [jgonggrijp] 4 | -------------------------------------------------------------------------------- /.github/config/codeql.yml: -------------------------------------------------------------------------------- 1 | paths: 2 | - 'modules/**' 3 | - 'test/**' 4 | - 'test-treeshake/**' 5 | - 'rollup*.js' 6 | - 'index.html' 7 | -------------------------------------------------------------------------------- /.github/workflows/codeql-analysis.yml: -------------------------------------------------------------------------------- 1 | # For most projects, this workflow file will not need changing; you simply need 2 | # to commit it to your repository. 3 | # 4 | # You may wish to alter this file to override the set of languages analyzed, 5 | # or to provide custom queries or build logic. 6 | # 7 | # ******** NOTE ******** 8 | # We have attempted to detect the languages in your repository. Please check 9 | # the `language` matrix defined below to confirm you have the correct set of 10 | # supported CodeQL languages. 11 | # 12 | name: "CodeQL" 13 | 14 | on: 15 | push: 16 | branches: [ master ] 17 | pull_request: 18 | # The branches below must be a subset of the branches above 19 | branches: [ master ] 20 | paths: 21 | - 'modules/**' 22 | - 'test/**' 23 | - 'test-treeshake/**' 24 | - 'rollup*.js' 25 | - 'index.html' 26 | schedule: 27 | - cron: '16 8 * * 3' 28 | 29 | jobs: 30 | analyze: 31 | name: Analyze 32 | runs-on: ubuntu-latest 33 | permissions: 34 | actions: read 35 | contents: read 36 | security-events: write 37 | 38 | strategy: 39 | fail-fast: false 40 | matrix: 41 | language: [ 'javascript' ] 42 | # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ] 43 | # Learn more about CodeQL language support at 44 | # https://codeql.github.com/docs/codeql-overview/supported-languages-and-frameworks/ 45 | 46 | steps: 47 | - name: Checkout repository 48 | uses: actions/checkout@v4 49 | 50 | # Initializes the CodeQL tools for scanning. 51 | - name: Initialize CodeQL 52 | uses: github/codeql-action/init@v3 53 | with: 54 | languages: ${{ matrix.language }} 55 | # If you wish to specify custom queries, you can do so here or in a config file. 56 | # By default, queries listed here will override any specified in a config file. 57 | # Prefix the list here with "+" to use these queries and those in the config file. 58 | # queries: ./path/to/local/query, your-org/your-repo/queries@main 59 | config-file: ./.github/config/codeql.yml 60 | 61 | # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). 62 | # If this step fails, then you should remove it and run the build manually (see below) 63 | - name: Autobuild 64 | uses: github/codeql-action/autobuild@v3 65 | 66 | # ℹ️ Command-line programs to run using the OS shell. 67 | # 📚 https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions 68 | 69 | # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines 70 | # and modify them (or add more) to build your code if your project 71 | # uses a compiled language 72 | 73 | #- run: | 74 | # make bootstrap 75 | # make release 76 | 77 | - name: Perform CodeQL Analysis 78 | uses: github/codeql-action/analyze@v3 79 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | raw 2 | node_modules 3 | *.log 4 | *.idea 5 | *.swp 6 | nyc_output 7 | coverage 8 | test-treeshake/*-umd.js 9 | amd 10 | cjs 11 | /underscore-node-*-pre* 12 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | sudo: false 3 | jobs: 4 | include: 5 | - node_js: 8 6 | env: 7 | - DOWNGRADE=true 8 | - EXTRA=false 9 | - node_js: 12 10 | env: 11 | - DOWNGRADE=false 12 | - EXTRA=false 13 | - node_js: 16 14 | env: 15 | - DOWNGRADE=false 16 | - EXTRA=true 17 | before_install: 18 | - "[ $EXTRA = false ] || npm install -g karma-cli" 19 | before_script: 20 | - "[ $EXTRA = false ] || npm install karma-sauce-launcher" 21 | - "[ $DOWNGRADE = false ] || npm install rollup@1" 22 | script: 23 | - "[ $EXTRA = false ] || npm run lint" 24 | - npm run prepare-tests 25 | - "[ $EXTRA = false ] || npm run build-umd" 26 | - "[ $EXTRA = false ] || npm run build-esm" 27 | - "[ $EXTRA = false ] || npm run doc" 28 | - "[ $EXTRA = true ] || npm run test-node" 29 | - "[ $EXTRA = false ] || npm run coveralls" 30 | - "[ $EXTRA = false ] || npm run test-browser" 31 | - "[ $EXTRA = false ] || karma start karma.conf-sauce.js" 32 | notifications: 33 | email: false 34 | env: 35 | global: 36 | - NPM_CONFIG_PROGRESS="false" 37 | - secure: bDZSBQfqr21hCayjcZ20IxrV6+XGhxQPFIfwWqEKLrF93Gu8LLVjZRxXE/mE8I8N4Z5WtDNb4ZHrm/TTzmcPa5MuHgIxEdknQCncobH8oimwc83SHwEPk6okeNKl39VlCjvvnmoe/V/KpnknuYn3Rqghtl/Uv9KLpCwskwjTtcw= 38 | - secure: SRECgXuwcZTcD3GVxTS2bYNgRyye4vq6BLrV2PH9FyNenowsKQR2EwlC/dppc1Q8NWMgv79J/R96q9JOFh+mEH9L5dlBb2yhnGH8amVeM/ChAJHT/F8YktKM453uVpz5fR00QcCQDDUOx6Pvx374ID0OKNpWKAkQBWA9mPTsLnE= 39 | -------------------------------------------------------------------------------- /CNAME: -------------------------------------------------------------------------------- 1 | underscorejs.org 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 6 | contributors and maintainers pledge to making participation in our project and 7 | our community a harassment-free experience for everyone, regardless of age, body 8 | size, disability, ethnicity, gender identity and expression, level of experience, 9 | nationality, personal appearance, race, religion, or sexual identity and 10 | orientation. 11 | 12 | ## Our Standards 13 | 14 | Examples of behavior that contributes to creating a positive environment 15 | include: 16 | 17 | * Using welcoming and inclusive language 18 | * Being respectful of differing viewpoints and experiences 19 | * Gracefully accepting constructive criticism 20 | * Focusing on what is best for the community 21 | * Showing empathy towards other community members 22 | 23 | Examples of unacceptable behavior by participants include: 24 | 25 | * The use of sexualized language or imagery and unwelcome sexual attention or 26 | advances 27 | * Trolling, insulting/derogatory comments, and personal or political attacks 28 | * Public or private harassment 29 | * Publishing others' private information, such as a physical or electronic 30 | address, without explicit permission 31 | * Other conduct which could reasonably be considered inappropriate in a 32 | professional setting 33 | 34 | ## Our Responsibilities 35 | 36 | Project maintainers are responsible for clarifying the standards of acceptable 37 | behavior and are expected to take appropriate and fair corrective action in 38 | response to any instances of unacceptable behavior. 39 | 40 | Project maintainers have the right and responsibility to remove, edit, or 41 | reject comments, commits, code, wiki edits, issues, and other contributions 42 | that are not aligned to this Code of Conduct, or to ban temporarily or 43 | permanently any contributor for other behaviors that they deem inappropriate, 44 | threatening, offensive, or harmful. 45 | 46 | ## Scope 47 | 48 | This Code of Conduct applies both within project spaces and in public spaces 49 | when an individual is representing the project or its community. Examples of 50 | representing a project or community include using an official project e-mail 51 | address, posting via an official social media account, or acting as an appointed 52 | representative at an online or offline event. Representation of a project may be 53 | further defined and clarified by project maintainers. 54 | 55 | ## Enforcement 56 | 57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 58 | reported by contacting the project team at jashkenas@gmail.com. The project team 59 | will review and investigate all complaints, and will respond in a way that it deems 60 | appropriate to the circumstances. The project team is obligated to maintain 61 | confidentiality with regard to the reporter of an incident. 62 | Project maintainers who do not follow or enforce the Code of Conduct in good 63 | faith may face temporary or permanent repercussions as determined by other 64 | members of the project's leadership. 65 | 66 | ## Moderation 67 | 68 | Edits of another user's comment must be clearly marked with "**edit**", the 69 | moderator's username, and a timestamp for each occurrence. The only acceptable 70 | reasons for editing another user's comment are: 71 | 72 | 1. to edit out violations of Our Pledge. These edits must include a rationale. 73 | 2. to direct future readers to a relevant point later in the conversation 74 | (usually the resolution). These edits must be append-only. 75 | 76 | Deletion of another user's comment is only acceptable when the comment includes 77 | no original value, such as "+1", ":+1:", or "me too". 78 | 79 | ## Self-Moderation 80 | 81 | Edits of your own comment after someone has responded must be append-only and 82 | clearly marked with "**edit**". Typographical and formatting fixes to your own 83 | comment which do not affect its meaning are exempt from this requirement. 84 | Deletion of your own comment is only acceptable before any later comments have 85 | been posted. 86 | 87 | ## Attribution 88 | 89 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, 90 | available at [https://contributor-covenant.org/version/1/4][version] 91 | 92 | [homepage]: https://contributor-covenant.org 93 | [version]: https://contributor-covenant.org/version/1/4/ 94 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | ## How to contribute to Underscore.js 2 | 3 | * This project adheres to a [code of conduct](CODE_OF_CONDUCT.md). By participating, you are expected to uphold this code. 4 | 5 | * Please do not open a ticket to report a security issue. Consult the [security policy](SECURITY.md) on what to do instead. 6 | 7 | * Before you open a ticket or send a pull request, [search](https://github.com/jashkenas/underscore/issues) for previous discussions about the same feature or issue. Add to the earlier ticket if you find one. 8 | 9 | * If you're proposing a new feature, make sure it isn't already implemented in [Underscore-Contrib](https://github.com/documentcloud/underscore-contrib). 10 | 11 | * When contributing code, make sure that you edit the source code in the `modules/` directory. Also, run `npm install` before committing any changes to ensure that our commit hooks can do their work. 12 | 13 | * Before sending a pull request for a feature, be sure to have [tests](https://underscorejs.org/test/). 14 | 15 | * Use the same coding style as the rest of the [codebase](https://github.com/jashkenas/underscore/blob/master/modules/index.js). 16 | 17 | * In your pull request, do not add documentation or re-build the minified `underscore-umd-min.js` file. We'll do those things before cutting a new release. 18 | 19 | ### "Help, cloning fails with `fatal: fsck error in packed object`" 20 | This error is caused by zero-padded file modes in the commit history. As fixing this is highly destructive, we suggest ignoring these warnings. The simplest way is to instruct git to do so when cloning. For example, to clone from `jashkenas/underscore`, run the following command: `git clone --config transfer.fsckobjects=false git@github.com:jashkenas/underscore.git`. If cloning from a different user or organization, replace `jashkenas` with their name in the previous command. -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2009-2022 Jeremy Ashkenas, Julian Gonggrijp, and DocumentCloud and Investigative Reporters & Editors 2 | 3 | Permission is hereby granted, free of charge, to any person 4 | obtaining a copy of this software and associated documentation 5 | files (the "Software"), to deal in the Software without 6 | restriction, including without limitation the rights to use, 7 | copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the 9 | Software is furnished to do so, subject to the following 10 | conditions: 11 | 12 | The above copyright notice and this permission notice shall be 13 | included in all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 17 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 19 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 20 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | OTHER DEALINGS IN THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | __ 2 | /\ \ __ 3 | __ __ ___ \_\ \ __ _ __ ____ ___ ___ _ __ __ /\_\ ____ 4 | /\ \/\ \ /' _ `\ /'_ \ /'__`\/\ __\/ ,__\ / ___\ / __`\/\ __\/'__`\ \/\ \ /',__\ 5 | \ \ \_\ \/\ \/\ \/\ \ \ \/\ __/\ \ \//\__, `\/\ \__//\ \ \ \ \ \//\ __/ __ \ \ \/\__, `\ 6 | \ \____/\ \_\ \_\ \___,_\ \____\\ \_\\/\____/\ \____\ \____/\ \_\\ \____\/\_\ _\ \ \/\____/ 7 | \/___/ \/_/\/_/\/__,_ /\/____/ \/_/ \/___/ \/____/\/___/ \/_/ \/____/\/_//\ \_\ \/___/ 8 | \ \____/ 9 | \/___/ 10 | 11 | Underscore.js is a utility-belt library for JavaScript that provides 12 | support for the usual functional suspects (each, map, reduce, filter...) 13 | without extending any core JavaScript objects. 14 | 15 | For Docs, License, Tests, and pre-packed downloads, see: 16 | https://underscorejs.org 17 | 18 | For support and questions, please consult 19 | our [security policy](SECURITY.md), 20 | [the gitter channel](https://gitter.im/jashkenas/underscore) 21 | or [stackoverflow](https://stackoverflow.com/search?q=underscore.js) 22 | 23 | Underscore is an open-sourced component of DocumentCloud: 24 | https://github.com/documentcloud 25 | 26 | Many thanks to our contributors: 27 | https://github.com/jashkenas/underscore/contributors 28 | 29 | You can support the project by donating on 30 | [Patreon](https://patreon.com/juliangonggrijp). 31 | Enterprise coverage is available as part of the 32 | [Tidelift Subscription](https://tidelift.com/subscription/pkg/npm-underscore?utm_source=npm-underscore&utm_medium=referral&utm_campaign=enterprise). 33 | 34 | This project adheres to a [code of conduct](CODE_OF_CONDUCT.md). By participating, you are expected to uphold this code. 35 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | ## Supported Versions 4 | 5 | We currently support the following versions of Underscore with security updates: 6 | 7 | - the latest commit on the `master` branch (published as "edge" on the 8 | [project website][website]); 9 | - the 1.x release tagged as [latest][npm-latest] on npm; 10 | - any release tagged as [preview][npm-preview] on npm, if present. 11 | 12 | [website]: https://underscorejs.org 13 | [npm-latest]: https://www.npmjs.com/package/underscore/v/latest 14 | [npm-preview]: https://www.npmjs.com/package/underscore/v/preview 15 | 16 | ## Reporting a Vulnerability 17 | 18 | Please report security issues by sending an email to 19 | dev@juliangonggrijp.com and jashkenas@gmail.com. 20 | 21 | Do __not__ submit an issue ticket or pull request or otherwise publicly 22 | disclose the issue. 23 | 24 | After receiving your email, we will respond as soon as possible and indicate 25 | what we plan to do. 26 | 27 | ## Disclosure policy 28 | 29 | After confirming a vulnerability, we will generally release a security update 30 | as soon as possible, including the minimum amount of information required for 31 | software maintainers and system administrators to assess the urgency of the 32 | update for their particular situation. 33 | 34 | We postpone the publication of any further details such as code comments, 35 | tests, commit history and diffs, in order to enable a substantial share of the 36 | users to install the security fix before this time. 37 | 38 | Upon publication of full details, we will credit the reporter if the reporter wishes to be publicly identified. 39 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "underscore", 3 | "main": "underscore-umd.js", 4 | "keywords": ["util", "functional", "server", "client", "browser"], 5 | "ignore" : ["docs", "test", "*.yml", "CNAME", "index.html", "favicon.ico", "CONTRIBUTING.md", ".*", "package.json", "karma.*"] 6 | } 7 | -------------------------------------------------------------------------------- /docs/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "globals": { 3 | "_": true, 4 | "parserOptions": {}, 5 | "rules": [], 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /docs/docco.css: -------------------------------------------------------------------------------- 1 | /*--------------------- Typography ----------------------------*/ 2 | 3 | @font-face { 4 | font-family: 'aller-light'; 5 | src: url('public/fonts/aller-light.eot'); 6 | src: url('public/fonts/aller-light.eot?#iefix') format('embedded-opentype'), 7 | url('public/fonts/aller-light.woff') format('woff'), 8 | url('public/fonts/aller-light.ttf') format('truetype'); 9 | font-weight: normal; 10 | font-style: normal; 11 | } 12 | 13 | @font-face { 14 | font-family: 'aller-bold'; 15 | src: url('public/fonts/aller-bold.eot'); 16 | src: url('public/fonts/aller-bold.eot?#iefix') format('embedded-opentype'), 17 | url('public/fonts/aller-bold.woff') format('woff'), 18 | url('public/fonts/aller-bold.ttf') format('truetype'); 19 | font-weight: normal; 20 | font-style: normal; 21 | } 22 | 23 | @font-face { 24 | font-family: 'roboto-black'; 25 | src: url('public/fonts/roboto-black.eot'); 26 | src: url('public/fonts/roboto-black.eot?#iefix') format('embedded-opentype'), 27 | url('public/fonts/roboto-black.woff') format('woff'), 28 | url('public/fonts/roboto-black.ttf') format('truetype'); 29 | font-weight: normal; 30 | font-style: normal; 31 | } 32 | 33 | /*--------------------- Layout ----------------------------*/ 34 | html { height: 100%; } 35 | body { 36 | font-family: "aller-light"; 37 | font-size: 14px; 38 | line-height: 18px; 39 | color: #30404f; 40 | margin: 0; padding: 0; 41 | height:100%; 42 | } 43 | #container { min-height: 100%; } 44 | 45 | a { 46 | color: #000; 47 | } 48 | 49 | b, strong { 50 | font-weight: normal; 51 | font-family: "aller-bold"; 52 | } 53 | 54 | p { 55 | margin: 15px 0 0px; 56 | } 57 | .annotation ul, .annotation ol { 58 | margin: 25px 0; 59 | } 60 | .annotation ul li, .annotation ol li { 61 | font-size: 14px; 62 | line-height: 18px; 63 | margin: 10px 0; 64 | } 65 | 66 | h1, h2, h3, h4, h5, h6 { 67 | color: #112233; 68 | line-height: 1em; 69 | font-weight: normal; 70 | font-family: "roboto-black"; 71 | text-transform: uppercase; 72 | margin: 30px 0 15px 0; 73 | } 74 | 75 | h1 { 76 | margin-top: 40px; 77 | } 78 | h2 { 79 | font-size: 1.26em; 80 | } 81 | 82 | hr { 83 | border: 0; 84 | background: 1px #ddd; 85 | height: 1px; 86 | margin: 20px 0; 87 | } 88 | 89 | pre, tt, code { 90 | font-size: 12px; line-height: 16px; 91 | font-family: Menlo, Monaco, Consolas, "Lucida Console", monospace; 92 | margin: 0; padding: 0; 93 | } 94 | .annotation pre { 95 | display: block; 96 | margin: 0; 97 | padding: 7px 10px; 98 | background: #fcfcfc; 99 | -moz-box-shadow: inset 0 0 10px rgba(0,0,0,0.1); 100 | -webkit-box-shadow: inset 0 0 10px rgba(0,0,0,0.1); 101 | box-shadow: inset 0 0 10px rgba(0,0,0,0.1); 102 | overflow-x: auto; 103 | } 104 | .annotation pre code { 105 | border: 0; 106 | padding: 0; 107 | background: transparent; 108 | } 109 | 110 | 111 | blockquote { 112 | border-left: 5px solid #ccc; 113 | margin: 0; 114 | padding: 1px 0 1px 1em; 115 | } 116 | .sections blockquote p { 117 | font-family: Menlo, Consolas, Monaco, monospace; 118 | font-size: 12px; line-height: 16px; 119 | color: #999; 120 | margin: 10px 0 0; 121 | white-space: pre-wrap; 122 | } 123 | 124 | ul.sections { 125 | list-style: none; 126 | padding:0 0 5px 0;; 127 | margin:0; 128 | } 129 | 130 | /* 131 | Force border-box so that % widths fit the parent 132 | container without overlap because of margin/padding. 133 | 134 | More Info : http://www.quirksmode.org/css/box.html 135 | */ 136 | ul.sections > li > div { 137 | -moz-box-sizing: border-box; /* firefox */ 138 | -ms-box-sizing: border-box; /* ie */ 139 | -webkit-box-sizing: border-box; /* webkit */ 140 | -khtml-box-sizing: border-box; /* konqueror */ 141 | box-sizing: border-box; /* css3 */ 142 | } 143 | 144 | 145 | /*---------------------- Jump Page -----------------------------*/ 146 | #jump_to, #jump_page { 147 | margin: 0; 148 | background: white; 149 | -webkit-box-shadow: 0 0 25px #777; -moz-box-shadow: 0 0 25px #777; 150 | -webkit-border-bottom-left-radius: 5px; -moz-border-radius-bottomleft: 5px; 151 | font: 16px Arial; 152 | cursor: pointer; 153 | text-align: right; 154 | list-style: none; 155 | } 156 | 157 | #jump_to a { 158 | text-decoration: none; 159 | } 160 | 161 | #jump_to a.large { 162 | display: none; 163 | } 164 | #jump_to a.small { 165 | font-size: 22px; 166 | font-weight: bold; 167 | color: #676767; 168 | } 169 | 170 | #jump_to, #jump_wrapper { 171 | position: fixed; 172 | right: 0; top: 0; 173 | padding: 10px 15px; 174 | margin:0; 175 | } 176 | 177 | #jump_wrapper { 178 | display: none; 179 | padding:0; 180 | } 181 | 182 | #jump_to:hover #jump_wrapper { 183 | display: block; 184 | } 185 | 186 | #jump_page_wrapper{ 187 | position: fixed; 188 | right: 0; 189 | top: 0; 190 | bottom: 0; 191 | } 192 | 193 | #jump_page { 194 | padding: 5px 0 3px; 195 | margin: 0 0 25px 25px; 196 | max-height: 100%; 197 | overflow: auto; 198 | } 199 | 200 | #jump_page .source { 201 | display: block; 202 | padding: 15px; 203 | text-decoration: none; 204 | border-top: 1px solid #eee; 205 | } 206 | 207 | #jump_page .source:hover { 208 | background: #f5f5ff; 209 | } 210 | 211 | #jump_page .source:first-child { 212 | } 213 | 214 | /*---------------------- Low resolutions (> 320px) ---------------------*/ 215 | @media only screen and (min-width: 320px) { 216 | .pilwrap { display: none; } 217 | 218 | ul.sections > li > div { 219 | display: block; 220 | padding:5px 10px 0 10px; 221 | } 222 | 223 | ul.sections > li > div.annotation ul, ul.sections > li > div.annotation ol { 224 | padding-left: 30px; 225 | } 226 | 227 | ul.sections > li > div.content { 228 | overflow-x:auto; 229 | -webkit-box-shadow: inset 0 0 5px #e5e5ee; 230 | box-shadow: inset 0 0 5px #e5e5ee; 231 | border: 1px solid #dedede; 232 | margin:5px 10px 5px 10px; 233 | padding-bottom: 5px; 234 | } 235 | 236 | ul.sections > li > div.annotation pre { 237 | margin: 7px 0 7px; 238 | padding-left: 15px; 239 | } 240 | 241 | ul.sections > li > div.annotation p tt, .annotation code { 242 | background: #f8f8ff; 243 | border: 1px solid #dedede; 244 | font-size: 12px; 245 | padding: 0 0.2em; 246 | } 247 | } 248 | 249 | /*---------------------- (> 481px) ---------------------*/ 250 | @media only screen and (min-width: 481px) { 251 | #container { 252 | position: relative; 253 | } 254 | body { 255 | background-color: #F5F5FF; 256 | font-size: 15px; 257 | line-height: 21px; 258 | } 259 | pre, tt, code { 260 | line-height: 18px; 261 | } 262 | p, ul, ol { 263 | margin: 0 0 15px; 264 | } 265 | 266 | 267 | #jump_to { 268 | padding: 5px 10px; 269 | } 270 | #jump_wrapper { 271 | padding: 0; 272 | } 273 | #jump_to, #jump_page { 274 | font: 10px Arial; 275 | text-transform: uppercase; 276 | } 277 | #jump_page .source { 278 | padding: 5px 10px; 279 | } 280 | #jump_to a.large { 281 | display: inline-block; 282 | } 283 | #jump_to a.small { 284 | display: none; 285 | } 286 | 287 | 288 | 289 | #background { 290 | position: absolute; 291 | top: 0; bottom: 0; 292 | width: 350px; 293 | background: #fff; 294 | border-right: 1px solid #e5e5ee; 295 | z-index: -1; 296 | } 297 | 298 | ul.sections > li > div.annotation ul, ul.sections > li > div.annotation ol { 299 | padding-left: 40px; 300 | } 301 | 302 | ul.sections > li { 303 | white-space: nowrap; 304 | } 305 | 306 | ul.sections > li > div { 307 | display: inline-block; 308 | } 309 | 310 | ul.sections > li > div.annotation { 311 | max-width: 350px; 312 | min-width: 350px; 313 | min-height: 5px; 314 | padding: 13px; 315 | overflow-x: hidden; 316 | white-space: normal; 317 | vertical-align: top; 318 | text-align: left; 319 | } 320 | ul.sections > li > div.annotation pre { 321 | margin: 15px 0 15px; 322 | padding-left: 15px; 323 | } 324 | 325 | ul.sections > li > div.content { 326 | padding: 13px; 327 | vertical-align: top; 328 | border: none; 329 | -webkit-box-shadow: none; 330 | box-shadow: none; 331 | } 332 | 333 | .pilwrap { 334 | position: relative; 335 | display: inline; 336 | } 337 | 338 | .pilcrow { 339 | font: 12px Arial; 340 | text-decoration: none; 341 | color: #454545; 342 | position: absolute; 343 | top: 3px; left: -20px; 344 | padding: 1px 2px; 345 | opacity: 0; 346 | -webkit-transition: opacity 0.2s linear; 347 | } 348 | .for-h1 .pilcrow { 349 | top: 47px; 350 | } 351 | .for-h2 .pilcrow, .for-h3 .pilcrow, .for-h4 .pilcrow { 352 | top: 35px; 353 | } 354 | 355 | ul.sections > li > div.annotation:hover .pilcrow { 356 | opacity: 1; 357 | } 358 | } 359 | 360 | /*---------------------- (> 1025px) ---------------------*/ 361 | @media only screen and (min-width: 1025px) { 362 | 363 | body { 364 | font-size: 16px; 365 | line-height: 24px; 366 | } 367 | 368 | #background { 369 | width: 525px; 370 | } 371 | ul.sections > li > div.annotation { 372 | max-width: 525px; 373 | min-width: 525px; 374 | padding: 10px 25px 1px 50px; 375 | } 376 | ul.sections > li > div.content { 377 | padding: 9px 15px 16px 25px; 378 | } 379 | } 380 | 381 | /*---------------------- Syntax Highlighting -----------------------------*/ 382 | 383 | td.linenos { background-color: #f0f0f0; padding-right: 10px; } 384 | span.lineno { background-color: #f0f0f0; padding: 0 5px 0 5px; } 385 | /* 386 | 387 | github.com style (c) Vasily Polovnyov 388 | 389 | */ 390 | 391 | pre code { 392 | display: block; padding: 0.5em; 393 | color: #000; 394 | background: #f8f8ff 395 | } 396 | 397 | pre .hljs-comment, 398 | pre .hljs-template_comment, 399 | pre .hljs-diff .hljs-header, 400 | pre .hljs-javadoc { 401 | color: #408080; 402 | font-style: italic 403 | } 404 | 405 | pre .hljs-keyword, 406 | pre .hljs-assignment, 407 | pre .hljs-literal, 408 | pre .hljs-css .hljs-rule .hljs-keyword, 409 | pre .hljs-winutils, 410 | pre .hljs-javascript .hljs-title, 411 | pre .hljs-lisp .hljs-title, 412 | pre .hljs-subst { 413 | color: #954121; 414 | /*font-weight: bold*/ 415 | } 416 | 417 | pre .hljs-number, 418 | pre .hljs-hexcolor { 419 | color: #40a070 420 | } 421 | 422 | pre .hljs-string, 423 | pre .hljs-tag .hljs-value, 424 | pre .hljs-phpdoc, 425 | pre .hljs-tex .hljs-formula { 426 | color: #219161; 427 | } 428 | 429 | pre .hljs-title, 430 | pre .hljs-id { 431 | color: #19469D; 432 | } 433 | pre .hljs-params { 434 | color: #00F; 435 | } 436 | 437 | pre .hljs-javascript .hljs-title, 438 | pre .hljs-lisp .hljs-title, 439 | pre .hljs-subst { 440 | font-weight: normal 441 | } 442 | 443 | pre .hljs-class .hljs-title, 444 | pre .hljs-haskell .hljs-label, 445 | pre .hljs-tex .hljs-command { 446 | color: #458; 447 | font-weight: bold 448 | } 449 | 450 | pre .hljs-tag, 451 | pre .hljs-tag .hljs-title, 452 | pre .hljs-rules .hljs-property, 453 | pre .hljs-django .hljs-tag .hljs-keyword { 454 | color: #000080; 455 | font-weight: normal 456 | } 457 | 458 | pre .hljs-attribute, 459 | pre .hljs-variable, 460 | pre .hljs-instancevar, 461 | pre .hljs-lisp .hljs-body { 462 | color: #008080 463 | } 464 | 465 | pre .hljs-regexp { 466 | color: #B68 467 | } 468 | 469 | pre .hljs-class { 470 | color: #458; 471 | font-weight: bold 472 | } 473 | 474 | pre .hljs-symbol, 475 | pre .hljs-ruby .hljs-symbol .hljs-string, 476 | pre .hljs-ruby .hljs-symbol .hljs-keyword, 477 | pre .hljs-ruby .hljs-symbol .hljs-keymethods, 478 | pre .hljs-lisp .hljs-keyword, 479 | pre .hljs-tex .hljs-special, 480 | pre .hljs-input_number { 481 | color: #990073 482 | } 483 | 484 | pre .hljs-builtin, 485 | pre .hljs-constructor, 486 | pre .hljs-built_in, 487 | pre .hljs-lisp .hljs-title { 488 | color: #0086b3 489 | } 490 | 491 | pre .hljs-preprocessor, 492 | pre .hljs-pi, 493 | pre .hljs-doctype, 494 | pre .hljs-shebang, 495 | pre .hljs-cdata { 496 | color: #999; 497 | font-weight: bold 498 | } 499 | 500 | pre .hljs-deletion { 501 | background: #fdd 502 | } 503 | 504 | pre .hljs-addition { 505 | background: #dfd 506 | } 507 | 508 | pre .hljs-diff .hljs-change { 509 | background: #0086b3 510 | } 511 | 512 | pre .hljs-chunk { 513 | color: #aaa 514 | } 515 | 516 | pre .hljs-tex .hljs-formula { 517 | opacity: 0.5; 518 | } 519 | -------------------------------------------------------------------------------- /docs/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jashkenas/underscore/0d820ef7292cdec28dd8b5d565921b8100ca3397/docs/favicon.ico -------------------------------------------------------------------------------- /docs/images/background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jashkenas/underscore/0d820ef7292cdec28dd8b5d565921b8100ca3397/docs/images/background.png -------------------------------------------------------------------------------- /docs/images/underscore.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jashkenas/underscore/0d820ef7292cdec28dd8b5d565921b8100ca3397/docs/images/underscore.png -------------------------------------------------------------------------------- /docs/linked-esm.jst: -------------------------------------------------------------------------------- 1 | <% /* 2 | This is an extended version of the resources/parallel/docco.jst that is 3 | bundled with Docco 0.8.0. 4 | The license of the original file is available over here: 5 | https://github.com/jashkenas/docco/blob/master/LICENSE. 6 | The extension adds hyperlinking to javascript import statements. 7 | */ %> 8 | 9 | 10 | 11 | 12 | <%= title %> 13 | 14 | 15 | 16 | 17 | 18 |
19 |
20 | <% if (sources.length > 1) { %> 21 | 38 | <% } %> 39 | 63 |
64 | <% /* Start of hyperlinking extension */ %> 65 | 66 | 106 | <% /* End of hyperlinking extension */ %> 107 | 108 | 109 | -------------------------------------------------------------------------------- /docs/main.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | var functions = document.querySelectorAll('[data-name]'); 3 | var sections = document.querySelectorAll('.searchable_section'); 4 | var searchInput = document.getElementById('function_filter'); 5 | 6 | function searchValue() { 7 | return searchInput.value.trim().replace(/^_\.?/, ''); 8 | } 9 | 10 | function strIn(a, b) { 11 | a = a.toLowerCase(); 12 | b = b.toLowerCase(); 13 | return b.indexOf(a) >= 0; 14 | } 15 | 16 | function doesMatch(element) { 17 | var name = element.getAttribute('data-name'); 18 | var aliases = element.getAttribute('data-aliases') || ''; 19 | var value = searchValue(); 20 | return strIn(value, name) || strIn(value, aliases); 21 | } 22 | 23 | function filterElement(element) { 24 | element.style.display = doesMatch(element) ? '' : 'none'; 25 | } 26 | 27 | function filterToc() { 28 | _.each(functions, filterElement); 29 | 30 | var emptySearch = searchValue() === ''; 31 | 32 | // Hide the titles of empty sections 33 | _.each(sections, function(section) { 34 | var sectionFunctions = section.querySelectorAll('[data-name]'); 35 | var showSection = emptySearch || _.some(sectionFunctions, doesMatch); 36 | section.style.display = showSection ? '' : 'none'; 37 | }); 38 | } 39 | 40 | function gotoFirst() { 41 | var firstFunction = _.find(functions, doesMatch); 42 | if (firstFunction) { 43 | window.location.hash = firstFunction.getAttribute('data-name'); 44 | searchInput.focus(); 45 | } 46 | } 47 | 48 | searchInput.addEventListener('input', filterToc, false); 49 | 50 | // Press "Enter" to jump to the first matching function 51 | searchInput.addEventListener('keypress', function(e) { 52 | if (e.which === 13) { 53 | gotoFirst(); 54 | } 55 | }); 56 | 57 | // Press "/" to search 58 | document.body.addEventListener('keyup', function(event) { 59 | if (191 === event.which) { 60 | searchInput.focus(); 61 | } 62 | }); 63 | }()); 64 | -------------------------------------------------------------------------------- /docs/public/fonts/aller-bold.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jashkenas/underscore/0d820ef7292cdec28dd8b5d565921b8100ca3397/docs/public/fonts/aller-bold.eot -------------------------------------------------------------------------------- /docs/public/fonts/aller-bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jashkenas/underscore/0d820ef7292cdec28dd8b5d565921b8100ca3397/docs/public/fonts/aller-bold.ttf -------------------------------------------------------------------------------- /docs/public/fonts/aller-bold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jashkenas/underscore/0d820ef7292cdec28dd8b5d565921b8100ca3397/docs/public/fonts/aller-bold.woff -------------------------------------------------------------------------------- /docs/public/fonts/aller-light.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jashkenas/underscore/0d820ef7292cdec28dd8b5d565921b8100ca3397/docs/public/fonts/aller-light.eot -------------------------------------------------------------------------------- /docs/public/fonts/aller-light.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jashkenas/underscore/0d820ef7292cdec28dd8b5d565921b8100ca3397/docs/public/fonts/aller-light.ttf -------------------------------------------------------------------------------- /docs/public/fonts/aller-light.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jashkenas/underscore/0d820ef7292cdec28dd8b5d565921b8100ca3397/docs/public/fonts/aller-light.woff -------------------------------------------------------------------------------- /docs/public/fonts/roboto-black.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jashkenas/underscore/0d820ef7292cdec28dd8b5d565921b8100ca3397/docs/public/fonts/roboto-black.eot -------------------------------------------------------------------------------- /docs/public/fonts/roboto-black.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jashkenas/underscore/0d820ef7292cdec28dd8b5d565921b8100ca3397/docs/public/fonts/roboto-black.ttf -------------------------------------------------------------------------------- /docs/public/fonts/roboto-black.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jashkenas/underscore/0d820ef7292cdec28dd8b5d565921b8100ca3397/docs/public/fonts/roboto-black.woff -------------------------------------------------------------------------------- /docs/public/stylesheets/normalize.css: -------------------------------------------------------------------------------- 1 | /*! normalize.css v2.0.1 | MIT License | git.io/normalize */ 2 | 3 | /* ========================================================================== 4 | HTML5 display definitions 5 | ========================================================================== */ 6 | 7 | /* 8 | * Corrects `block` display not defined in IE 8/9. 9 | */ 10 | 11 | article, 12 | aside, 13 | details, 14 | figcaption, 15 | figure, 16 | footer, 17 | header, 18 | hgroup, 19 | nav, 20 | section, 21 | summary { 22 | display: block; 23 | } 24 | 25 | /* 26 | * Corrects `inline-block` display not defined in IE 8/9. 27 | */ 28 | 29 | audio, 30 | canvas, 31 | video { 32 | display: inline-block; 33 | } 34 | 35 | /* 36 | * Prevents modern browsers from displaying `audio` without controls. 37 | * Remove excess height in iOS 5 devices. 38 | */ 39 | 40 | audio:not([controls]) { 41 | display: none; 42 | height: 0; 43 | } 44 | 45 | /* 46 | * Addresses styling for `hidden` attribute not present in IE 8/9. 47 | */ 48 | 49 | [hidden] { 50 | display: none; 51 | } 52 | 53 | /* ========================================================================== 54 | Base 55 | ========================================================================== */ 56 | 57 | /* 58 | * 1. Sets default font family to sans-serif. 59 | * 2. Prevents iOS text size adjust after orientation change, without disabling 60 | * user zoom. 61 | */ 62 | 63 | html { 64 | font-family: sans-serif; /* 1 */ 65 | -webkit-text-size-adjust: 100%; /* 2 */ 66 | -ms-text-size-adjust: 100%; /* 2 */ 67 | } 68 | 69 | /* 70 | * Removes default margin. 71 | */ 72 | 73 | body { 74 | margin: 0; 75 | } 76 | 77 | /* ========================================================================== 78 | Links 79 | ========================================================================== */ 80 | 81 | /* 82 | * Addresses `outline` inconsistency between Chrome and other browsers. 83 | */ 84 | 85 | a:focus { 86 | outline: thin dotted; 87 | } 88 | 89 | /* 90 | * Improves readability when focused and also mouse hovered in all browsers. 91 | */ 92 | 93 | a:active, 94 | a:hover { 95 | outline: 0; 96 | } 97 | 98 | /* ========================================================================== 99 | Typography 100 | ========================================================================== */ 101 | 102 | /* 103 | * Addresses `h1` font sizes within `section` and `article` in Firefox 4+, 104 | * Safari 5, and Chrome. 105 | */ 106 | 107 | h1 { 108 | font-size: 2em; 109 | } 110 | 111 | /* 112 | * Addresses styling not present in IE 8/9, Safari 5, and Chrome. 113 | */ 114 | 115 | abbr[title] { 116 | border-bottom: 1px dotted; 117 | } 118 | 119 | /* 120 | * Addresses style set to `bolder` in Firefox 4+, Safari 5, and Chrome. 121 | */ 122 | 123 | b, 124 | strong { 125 | font-weight: bold; 126 | } 127 | 128 | /* 129 | * Addresses styling not present in Safari 5 and Chrome. 130 | */ 131 | 132 | dfn { 133 | font-style: italic; 134 | } 135 | 136 | /* 137 | * Addresses styling not present in IE 8/9. 138 | */ 139 | 140 | mark { 141 | background: #ff0; 142 | color: #000; 143 | } 144 | 145 | 146 | /* 147 | * Corrects font family set oddly in Safari 5 and Chrome. 148 | */ 149 | 150 | code, 151 | kbd, 152 | pre, 153 | samp { 154 | font-family: monospace, serif; 155 | font-size: 1em; 156 | } 157 | 158 | /* 159 | * Improves readability of pre-formatted text in all browsers. 160 | */ 161 | 162 | pre { 163 | white-space: pre; 164 | white-space: pre-wrap; 165 | word-wrap: break-word; 166 | } 167 | 168 | /* 169 | * Sets consistent quote types. 170 | */ 171 | 172 | q { 173 | quotes: "\201C" "\201D" "\2018" "\2019"; 174 | } 175 | 176 | /* 177 | * Addresses inconsistent and variable font size in all browsers. 178 | */ 179 | 180 | small { 181 | font-size: 80%; 182 | } 183 | 184 | /* 185 | * Prevents `sub` and `sup` affecting `line-height` in all browsers. 186 | */ 187 | 188 | sub, 189 | sup { 190 | font-size: 75%; 191 | line-height: 0; 192 | position: relative; 193 | vertical-align: baseline; 194 | } 195 | 196 | sup { 197 | top: -0.5em; 198 | } 199 | 200 | sub { 201 | bottom: -0.25em; 202 | } 203 | 204 | /* ========================================================================== 205 | Embedded content 206 | ========================================================================== */ 207 | 208 | /* 209 | * Removes border when inside `a` element in IE 8/9. 210 | */ 211 | 212 | img { 213 | border: 0; 214 | } 215 | 216 | /* 217 | * Corrects overflow displayed oddly in IE 9. 218 | */ 219 | 220 | svg:not(:root) { 221 | overflow: hidden; 222 | } 223 | 224 | /* ========================================================================== 225 | Figures 226 | ========================================================================== */ 227 | 228 | /* 229 | * Addresses margin not present in IE 8/9 and Safari 5. 230 | */ 231 | 232 | figure { 233 | margin: 0; 234 | } 235 | 236 | /* ========================================================================== 237 | Forms 238 | ========================================================================== */ 239 | 240 | /* 241 | * Define consistent border, margin, and padding. 242 | */ 243 | 244 | fieldset { 245 | border: 1px solid #c0c0c0; 246 | margin: 0 2px; 247 | padding: 0.35em 0.625em 0.75em; 248 | } 249 | 250 | /* 251 | * 1. Corrects color not being inherited in IE 8/9. 252 | * 2. Remove padding so people aren't caught out if they zero out fieldsets. 253 | */ 254 | 255 | legend { 256 | border: 0; /* 1 */ 257 | padding: 0; /* 2 */ 258 | } 259 | 260 | /* 261 | * 1. Corrects font family not being inherited in all browsers. 262 | * 2. Corrects font size not being inherited in all browsers. 263 | * 3. Addresses margins set differently in Firefox 4+, Safari 5, and Chrome 264 | */ 265 | 266 | button, 267 | input, 268 | select, 269 | textarea { 270 | font-family: inherit; /* 1 */ 271 | font-size: 100%; /* 2 */ 272 | margin: 0; /* 3 */ 273 | } 274 | 275 | /* 276 | * Addresses Firefox 4+ setting `line-height` on `input` using `!important` in 277 | * the UA stylesheet. 278 | */ 279 | 280 | button, 281 | input { 282 | line-height: normal; 283 | } 284 | 285 | /* 286 | * 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio` 287 | * and `video` controls. 288 | * 2. Corrects inability to style clickable `input` types in iOS. 289 | * 3. Improves usability and consistency of cursor style between image-type 290 | * `input` and others. 291 | */ 292 | 293 | button, 294 | html input[type="button"], /* 1 */ 295 | input[type="reset"], 296 | input[type="submit"] { 297 | -webkit-appearance: button; /* 2 */ 298 | cursor: pointer; /* 3 */ 299 | } 300 | 301 | /* 302 | * Re-set default cursor for disabled elements. 303 | */ 304 | 305 | button[disabled], 306 | input[disabled] { 307 | cursor: default; 308 | } 309 | 310 | /* 311 | * 1. Addresses box sizing set to `content-box` in IE 8/9. 312 | * 2. Removes excess padding in IE 8/9. 313 | */ 314 | 315 | input[type="checkbox"], 316 | input[type="radio"] { 317 | box-sizing: border-box; /* 1 */ 318 | padding: 0; /* 2 */ 319 | } 320 | 321 | /* 322 | * 1. Addresses `appearance` set to `searchfield` in Safari 5 and Chrome. 323 | * 2. Addresses `box-sizing` set to `border-box` in Safari 5 and Chrome 324 | * (include `-moz` to future-proof). 325 | */ 326 | 327 | input[type="search"] { 328 | -webkit-appearance: textfield; /* 1 */ 329 | -moz-box-sizing: content-box; 330 | -webkit-box-sizing: content-box; /* 2 */ 331 | box-sizing: content-box; 332 | } 333 | 334 | /* 335 | * Removes inner padding and search cancel button in Safari 5 and Chrome 336 | * on OS X. 337 | */ 338 | 339 | input[type="search"]::-webkit-search-cancel-button, 340 | input[type="search"]::-webkit-search-decoration { 341 | -webkit-appearance: none; 342 | } 343 | 344 | /* 345 | * Removes inner padding and border in Firefox 4+. 346 | */ 347 | 348 | button::-moz-focus-inner, 349 | input::-moz-focus-inner { 350 | border: 0; 351 | padding: 0; 352 | } 353 | 354 | /* 355 | * 1. Removes default vertical scrollbar in IE 8/9. 356 | * 2. Improves readability and alignment in all browsers. 357 | */ 358 | 359 | textarea { 360 | overflow: auto; /* 1 */ 361 | vertical-align: top; /* 2 */ 362 | } 363 | 364 | /* ========================================================================== 365 | Tables 366 | ========================================================================== */ 367 | 368 | /* 369 | * Remove most spacing between table cells. 370 | */ 371 | 372 | table { 373 | border-collapse: collapse; 374 | border-spacing: 0; 375 | } -------------------------------------------------------------------------------- /favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jashkenas/underscore/0d820ef7292cdec28dd8b5d565921b8100ca3397/favicon.ico -------------------------------------------------------------------------------- /karma.conf-sauce.js: -------------------------------------------------------------------------------- 1 | var _ = require('./'); 2 | 3 | // Browsers to run on Sauce Labs platforms 4 | // (See https://saucelabs.com/platform/supported-browsers-devices for an 5 | // up-to-date overview of supported versions of browsers and platforms.) 6 | var sauceBrowsers = _.reduce([ 7 | ['firefox', 'latest'], 8 | ['firefox', '60'], 9 | ['firefox', '40'], 10 | ['firefox', '11'], 11 | // ['firefox', '4'], // failing due to "not enough arguments" 12 | 13 | ['chrome', 'latest'], 14 | ['chrome', '60'], 15 | ['chrome', '40'], 16 | ['chrome', '26'], 17 | 18 | // latest Edge as well as pre-Blink versions 19 | ['microsoftedge', 'latest', 'Windows 10'], 20 | ['microsoftedge', '18', 'Windows 10'], 21 | ['microsoftedge', '13', 'Windows 10'], 22 | 23 | ['internet explorer', 'latest', 'Windows 10'], 24 | ['internet explorer', '10', 'Windows 8'], 25 | ['internet explorer', '9', 'Windows 7'], 26 | // Older versions of IE no longer supported by Sauce Labs 27 | 28 | ['safari', 'latest', 'macOS 10.15'], 29 | ['safari', '12', 'macOS 10.14'], 30 | ['safari', '11', 'macOS 10.13'], 31 | ['safari', '8', 'OS X 10.10'], 32 | 33 | ], function(memo, platform) { 34 | // internet explorer -> ie 35 | var label = platform[0].split(' '); 36 | if (label.length > 1) { 37 | label = _.invoke(label, 'charAt', 0) 38 | } 39 | label = (label.join("") + '_v' + platform[1]).replace(' ', '_').toUpperCase(); 40 | memo[label] = _.pick({ 41 | 'base': 'SauceLabs', 42 | 'browserName': platform[0], 43 | 'version': platform[1], 44 | 'platform': platform[2] 45 | }, Boolean); 46 | return memo; 47 | }, {}); 48 | 49 | module.exports = function(config) { 50 | if ( !process.env.SAUCE_USERNAME || !process.env.SAUCE_ACCESS_KEY ) { 51 | console.log('Sauce environments not set --- Skipping'); 52 | return process.exit(0); 53 | } 54 | 55 | config.set({ 56 | basePath: '', 57 | frameworks: ['qunit'], 58 | singleRun: true, 59 | browserDisconnectTolerance: 5, 60 | browserNoActivityTimeout: 240000, 61 | 62 | // list of files / patterns to load in the browser 63 | files: [ 64 | 'test/vendor/qunit-extras.js', 65 | 'test/qunit-setup.js', 66 | 'test/overrides.js', 67 | 'underscore-umd.js', 68 | 'test/*.js' 69 | ], 70 | 71 | // Number of sauce tests to start in parallel 72 | concurrency: 9, 73 | 74 | // test results reporter to use 75 | reporters: ['dots', 'saucelabs'], 76 | port: 9876, 77 | colors: true, 78 | logLevel: config.LOG_INFO, 79 | sauceLabs: { 80 | build: 'TRAVIS #' + process.env.TRAVIS_BUILD_NUMBER + ' (' + process.env.TRAVIS_BUILD_ID + ')', 81 | startConnect: true, 82 | tunnelIdentifier: process.env.TRAVIS_JOB_NUMBER 83 | }, 84 | 85 | captureTimeout: 120000, 86 | customLaunchers: sauceBrowsers, 87 | 88 | // Browsers to launch, commented out to prevent karma from starting 89 | // too many concurrent browsers and timing sauce out. 90 | browsers: _.keys(sauceBrowsers) 91 | }); 92 | }; 93 | -------------------------------------------------------------------------------- /karma.conf.js: -------------------------------------------------------------------------------- 1 | // Note some browser launchers should be installed before using karma start. 2 | 3 | // For example: 4 | // $ npm install karma-firefox-launcher 5 | // $ karma start --browser=Firefox 6 | 7 | // See https://karma-runner.github.io/0.8/config/configuration-file.html 8 | module.exports = function(config) { 9 | config.set({ 10 | basePath: '', 11 | frameworks: ['qunit'], 12 | logLevel: config.LOG_INFO, 13 | port: 9876, 14 | 15 | // list of files / patterns to load in the browser 16 | files: [ 17 | 'test/qunit-setup.js', 18 | 'test/overrides.js', 19 | 'underscore-umd.js', 20 | 'test/*.js' 21 | ], 22 | 23 | // Test results reporter to use 24 | // https://npmjs.org/browse/keyword/karma-reporter 25 | reporters: ['progress'], 26 | 27 | // start these browsers 28 | // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher 29 | browsers: ['PhantomJS'], 30 | 31 | // Continuous Integration mode 32 | // if true, Karma captures browsers, runs the tests and exits 33 | singleRun: true 34 | }); 35 | }; -------------------------------------------------------------------------------- /modules/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "parserOptions": { 3 | "ecmaVersion": 6, 4 | "sourceType": "module", 5 | }, 6 | "plugins": [ 7 | "import" 8 | ], 9 | "extends": [ 10 | "plugin:import/errors" 11 | ], 12 | "rules": { 13 | // ExtendScript wrongly gives equal precedence to && and ||. #2949 14 | "no-mixed-operators": [ 15 | "error", 16 | { 17 | "groups": [["&&", "||"]] 18 | } 19 | ] 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /modules/_baseCreate.js: -------------------------------------------------------------------------------- 1 | import isObject from './isObject.js'; 2 | import { nativeCreate } from './_setup.js'; 3 | 4 | // Create a naked function reference for surrogate-prototype-swapping. 5 | function ctor() { 6 | return function(){}; 7 | } 8 | 9 | // An internal function for creating a new object that inherits from another. 10 | export default function baseCreate(prototype) { 11 | if (!isObject(prototype)) return {}; 12 | if (nativeCreate) return nativeCreate(prototype); 13 | var Ctor = ctor(); 14 | Ctor.prototype = prototype; 15 | var result = new Ctor; 16 | Ctor.prototype = null; 17 | return result; 18 | } 19 | -------------------------------------------------------------------------------- /modules/_baseIteratee.js: -------------------------------------------------------------------------------- 1 | import identity from './identity.js'; 2 | import isFunction from './isFunction.js'; 3 | import isObject from './isObject.js'; 4 | import isArray from './isArray.js'; 5 | import matcher from './matcher.js'; 6 | import property from './property.js'; 7 | import optimizeCb from './_optimizeCb.js'; 8 | 9 | // An internal function to generate callbacks that can be applied to each 10 | // element in a collection, returning the desired result — either `_.identity`, 11 | // an arbitrary callback, a property matcher, or a property accessor. 12 | export default function baseIteratee(value, context, argCount) { 13 | if (value == null) return identity; 14 | if (isFunction(value)) return optimizeCb(value, context, argCount); 15 | if (isObject(value) && !isArray(value)) return matcher(value); 16 | return property(value); 17 | } 18 | -------------------------------------------------------------------------------- /modules/_cb.js: -------------------------------------------------------------------------------- 1 | import _ from './underscore.js'; 2 | import baseIteratee from './_baseIteratee.js'; 3 | import iteratee from './iteratee.js'; 4 | 5 | // The function we call internally to generate a callback. It invokes 6 | // `_.iteratee` if overridden, otherwise `baseIteratee`. 7 | export default function cb(value, context, argCount) { 8 | if (_.iteratee !== iteratee) return _.iteratee(value, context); 9 | return baseIteratee(value, context, argCount); 10 | } 11 | -------------------------------------------------------------------------------- /modules/_chainResult.js: -------------------------------------------------------------------------------- 1 | import _ from './underscore.js'; 2 | 3 | // Helper function to continue chaining intermediate results. 4 | export default function chainResult(instance, obj) { 5 | return instance._chain ? _(obj).chain() : obj; 6 | } 7 | -------------------------------------------------------------------------------- /modules/_collectNonEnumProps.js: -------------------------------------------------------------------------------- 1 | import { nonEnumerableProps, ObjProto } from './_setup.js'; 2 | import isFunction from './isFunction.js'; 3 | import has from './_has.js'; 4 | 5 | // Internal helper to create a simple lookup structure. 6 | // `collectNonEnumProps` used to depend on `_.contains`, but this led to 7 | // circular imports. `emulatedSet` is a one-off solution that only works for 8 | // arrays of strings. 9 | function emulatedSet(keys) { 10 | var hash = {}; 11 | for (var l = keys.length, i = 0; i < l; ++i) hash[keys[i]] = true; 12 | return { 13 | contains: function(key) { return hash[key] === true; }, 14 | push: function(key) { 15 | hash[key] = true; 16 | return keys.push(key); 17 | } 18 | }; 19 | } 20 | 21 | // Internal helper. Checks `keys` for the presence of keys in IE < 9 that won't 22 | // be iterated by `for key in ...` and thus missed. Extends `keys` in place if 23 | // needed. 24 | export default function collectNonEnumProps(obj, keys) { 25 | keys = emulatedSet(keys); 26 | var nonEnumIdx = nonEnumerableProps.length; 27 | var constructor = obj.constructor; 28 | var proto = (isFunction(constructor) && constructor.prototype) || ObjProto; 29 | 30 | // Constructor is a special case. 31 | var prop = 'constructor'; 32 | if (has(obj, prop) && !keys.contains(prop)) keys.push(prop); 33 | 34 | while (nonEnumIdx--) { 35 | prop = nonEnumerableProps[nonEnumIdx]; 36 | if (prop in obj && obj[prop] !== proto[prop] && !keys.contains(prop)) { 37 | keys.push(prop); 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /modules/_createAssigner.js: -------------------------------------------------------------------------------- 1 | // An internal function for creating assigner functions. 2 | export default function createAssigner(keysFunc, defaults) { 3 | return function(obj) { 4 | var length = arguments.length; 5 | if (defaults) obj = Object(obj); 6 | if (length < 2 || obj == null) return obj; 7 | for (var index = 1; index < length; index++) { 8 | var source = arguments[index], 9 | keys = keysFunc(source), 10 | l = keys.length; 11 | for (var i = 0; i < l; i++) { 12 | var key = keys[i]; 13 | if (!defaults || obj[key] === void 0) obj[key] = source[key]; 14 | } 15 | } 16 | return obj; 17 | }; 18 | } 19 | -------------------------------------------------------------------------------- /modules/_createEscaper.js: -------------------------------------------------------------------------------- 1 | import keys from './keys.js'; 2 | 3 | // Internal helper to generate functions for escaping and unescaping strings 4 | // to/from HTML interpolation. 5 | export default function createEscaper(map) { 6 | var escaper = function(match) { 7 | return map[match]; 8 | }; 9 | // Regexes for identifying a key that needs to be escaped. 10 | var source = '(?:' + keys(map).join('|') + ')'; 11 | var testRegexp = RegExp(source); 12 | var replaceRegexp = RegExp(source, 'g'); 13 | return function(string) { 14 | string = string == null ? '' : '' + string; 15 | return testRegexp.test(string) ? string.replace(replaceRegexp, escaper) : string; 16 | }; 17 | } 18 | -------------------------------------------------------------------------------- /modules/_createIndexFinder.js: -------------------------------------------------------------------------------- 1 | import getLength from './_getLength.js'; 2 | import { slice } from './_setup.js'; 3 | import isNaN from './isNaN.js'; 4 | 5 | // Internal function to generate the `_.indexOf` and `_.lastIndexOf` functions. 6 | export default function createIndexFinder(dir, predicateFind, sortedIndex) { 7 | return function(array, item, idx) { 8 | var i = 0, length = getLength(array); 9 | if (typeof idx == 'number') { 10 | if (dir > 0) { 11 | i = idx >= 0 ? idx : Math.max(idx + length, i); 12 | } else { 13 | length = idx >= 0 ? Math.min(idx + 1, length) : idx + length + 1; 14 | } 15 | } else if (sortedIndex && idx && length) { 16 | idx = sortedIndex(array, item); 17 | return array[idx] === item ? idx : -1; 18 | } 19 | if (item !== item) { 20 | idx = predicateFind(slice.call(array, i, length), isNaN); 21 | return idx >= 0 ? idx + i : -1; 22 | } 23 | for (idx = dir > 0 ? i : length - 1; idx >= 0 && idx < length; idx += dir) { 24 | if (array[idx] === item) return idx; 25 | } 26 | return -1; 27 | }; 28 | } 29 | -------------------------------------------------------------------------------- /modules/_createPredicateIndexFinder.js: -------------------------------------------------------------------------------- 1 | import cb from './_cb.js'; 2 | import getLength from './_getLength.js'; 3 | 4 | // Internal function to generate `_.findIndex` and `_.findLastIndex`. 5 | export default function createPredicateIndexFinder(dir) { 6 | return function(array, predicate, context) { 7 | predicate = cb(predicate, context); 8 | var length = getLength(array); 9 | var index = dir > 0 ? 0 : length - 1; 10 | for (; index >= 0 && index < length; index += dir) { 11 | if (predicate(array[index], index, array)) return index; 12 | } 13 | return -1; 14 | }; 15 | } 16 | -------------------------------------------------------------------------------- /modules/_createReduce.js: -------------------------------------------------------------------------------- 1 | import isArrayLike from './_isArrayLike.js'; 2 | import keys from './keys.js'; 3 | import optimizeCb from './_optimizeCb.js'; 4 | 5 | // Internal helper to create a reducing function, iterating left or right. 6 | export default function createReduce(dir) { 7 | // Wrap code that reassigns argument variables in a separate function than 8 | // the one that accesses `arguments.length` to avoid a perf hit. (#1991) 9 | var reducer = function(obj, iteratee, memo, initial) { 10 | var _keys = !isArrayLike(obj) && keys(obj), 11 | length = (_keys || obj).length, 12 | index = dir > 0 ? 0 : length - 1; 13 | if (!initial) { 14 | memo = obj[_keys ? _keys[index] : index]; 15 | index += dir; 16 | } 17 | for (; index >= 0 && index < length; index += dir) { 18 | var currentKey = _keys ? _keys[index] : index; 19 | memo = iteratee(memo, obj[currentKey], currentKey, obj); 20 | } 21 | return memo; 22 | }; 23 | 24 | return function(obj, iteratee, memo, context) { 25 | var initial = arguments.length >= 3; 26 | return reducer(obj, optimizeCb(iteratee, context, 4), memo, initial); 27 | }; 28 | } 29 | -------------------------------------------------------------------------------- /modules/_createSizePropertyCheck.js: -------------------------------------------------------------------------------- 1 | import { MAX_ARRAY_INDEX } from './_setup.js'; 2 | 3 | // Common internal logic for `isArrayLike` and `isBufferLike`. 4 | export default function createSizePropertyCheck(getSizeProperty) { 5 | return function(collection) { 6 | var sizeProperty = getSizeProperty(collection); 7 | return typeof sizeProperty == 'number' && sizeProperty >= 0 && sizeProperty <= MAX_ARRAY_INDEX; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /modules/_deepGet.js: -------------------------------------------------------------------------------- 1 | // Internal function to obtain a nested property in `obj` along `path`. 2 | export default function deepGet(obj, path) { 3 | var length = path.length; 4 | for (var i = 0; i < length; i++) { 5 | if (obj == null) return void 0; 6 | obj = obj[path[i]]; 7 | } 8 | return length ? obj : void 0; 9 | } 10 | -------------------------------------------------------------------------------- /modules/_escapeMap.js: -------------------------------------------------------------------------------- 1 | // Internal list of HTML entities for escaping. 2 | export default { 3 | '&': '&', 4 | '<': '<', 5 | '>': '>', 6 | '"': '"', 7 | "'": ''', 8 | '`': '`' 9 | }; 10 | -------------------------------------------------------------------------------- /modules/_executeBound.js: -------------------------------------------------------------------------------- 1 | import baseCreate from './_baseCreate.js'; 2 | import isObject from './isObject.js'; 3 | 4 | // Internal function to execute `sourceFunc` bound to `context` with optional 5 | // `args`. Determines whether to execute a function as a constructor or as a 6 | // normal function. 7 | export default function executeBound(sourceFunc, boundFunc, context, callingContext, args) { 8 | if (!(callingContext instanceof boundFunc)) return sourceFunc.apply(context, args); 9 | var self = baseCreate(sourceFunc.prototype); 10 | var result = sourceFunc.apply(self, args); 11 | if (isObject(result)) return result; 12 | return self; 13 | } 14 | -------------------------------------------------------------------------------- /modules/_flatten.js: -------------------------------------------------------------------------------- 1 | import getLength from './_getLength.js'; 2 | import isArrayLike from './_isArrayLike.js'; 3 | import isArray from './isArray.js'; 4 | import isArguments from './isArguments.js'; 5 | 6 | // Internal implementation of a recursive `flatten` function. 7 | export default function flatten(input, depth, strict, output) { 8 | output = output || []; 9 | if (!depth && depth !== 0) { 10 | depth = Infinity; 11 | } else if (depth <= 0) { 12 | return output.concat(input); 13 | } 14 | var idx = output.length; 15 | for (var i = 0, length = getLength(input); i < length; i++) { 16 | var value = input[i]; 17 | if (isArrayLike(value) && (isArray(value) || isArguments(value))) { 18 | // Flatten current level of array or arguments object. 19 | if (depth > 1) { 20 | flatten(value, depth - 1, strict, output); 21 | idx = output.length; 22 | } else { 23 | var j = 0, len = value.length; 24 | while (j < len) output[idx++] = value[j++]; 25 | } 26 | } else if (!strict) { 27 | output[idx++] = value; 28 | } 29 | } 30 | return output; 31 | } 32 | -------------------------------------------------------------------------------- /modules/_getByteLength.js: -------------------------------------------------------------------------------- 1 | import shallowProperty from './_shallowProperty.js'; 2 | 3 | // Internal helper to obtain the `byteLength` property of an object. 4 | export default shallowProperty('byteLength'); 5 | -------------------------------------------------------------------------------- /modules/_getLength.js: -------------------------------------------------------------------------------- 1 | import shallowProperty from './_shallowProperty.js'; 2 | 3 | // Internal helper to obtain the `length` property of an object. 4 | export default shallowProperty('length'); 5 | -------------------------------------------------------------------------------- /modules/_group.js: -------------------------------------------------------------------------------- 1 | import cb from './_cb.js'; 2 | import each from './each.js'; 3 | 4 | // An internal function used for aggregate "group by" operations. 5 | export default function group(behavior, partition) { 6 | return function(obj, iteratee, context) { 7 | var result = partition ? [[], []] : {}; 8 | iteratee = cb(iteratee, context); 9 | each(obj, function(value, index) { 10 | var key = iteratee(value, index, obj); 11 | behavior(result, value, key); 12 | }); 13 | return result; 14 | }; 15 | } 16 | -------------------------------------------------------------------------------- /modules/_has.js: -------------------------------------------------------------------------------- 1 | import { hasOwnProperty } from './_setup.js'; 2 | 3 | // Internal function to check whether `key` is an own property name of `obj`. 4 | export default function has(obj, key) { 5 | return obj != null && hasOwnProperty.call(obj, key); 6 | } 7 | -------------------------------------------------------------------------------- /modules/_hasObjectTag.js: -------------------------------------------------------------------------------- 1 | import tagTester from './_tagTester.js'; 2 | 3 | export default tagTester('Object'); 4 | -------------------------------------------------------------------------------- /modules/_isArrayLike.js: -------------------------------------------------------------------------------- 1 | import createSizePropertyCheck from './_createSizePropertyCheck.js'; 2 | import getLength from './_getLength.js'; 3 | 4 | // Internal helper for collection methods to determine whether a collection 5 | // should be iterated as an array or as an object. 6 | // Related: https://people.mozilla.org/~jorendorff/es6-draft.html#sec-tolength 7 | // Avoids a very nasty iOS 8 JIT bug on ARM-64. #2094 8 | export default createSizePropertyCheck(getLength); 9 | -------------------------------------------------------------------------------- /modules/_isBufferLike.js: -------------------------------------------------------------------------------- 1 | import createSizePropertyCheck from './_createSizePropertyCheck.js'; 2 | import getByteLength from './_getByteLength.js'; 3 | 4 | // Internal helper to determine whether we should spend extensive checks against 5 | // `ArrayBuffer` et al. 6 | export default createSizePropertyCheck(getByteLength); 7 | -------------------------------------------------------------------------------- /modules/_keyInObj.js: -------------------------------------------------------------------------------- 1 | // Internal `_.pick` helper function to determine whether `key` is an enumerable 2 | // property name of `obj`. 3 | export default function keyInObj(value, key, obj) { 4 | return key in obj; 5 | } 6 | -------------------------------------------------------------------------------- /modules/_methodFingerprint.js: -------------------------------------------------------------------------------- 1 | import getLength from './_getLength.js'; 2 | import isFunction from './isFunction.js'; 3 | import allKeys from './allKeys.js'; 4 | 5 | // Since the regular `Object.prototype.toString` type tests don't work for 6 | // some types in IE 11, we use a fingerprinting heuristic instead, based 7 | // on the methods. It's not great, but it's the best we got. 8 | // The fingerprint method lists are defined below. 9 | export function ie11fingerprint(methods) { 10 | var length = getLength(methods); 11 | return function(obj) { 12 | if (obj == null) return false; 13 | // `Map`, `WeakMap` and `Set` have no enumerable keys. 14 | var keys = allKeys(obj); 15 | if (getLength(keys)) return false; 16 | for (var i = 0; i < length; i++) { 17 | if (!isFunction(obj[methods[i]])) return false; 18 | } 19 | // If we are testing against `WeakMap`, we need to ensure that 20 | // `obj` doesn't have a `forEach` method in order to distinguish 21 | // it from a regular `Map`. 22 | return methods !== weakMapMethods || !isFunction(obj[forEachName]); 23 | }; 24 | } 25 | 26 | // In the interest of compact minification, we write 27 | // each string in the fingerprints only once. 28 | var forEachName = 'forEach', 29 | hasName = 'has', 30 | commonInit = ['clear', 'delete'], 31 | mapTail = ['get', hasName, 'set']; 32 | 33 | // `Map`, `WeakMap` and `Set` each have slightly different 34 | // combinations of the above sublists. 35 | export var mapMethods = commonInit.concat(forEachName, mapTail), 36 | weakMapMethods = commonInit.concat(mapTail), 37 | setMethods = ['add'].concat(commonInit, forEachName, hasName); 38 | -------------------------------------------------------------------------------- /modules/_optimizeCb.js: -------------------------------------------------------------------------------- 1 | // Internal function that returns an efficient (for current engines) version 2 | // of the passed-in callback, to be repeatedly applied in other Underscore 3 | // functions. 4 | export default function optimizeCb(func, context, argCount) { 5 | if (context === void 0) return func; 6 | switch (argCount == null ? 3 : argCount) { 7 | case 1: return function(value) { 8 | return func.call(context, value); 9 | }; 10 | // The 2-argument case is omitted because we’re not using it. 11 | case 3: return function(value, index, collection) { 12 | return func.call(context, value, index, collection); 13 | }; 14 | case 4: return function(accumulator, value, index, collection) { 15 | return func.call(context, accumulator, value, index, collection); 16 | }; 17 | } 18 | return function() { 19 | return func.apply(context, arguments); 20 | }; 21 | } 22 | -------------------------------------------------------------------------------- /modules/_setup.js: -------------------------------------------------------------------------------- 1 | // Current version. 2 | export var VERSION = '1.13.7'; 3 | 4 | // Establish the root object, `window` (`self`) in the browser, `global` 5 | // on the server, or `this` in some virtual machines. We use `self` 6 | // instead of `window` for `WebWorker` support. 7 | export var root = (typeof self == 'object' && self.self === self && self) || 8 | (typeof global == 'object' && global.global === global && global) || 9 | Function('return this')() || 10 | {}; 11 | 12 | // Save bytes in the minified (but not gzipped) version: 13 | export var ArrayProto = Array.prototype, ObjProto = Object.prototype; 14 | export var SymbolProto = typeof Symbol !== 'undefined' ? Symbol.prototype : null; 15 | 16 | // Create quick reference variables for speed access to core prototypes. 17 | export var push = ArrayProto.push, 18 | slice = ArrayProto.slice, 19 | toString = ObjProto.toString, 20 | hasOwnProperty = ObjProto.hasOwnProperty; 21 | 22 | // Modern feature detection. 23 | export var supportsArrayBuffer = typeof ArrayBuffer !== 'undefined', 24 | supportsDataView = typeof DataView !== 'undefined'; 25 | 26 | // All **ECMAScript 5+** native function implementations that we hope to use 27 | // are declared here. 28 | export var nativeIsArray = Array.isArray, 29 | nativeKeys = Object.keys, 30 | nativeCreate = Object.create, 31 | nativeIsView = supportsArrayBuffer && ArrayBuffer.isView; 32 | 33 | // Create references to these builtin functions because we override them. 34 | export var _isNaN = isNaN, 35 | _isFinite = isFinite; 36 | 37 | // Keys in IE < 9 that won't be iterated by `for key in ...` and thus missed. 38 | export var hasEnumBug = !{toString: null}.propertyIsEnumerable('toString'); 39 | export var nonEnumerableProps = ['valueOf', 'isPrototypeOf', 'toString', 40 | 'propertyIsEnumerable', 'hasOwnProperty', 'toLocaleString']; 41 | 42 | // The largest integer that can be represented exactly. 43 | export var MAX_ARRAY_INDEX = Math.pow(2, 53) - 1; 44 | -------------------------------------------------------------------------------- /modules/_shallowProperty.js: -------------------------------------------------------------------------------- 1 | // Internal helper to generate a function to obtain property `key` from `obj`. 2 | export default function shallowProperty(key) { 3 | return function(obj) { 4 | return obj == null ? void 0 : obj[key]; 5 | }; 6 | } 7 | -------------------------------------------------------------------------------- /modules/_stringTagBug.js: -------------------------------------------------------------------------------- 1 | import { supportsDataView } from './_setup.js'; 2 | import hasObjectTag from './_hasObjectTag.js'; 3 | 4 | // In IE 10 - Edge 13, `DataView` has string tag `'[object Object]'`. 5 | // In IE 11, the most common among them, this problem also applies to 6 | // `Map`, `WeakMap` and `Set`. 7 | // Also, there are cases where an application can override the native 8 | // `DataView` object, in cases like that we can't use the constructor 9 | // safely and should just rely on alternate `DataView` checks 10 | export var hasDataViewBug = ( 11 | supportsDataView && (!/\[native code\]/.test(String(DataView)) || hasObjectTag(new DataView(new ArrayBuffer(8)))) 12 | ), 13 | isIE11 = (typeof Map !== 'undefined' && hasObjectTag(new Map)); 14 | -------------------------------------------------------------------------------- /modules/_tagTester.js: -------------------------------------------------------------------------------- 1 | import { toString } from './_setup.js'; 2 | 3 | // Internal function for creating a `toString`-based type tester. 4 | export default function tagTester(name) { 5 | var tag = '[object ' + name + ']'; 6 | return function(obj) { 7 | return toString.call(obj) === tag; 8 | }; 9 | } 10 | -------------------------------------------------------------------------------- /modules/_toBufferView.js: -------------------------------------------------------------------------------- 1 | import getByteLength from './_getByteLength.js'; 2 | 3 | // Internal function to wrap or shallow-copy an ArrayBuffer, 4 | // typed array or DataView to a new view, reusing the buffer. 5 | export default function toBufferView(bufferSource) { 6 | return new Uint8Array( 7 | bufferSource.buffer || bufferSource, 8 | bufferSource.byteOffset || 0, 9 | getByteLength(bufferSource) 10 | ); 11 | } 12 | -------------------------------------------------------------------------------- /modules/_toPath.js: -------------------------------------------------------------------------------- 1 | import _ from './underscore.js'; 2 | import './toPath.js'; 3 | 4 | // Internal wrapper for `_.toPath` to enable minification. 5 | // Similar to `cb` for `_.iteratee`. 6 | export default function toPath(path) { 7 | return _.toPath(path); 8 | } 9 | -------------------------------------------------------------------------------- /modules/_unescapeMap.js: -------------------------------------------------------------------------------- 1 | import invert from './invert.js'; 2 | import escapeMap from './_escapeMap.js'; 3 | 4 | // Internal list of HTML entities for unescaping. 5 | export default invert(escapeMap); 6 | -------------------------------------------------------------------------------- /modules/after.js: -------------------------------------------------------------------------------- 1 | // Returns a function that will only be executed on and after the Nth call. 2 | export default function after(times, func) { 3 | return function() { 4 | if (--times < 1) { 5 | return func.apply(this, arguments); 6 | } 7 | }; 8 | } 9 | -------------------------------------------------------------------------------- /modules/allKeys.js: -------------------------------------------------------------------------------- 1 | import isObject from './isObject.js'; 2 | import { hasEnumBug } from './_setup.js'; 3 | import collectNonEnumProps from './_collectNonEnumProps.js'; 4 | 5 | // Retrieve all the enumerable property names of an object. 6 | export default function allKeys(obj) { 7 | if (!isObject(obj)) return []; 8 | var keys = []; 9 | for (var key in obj) keys.push(key); 10 | // Ahem, IE < 9. 11 | if (hasEnumBug) collectNonEnumProps(obj, keys); 12 | return keys; 13 | } 14 | -------------------------------------------------------------------------------- /modules/before.js: -------------------------------------------------------------------------------- 1 | // Returns a function that will only be executed up to (but not including) the 2 | // Nth call. 3 | export default function before(times, func) { 4 | var memo; 5 | return function() { 6 | if (--times > 0) { 7 | memo = func.apply(this, arguments); 8 | } 9 | if (times <= 1) func = null; 10 | return memo; 11 | }; 12 | } 13 | -------------------------------------------------------------------------------- /modules/bind.js: -------------------------------------------------------------------------------- 1 | import restArguments from './restArguments.js'; 2 | import isFunction from './isFunction.js'; 3 | import executeBound from './_executeBound.js'; 4 | 5 | // Create a function bound to a given object (assigning `this`, and arguments, 6 | // optionally). 7 | export default restArguments(function(func, context, args) { 8 | if (!isFunction(func)) throw new TypeError('Bind must be called on a function'); 9 | var bound = restArguments(function(callArgs) { 10 | return executeBound(func, bound, context, this, args.concat(callArgs)); 11 | }); 12 | return bound; 13 | }); 14 | -------------------------------------------------------------------------------- /modules/bindAll.js: -------------------------------------------------------------------------------- 1 | import restArguments from './restArguments.js'; 2 | import flatten from './_flatten.js'; 3 | import bind from './bind.js'; 4 | 5 | // Bind a number of an object's methods to that object. Remaining arguments 6 | // are the method names to be bound. Useful for ensuring that all callbacks 7 | // defined on an object belong to it. 8 | export default restArguments(function(obj, keys) { 9 | keys = flatten(keys, false, false); 10 | var index = keys.length; 11 | if (index < 1) throw new Error('bindAll must be passed function names'); 12 | while (index--) { 13 | var key = keys[index]; 14 | obj[key] = bind(obj[key], obj); 15 | } 16 | return obj; 17 | }); 18 | -------------------------------------------------------------------------------- /modules/chain.js: -------------------------------------------------------------------------------- 1 | import _ from './underscore.js'; 2 | 3 | // Start chaining a wrapped Underscore object. 4 | export default function chain(obj) { 5 | var instance = _(obj); 6 | instance._chain = true; 7 | return instance; 8 | } 9 | -------------------------------------------------------------------------------- /modules/chunk.js: -------------------------------------------------------------------------------- 1 | import { slice } from './_setup.js'; 2 | 3 | // Chunk a single array into multiple arrays, each containing `count` or fewer 4 | // items. 5 | export default function chunk(array, count) { 6 | if (count == null || count < 1) return []; 7 | var result = []; 8 | var i = 0, length = array.length; 9 | while (i < length) { 10 | result.push(slice.call(array, i, i += count)); 11 | } 12 | return result; 13 | } 14 | -------------------------------------------------------------------------------- /modules/clone.js: -------------------------------------------------------------------------------- 1 | import isObject from './isObject.js'; 2 | import isArray from './isArray.js'; 3 | import extend from './extend.js'; 4 | 5 | // Create a (shallow-cloned) duplicate of an object. 6 | export default function clone(obj) { 7 | if (!isObject(obj)) return obj; 8 | return isArray(obj) ? obj.slice() : extend({}, obj); 9 | } 10 | -------------------------------------------------------------------------------- /modules/compact.js: -------------------------------------------------------------------------------- 1 | import filter from './filter.js'; 2 | 3 | // Trim out all falsy values from an array. 4 | export default function compact(array) { 5 | return filter(array, Boolean); 6 | } 7 | -------------------------------------------------------------------------------- /modules/compose.js: -------------------------------------------------------------------------------- 1 | // Returns a function that is the composition of a list of functions, each 2 | // consuming the return value of the function that follows. 3 | export default function compose() { 4 | var args = arguments; 5 | var start = args.length - 1; 6 | return function() { 7 | var i = start; 8 | var result = args[start].apply(this, arguments); 9 | while (i--) result = args[i].call(this, result); 10 | return result; 11 | }; 12 | } 13 | -------------------------------------------------------------------------------- /modules/constant.js: -------------------------------------------------------------------------------- 1 | // Predicate-generating function. Often useful outside of Underscore. 2 | export default function constant(value) { 3 | return function() { 4 | return value; 5 | }; 6 | } 7 | -------------------------------------------------------------------------------- /modules/contains.js: -------------------------------------------------------------------------------- 1 | import isArrayLike from './_isArrayLike.js'; 2 | import values from './values.js'; 3 | import indexOf from './indexOf.js'; 4 | 5 | // Determine if the array or object contains a given item (using `===`). 6 | export default function contains(obj, item, fromIndex, guard) { 7 | if (!isArrayLike(obj)) obj = values(obj); 8 | if (typeof fromIndex != 'number' || guard) fromIndex = 0; 9 | return indexOf(obj, item, fromIndex) >= 0; 10 | } 11 | -------------------------------------------------------------------------------- /modules/countBy.js: -------------------------------------------------------------------------------- 1 | import group from './_group.js'; 2 | import has from './_has.js'; 3 | 4 | // Counts instances of an object that group by a certain criterion. Pass 5 | // either a string attribute to count by, or a function that returns the 6 | // criterion. 7 | export default group(function(result, value, key) { 8 | if (has(result, key)) result[key]++; else result[key] = 1; 9 | }); 10 | -------------------------------------------------------------------------------- /modules/create.js: -------------------------------------------------------------------------------- 1 | import baseCreate from './_baseCreate.js'; 2 | import extendOwn from './extendOwn.js'; 3 | 4 | // Creates an object that inherits from the given prototype object. 5 | // If additional properties are provided then they will be added to the 6 | // created object. 7 | export default function create(prototype, props) { 8 | var result = baseCreate(prototype); 9 | if (props) extendOwn(result, props); 10 | return result; 11 | } 12 | -------------------------------------------------------------------------------- /modules/debounce.js: -------------------------------------------------------------------------------- 1 | import restArguments from './restArguments.js'; 2 | import now from './now.js'; 3 | 4 | // When a sequence of calls of the returned function ends, the argument 5 | // function is triggered. The end of a sequence is defined by the `wait` 6 | // parameter. If `immediate` is passed, the argument function will be 7 | // triggered at the beginning of the sequence instead of at the end. 8 | export default function debounce(func, wait, immediate) { 9 | var timeout, previous, args, result, context; 10 | 11 | var later = function() { 12 | var passed = now() - previous; 13 | if (wait > passed) { 14 | timeout = setTimeout(later, wait - passed); 15 | } else { 16 | timeout = null; 17 | if (!immediate) result = func.apply(context, args); 18 | // This check is needed because `func` can recursively invoke `debounced`. 19 | if (!timeout) args = context = null; 20 | } 21 | }; 22 | 23 | var debounced = restArguments(function(_args) { 24 | context = this; 25 | args = _args; 26 | previous = now(); 27 | if (!timeout) { 28 | timeout = setTimeout(later, wait); 29 | if (immediate) result = func.apply(context, args); 30 | } 31 | return result; 32 | }); 33 | 34 | debounced.cancel = function() { 35 | clearTimeout(timeout); 36 | timeout = args = context = null; 37 | }; 38 | 39 | return debounced; 40 | } 41 | -------------------------------------------------------------------------------- /modules/defaults.js: -------------------------------------------------------------------------------- 1 | import createAssigner from './_createAssigner.js'; 2 | import allKeys from './allKeys.js'; 3 | 4 | // Fill in a given object with default properties. 5 | export default createAssigner(allKeys, true); 6 | -------------------------------------------------------------------------------- /modules/defer.js: -------------------------------------------------------------------------------- 1 | import partial from './partial.js'; 2 | import delay from './delay.js'; 3 | import _ from './underscore.js'; 4 | 5 | // Defers a function, scheduling it to run after the current call stack has 6 | // cleared. 7 | export default partial(delay, _, 1); 8 | -------------------------------------------------------------------------------- /modules/delay.js: -------------------------------------------------------------------------------- 1 | import restArguments from './restArguments.js'; 2 | 3 | // Delays a function for the given number of milliseconds, and then calls 4 | // it with the arguments supplied. 5 | export default restArguments(function(func, wait, args) { 6 | return setTimeout(function() { 7 | return func.apply(null, args); 8 | }, wait); 9 | }); 10 | -------------------------------------------------------------------------------- /modules/difference.js: -------------------------------------------------------------------------------- 1 | import restArguments from './restArguments.js'; 2 | import flatten from './_flatten.js'; 3 | import filter from './filter.js'; 4 | import contains from './contains.js'; 5 | 6 | // Take the difference between one array and a number of other arrays. 7 | // Only the elements present in just the first array will remain. 8 | export default restArguments(function(array, rest) { 9 | rest = flatten(rest, true, true); 10 | return filter(array, function(value){ 11 | return !contains(rest, value); 12 | }); 13 | }); 14 | -------------------------------------------------------------------------------- /modules/each.js: -------------------------------------------------------------------------------- 1 | import optimizeCb from './_optimizeCb.js'; 2 | import isArrayLike from './_isArrayLike.js'; 3 | import keys from './keys.js'; 4 | 5 | // The cornerstone for collection functions, an `each` 6 | // implementation, aka `forEach`. 7 | // Handles raw objects in addition to array-likes. Treats all 8 | // sparse array-likes as if they were dense. 9 | export default function each(obj, iteratee, context) { 10 | iteratee = optimizeCb(iteratee, context); 11 | var i, length; 12 | if (isArrayLike(obj)) { 13 | for (i = 0, length = obj.length; i < length; i++) { 14 | iteratee(obj[i], i, obj); 15 | } 16 | } else { 17 | var _keys = keys(obj); 18 | for (i = 0, length = _keys.length; i < length; i++) { 19 | iteratee(obj[_keys[i]], _keys[i], obj); 20 | } 21 | } 22 | return obj; 23 | } 24 | -------------------------------------------------------------------------------- /modules/escape.js: -------------------------------------------------------------------------------- 1 | import createEscaper from './_createEscaper.js'; 2 | import escapeMap from './_escapeMap.js'; 3 | 4 | // Function for escaping strings to HTML interpolation. 5 | export default createEscaper(escapeMap); 6 | -------------------------------------------------------------------------------- /modules/every.js: -------------------------------------------------------------------------------- 1 | import cb from './_cb.js'; 2 | import isArrayLike from './_isArrayLike.js'; 3 | import keys from './keys.js'; 4 | 5 | // Determine whether all of the elements pass a truth test. 6 | export default function every(obj, predicate, context) { 7 | predicate = cb(predicate, context); 8 | var _keys = !isArrayLike(obj) && keys(obj), 9 | length = (_keys || obj).length; 10 | for (var index = 0; index < length; index++) { 11 | var currentKey = _keys ? _keys[index] : index; 12 | if (!predicate(obj[currentKey], currentKey, obj)) return false; 13 | } 14 | return true; 15 | } 16 | -------------------------------------------------------------------------------- /modules/extend.js: -------------------------------------------------------------------------------- 1 | import createAssigner from './_createAssigner.js'; 2 | import allKeys from './allKeys.js'; 3 | 4 | // Extend a given object with all the properties in passed-in object(s). 5 | export default createAssigner(allKeys); 6 | -------------------------------------------------------------------------------- /modules/extendOwn.js: -------------------------------------------------------------------------------- 1 | import createAssigner from './_createAssigner.js'; 2 | import keys from './keys.js'; 3 | 4 | // Assigns a given object with all the own properties in the passed-in 5 | // object(s). 6 | // (https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object/assign) 7 | export default createAssigner(keys); 8 | -------------------------------------------------------------------------------- /modules/filter.js: -------------------------------------------------------------------------------- 1 | import cb from './_cb.js'; 2 | import each from './each.js'; 3 | 4 | // Return all the elements that pass a truth test. 5 | export default function filter(obj, predicate, context) { 6 | var results = []; 7 | predicate = cb(predicate, context); 8 | each(obj, function(value, index, list) { 9 | if (predicate(value, index, list)) results.push(value); 10 | }); 11 | return results; 12 | } 13 | -------------------------------------------------------------------------------- /modules/find.js: -------------------------------------------------------------------------------- 1 | import isArrayLike from './_isArrayLike.js'; 2 | import findIndex from './findIndex.js'; 3 | import findKey from './findKey.js'; 4 | 5 | // Return the first value which passes a truth test. 6 | export default function find(obj, predicate, context) { 7 | var keyFinder = isArrayLike(obj) ? findIndex : findKey; 8 | var key = keyFinder(obj, predicate, context); 9 | if (key !== void 0 && key !== -1) return obj[key]; 10 | } 11 | -------------------------------------------------------------------------------- /modules/findIndex.js: -------------------------------------------------------------------------------- 1 | import createPredicateIndexFinder from './_createPredicateIndexFinder.js'; 2 | 3 | // Returns the first index on an array-like that passes a truth test. 4 | export default createPredicateIndexFinder(1); 5 | -------------------------------------------------------------------------------- /modules/findKey.js: -------------------------------------------------------------------------------- 1 | import cb from './_cb.js'; 2 | import keys from './keys.js'; 3 | 4 | // Returns the first key on an object that passes a truth test. 5 | export default function findKey(obj, predicate, context) { 6 | predicate = cb(predicate, context); 7 | var _keys = keys(obj), key; 8 | for (var i = 0, length = _keys.length; i < length; i++) { 9 | key = _keys[i]; 10 | if (predicate(obj[key], key, obj)) return key; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /modules/findLastIndex.js: -------------------------------------------------------------------------------- 1 | import createPredicateIndexFinder from './_createPredicateIndexFinder.js'; 2 | 3 | // Returns the last index on an array-like that passes a truth test. 4 | export default createPredicateIndexFinder(-1); 5 | -------------------------------------------------------------------------------- /modules/findWhere.js: -------------------------------------------------------------------------------- 1 | import find from './find.js'; 2 | import matcher from './matcher.js'; 3 | 4 | // Convenience version of a common use case of `_.find`: getting the first 5 | // object containing specific `key:value` pairs. 6 | export default function findWhere(obj, attrs) { 7 | return find(obj, matcher(attrs)); 8 | } 9 | -------------------------------------------------------------------------------- /modules/first.js: -------------------------------------------------------------------------------- 1 | import initial from './initial.js'; 2 | 3 | // Get the first element of an array. Passing **n** will return the first N 4 | // values in the array. The **guard** check allows it to work with `_.map`. 5 | export default function first(array, n, guard) { 6 | if (array == null || array.length < 1) return n == null || guard ? void 0 : []; 7 | if (n == null || guard) return array[0]; 8 | return initial(array, array.length - n); 9 | } 10 | -------------------------------------------------------------------------------- /modules/flatten.js: -------------------------------------------------------------------------------- 1 | import _flatten from './_flatten.js'; 2 | 3 | // Flatten out an array, either recursively (by default), or up to `depth`. 4 | // Passing `true` or `false` as `depth` means `1` or `Infinity`, respectively. 5 | export default function flatten(array, depth) { 6 | return _flatten(array, depth, false); 7 | } 8 | -------------------------------------------------------------------------------- /modules/functions.js: -------------------------------------------------------------------------------- 1 | import isFunction from './isFunction.js'; 2 | 3 | // Return a sorted list of the function names available on the object. 4 | export default function functions(obj) { 5 | var names = []; 6 | for (var key in obj) { 7 | if (isFunction(obj[key])) names.push(key); 8 | } 9 | return names.sort(); 10 | } 11 | -------------------------------------------------------------------------------- /modules/get.js: -------------------------------------------------------------------------------- 1 | import toPath from './_toPath.js'; 2 | import deepGet from './_deepGet.js'; 3 | import isUndefined from './isUndefined.js'; 4 | 5 | // Get the value of the (deep) property on `path` from `object`. 6 | // If any property in `path` does not exist or if the value is 7 | // `undefined`, return `defaultValue` instead. 8 | // The `path` is normalized through `_.toPath`. 9 | export default function get(object, path, defaultValue) { 10 | var value = deepGet(object, toPath(path)); 11 | return isUndefined(value) ? defaultValue : value; 12 | } 13 | -------------------------------------------------------------------------------- /modules/groupBy.js: -------------------------------------------------------------------------------- 1 | import group from './_group.js'; 2 | import has from './_has.js'; 3 | 4 | // Groups the object's values by a criterion. Pass either a string attribute 5 | // to group by, or a function that returns the criterion. 6 | export default group(function(result, value, key) { 7 | if (has(result, key)) result[key].push(value); else result[key] = [value]; 8 | }); 9 | -------------------------------------------------------------------------------- /modules/has.js: -------------------------------------------------------------------------------- 1 | import _has from './_has.js'; 2 | import toPath from './_toPath.js'; 3 | 4 | // Shortcut function for checking if an object has a given property directly on 5 | // itself (in other words, not on a prototype). Unlike the internal `has` 6 | // function, this public version can also traverse nested properties. 7 | export default function has(obj, path) { 8 | path = toPath(path); 9 | var length = path.length; 10 | for (var i = 0; i < length; i++) { 11 | var key = path[i]; 12 | if (!_has(obj, key)) return false; 13 | obj = obj[key]; 14 | } 15 | return !!length; 16 | } 17 | -------------------------------------------------------------------------------- /modules/identity.js: -------------------------------------------------------------------------------- 1 | // Keep the identity function around for default iteratees. 2 | export default function identity(value) { 3 | return value; 4 | } 5 | -------------------------------------------------------------------------------- /modules/index-all.js: -------------------------------------------------------------------------------- 1 | // ESM Exports 2 | // =========== 3 | // This module is the package entry point for ES module users. In other words, 4 | // it is the module they are interfacing with when they import from the whole 5 | // package instead of from a submodule, like this: 6 | // 7 | // ```js 8 | // import { map } from 'underscore'; 9 | // ``` 10 | // 11 | // The difference with `./index-default`, which is the package entry point for 12 | // CommonJS, AMD and UMD users, is purely technical. In ES modules, named and 13 | // default exports are considered to be siblings, so when you have a default 14 | // export, its properties are not automatically available as named exports. For 15 | // this reason, we re-export the named exports in addition to providing the same 16 | // default export as in `./index-default`. 17 | export { default } from './index-default.js'; 18 | export * from './index.js'; 19 | -------------------------------------------------------------------------------- /modules/index-default.js: -------------------------------------------------------------------------------- 1 | // Default Export 2 | // ============== 3 | // In this module, we mix our bundled exports into the `_` object and export 4 | // the result. This is analogous to setting `module.exports = _` in CommonJS. 5 | // Hence, this module is also the entry point of our UMD bundle and the package 6 | // entry point for CommonJS and AMD users. In other words, this is (the source 7 | // of) the module you are interfacing with when you do any of the following: 8 | // 9 | // ```js 10 | // // CommonJS 11 | // var _ = require('underscore'); 12 | // 13 | // // AMD 14 | // define(['underscore'], function(_) {...}); 15 | // 16 | // // UMD in the browser 17 | // // _ is available as a global variable 18 | // ``` 19 | import * as allExports from './index.js'; 20 | import { mixin } from './index.js'; 21 | 22 | // Add all of the Underscore functions to the wrapper object. 23 | var _ = mixin(allExports); 24 | // Legacy Node.js API. 25 | _._ = _; 26 | // Export the Underscore API. 27 | export default _; 28 | -------------------------------------------------------------------------------- /modules/index.js: -------------------------------------------------------------------------------- 1 | // Named Exports 2 | // ============= 3 | 4 | // Underscore.js 1.13.7 5 | // https://underscorejs.org 6 | // (c) 2009-2024 Jeremy Ashkenas, Julian Gonggrijp, and DocumentCloud and Investigative Reporters & Editors 7 | // Underscore may be freely distributed under the MIT license. 8 | 9 | // Baseline setup. 10 | export { VERSION } from './_setup.js'; 11 | export { default as restArguments } from './restArguments.js'; 12 | 13 | // Object Functions 14 | // ---------------- 15 | // Our most fundamental functions operate on any JavaScript object. 16 | // Most functions in Underscore depend on at least one function in this section. 17 | 18 | // A group of functions that check the types of core JavaScript values. 19 | // These are often informally referred to as the "isType" functions. 20 | export { default as isObject } from './isObject.js'; 21 | export { default as isNull } from './isNull.js'; 22 | export { default as isUndefined } from './isUndefined.js'; 23 | export { default as isBoolean } from './isBoolean.js'; 24 | export { default as isElement } from './isElement.js'; 25 | export { default as isString } from './isString.js'; 26 | export { default as isNumber } from './isNumber.js'; 27 | export { default as isDate } from './isDate.js'; 28 | export { default as isRegExp } from './isRegExp.js'; 29 | export { default as isError } from './isError.js'; 30 | export { default as isSymbol } from './isSymbol.js'; 31 | export { default as isArrayBuffer } from './isArrayBuffer.js'; 32 | export { default as isDataView } from './isDataView.js'; 33 | export { default as isArray } from './isArray.js'; 34 | export { default as isFunction } from './isFunction.js'; 35 | export { default as isArguments } from './isArguments.js'; 36 | export { default as isFinite } from './isFinite.js'; 37 | export { default as isNaN } from './isNaN.js'; 38 | export { default as isTypedArray } from './isTypedArray.js'; 39 | export { default as isEmpty } from './isEmpty.js'; 40 | export { default as isMatch } from './isMatch.js'; 41 | export { default as isEqual } from './isEqual.js'; 42 | export { default as isMap } from './isMap.js'; 43 | export { default as isWeakMap } from './isWeakMap.js'; 44 | export { default as isSet } from './isSet.js'; 45 | export { default as isWeakSet } from './isWeakSet.js'; 46 | 47 | // Functions that treat an object as a dictionary of key-value pairs. 48 | export { default as keys } from './keys.js'; 49 | export { default as allKeys } from './allKeys.js'; 50 | export { default as values } from './values.js'; 51 | export { default as pairs } from './pairs.js'; 52 | export { default as invert } from './invert.js'; 53 | export { default as functions, 54 | default as methods } from './functions.js'; 55 | export { default as extend } from './extend.js'; 56 | export { default as extendOwn, 57 | default as assign } from './extendOwn.js'; 58 | export { default as defaults } from './defaults.js'; 59 | export { default as create } from './create.js'; 60 | export { default as clone } from './clone.js'; 61 | export { default as tap } from './tap.js'; 62 | export { default as get } from './get.js'; 63 | export { default as has } from './has.js'; 64 | export { default as mapObject } from './mapObject.js'; 65 | 66 | // Utility Functions 67 | // ----------------- 68 | // A bit of a grab bag: Predicate-generating functions for use with filters and 69 | // loops, string escaping and templating, create random numbers and unique ids, 70 | // and functions that facilitate Underscore's chaining and iteration conventions. 71 | export { default as identity } from './identity.js'; 72 | export { default as constant } from './constant.js'; 73 | export { default as noop } from './noop.js'; 74 | export { default as toPath } from './toPath.js'; 75 | export { default as property } from './property.js'; 76 | export { default as propertyOf } from './propertyOf.js'; 77 | export { default as matcher, 78 | default as matches } from './matcher.js'; 79 | export { default as times } from './times.js'; 80 | export { default as random } from './random.js'; 81 | export { default as now } from './now.js'; 82 | export { default as escape } from './escape.js'; 83 | export { default as unescape } from './unescape.js'; 84 | export { default as templateSettings } from './templateSettings.js'; 85 | export { default as template } from './template.js'; 86 | export { default as result } from './result.js'; 87 | export { default as uniqueId } from './uniqueId.js'; 88 | export { default as chain } from './chain.js'; 89 | export { default as iteratee } from './iteratee.js'; 90 | 91 | // Function (ahem) Functions 92 | // ------------------------- 93 | // These functions take a function as an argument and return a new function 94 | // as the result. Also known as higher-order functions. 95 | export { default as partial } from './partial.js'; 96 | export { default as bind } from './bind.js'; 97 | export { default as bindAll } from './bindAll.js'; 98 | export { default as memoize } from './memoize.js'; 99 | export { default as delay } from './delay.js'; 100 | export { default as defer } from './defer.js'; 101 | export { default as throttle } from './throttle.js'; 102 | export { default as debounce } from './debounce.js'; 103 | export { default as wrap } from './wrap.js'; 104 | export { default as negate } from './negate.js'; 105 | export { default as compose } from './compose.js'; 106 | export { default as after } from './after.js'; 107 | export { default as before } from './before.js'; 108 | export { default as once } from './once.js'; 109 | 110 | // Finders 111 | // ------- 112 | // Functions that extract (the position of) a single element from an object 113 | // or array based on some criterion. 114 | export { default as findKey } from './findKey.js'; 115 | export { default as findIndex } from './findIndex.js'; 116 | export { default as findLastIndex } from './findLastIndex.js'; 117 | export { default as sortedIndex } from './sortedIndex.js'; 118 | export { default as indexOf } from './indexOf.js'; 119 | export { default as lastIndexOf } from './lastIndexOf.js'; 120 | export { default as find, 121 | default as detect } from './find.js'; 122 | export { default as findWhere } from './findWhere.js'; 123 | 124 | // Collection Functions 125 | // -------------------- 126 | // Functions that work on any collection of elements: either an array, or 127 | // an object of key-value pairs. 128 | export { default as each, 129 | default as forEach } from './each.js'; 130 | export { default as map, 131 | default as collect } from './map.js'; 132 | export { default as reduce, 133 | default as foldl, 134 | default as inject } from './reduce.js'; 135 | export { default as reduceRight, 136 | default as foldr } from './reduceRight.js'; 137 | export { default as filter, 138 | default as select } from './filter.js'; 139 | export { default as reject } from './reject.js'; 140 | export { default as every, 141 | default as all } from './every.js'; 142 | export { default as some, 143 | default as any } from './some.js'; 144 | export { default as contains, 145 | default as includes, 146 | default as include } from './contains.js'; 147 | export { default as invoke } from './invoke.js'; 148 | export { default as pluck } from './pluck.js'; 149 | export { default as where } from './where.js'; 150 | export { default as max } from './max.js'; 151 | export { default as min } from './min.js'; 152 | export { default as shuffle } from './shuffle.js'; 153 | export { default as sample } from './sample.js'; 154 | export { default as sortBy } from './sortBy.js'; 155 | export { default as groupBy } from './groupBy.js'; 156 | export { default as indexBy } from './indexBy.js'; 157 | export { default as countBy } from './countBy.js'; 158 | export { default as partition } from './partition.js'; 159 | export { default as toArray } from './toArray.js'; 160 | export { default as size } from './size.js'; 161 | 162 | // `_.pick` and `_.omit` are actually object functions, but we put 163 | // them here in order to create a more natural reading order in the 164 | // monolithic build as they depend on `_.contains`. 165 | export { default as pick } from './pick.js'; 166 | export { default as omit } from './omit.js'; 167 | 168 | // Array Functions 169 | // --------------- 170 | // Functions that operate on arrays (and array-likes) only, because they’re 171 | // expressed in terms of operations on an ordered list of values. 172 | export { default as first, 173 | default as head, 174 | default as take } from './first.js'; 175 | export { default as initial } from './initial.js'; 176 | export { default as last } from './last.js'; 177 | export { default as rest, 178 | default as tail, 179 | default as drop } from './rest.js'; 180 | export { default as compact } from './compact.js'; 181 | export { default as flatten } from './flatten.js'; 182 | export { default as without } from './without.js'; 183 | export { default as uniq, 184 | default as unique } from './uniq.js'; 185 | export { default as union } from './union.js'; 186 | export { default as intersection } from './intersection.js'; 187 | export { default as difference } from './difference.js'; 188 | export { default as unzip, 189 | default as transpose } from './unzip.js'; 190 | export { default as zip } from './zip.js'; 191 | export { default as object } from './object.js'; 192 | export { default as range } from './range.js'; 193 | export { default as chunk } from './chunk.js'; 194 | 195 | // OOP 196 | // --- 197 | // These modules support the "object-oriented" calling style. See also 198 | // `underscore.js` and `index-default.js`. 199 | export { default as mixin } from './mixin.js'; 200 | export { default } from './underscore-array-methods.js'; 201 | -------------------------------------------------------------------------------- /modules/indexBy.js: -------------------------------------------------------------------------------- 1 | import group from './_group.js'; 2 | 3 | // Indexes the object's values by a criterion, similar to `_.groupBy`, but for 4 | // when you know that your index values will be unique. 5 | export default group(function(result, value, key) { 6 | result[key] = value; 7 | }); 8 | -------------------------------------------------------------------------------- /modules/indexOf.js: -------------------------------------------------------------------------------- 1 | import sortedIndex from './sortedIndex.js'; 2 | import findIndex from './findIndex.js'; 3 | import createIndexFinder from './_createIndexFinder.js'; 4 | 5 | // Return the position of the first occurrence of an item in an array, 6 | // or -1 if the item is not included in the array. 7 | // If the array is large and already in sort order, pass `true` 8 | // for **isSorted** to use binary search. 9 | export default createIndexFinder(1, findIndex, sortedIndex); 10 | -------------------------------------------------------------------------------- /modules/initial.js: -------------------------------------------------------------------------------- 1 | import { slice } from './_setup.js'; 2 | 3 | // Returns everything but the last entry of the array. Especially useful on 4 | // the arguments object. Passing **n** will return all the values in 5 | // the array, excluding the last N. 6 | export default function initial(array, n, guard) { 7 | return slice.call(array, 0, Math.max(0, array.length - (n == null || guard ? 1 : n))); 8 | } 9 | -------------------------------------------------------------------------------- /modules/intersection.js: -------------------------------------------------------------------------------- 1 | import getLength from './_getLength.js'; 2 | import contains from './contains.js'; 3 | 4 | // Produce an array that contains every item shared between all the 5 | // passed-in arrays. 6 | export default function intersection(array) { 7 | var result = []; 8 | var argsLength = arguments.length; 9 | for (var i = 0, length = getLength(array); i < length; i++) { 10 | var item = array[i]; 11 | if (contains(result, item)) continue; 12 | var j; 13 | for (j = 1; j < argsLength; j++) { 14 | if (!contains(arguments[j], item)) break; 15 | } 16 | if (j === argsLength) result.push(item); 17 | } 18 | return result; 19 | } 20 | -------------------------------------------------------------------------------- /modules/invert.js: -------------------------------------------------------------------------------- 1 | import keys from './keys.js'; 2 | 3 | // Invert the keys and values of an object. The values must be serializable. 4 | export default function invert(obj) { 5 | var result = {}; 6 | var _keys = keys(obj); 7 | for (var i = 0, length = _keys.length; i < length; i++) { 8 | result[obj[_keys[i]]] = _keys[i]; 9 | } 10 | return result; 11 | } 12 | -------------------------------------------------------------------------------- /modules/invoke.js: -------------------------------------------------------------------------------- 1 | import restArguments from './restArguments.js'; 2 | import isFunction from './isFunction.js'; 3 | import map from './map.js'; 4 | import deepGet from './_deepGet.js'; 5 | import toPath from './_toPath.js'; 6 | 7 | // Invoke a method (with arguments) on every item in a collection. 8 | export default restArguments(function(obj, path, args) { 9 | var contextPath, func; 10 | if (isFunction(path)) { 11 | func = path; 12 | } else { 13 | path = toPath(path); 14 | contextPath = path.slice(0, -1); 15 | path = path[path.length - 1]; 16 | } 17 | return map(obj, function(context) { 18 | var method = func; 19 | if (!method) { 20 | if (contextPath && contextPath.length) { 21 | context = deepGet(context, contextPath); 22 | } 23 | if (context == null) return void 0; 24 | method = context[path]; 25 | } 26 | return method == null ? method : method.apply(context, args); 27 | }); 28 | }); 29 | -------------------------------------------------------------------------------- /modules/isArguments.js: -------------------------------------------------------------------------------- 1 | import tagTester from './_tagTester.js'; 2 | import has from './_has.js'; 3 | 4 | var isArguments = tagTester('Arguments'); 5 | 6 | // Define a fallback version of the method in browsers (ahem, IE < 9), where 7 | // there isn't any inspectable "Arguments" type. 8 | (function() { 9 | if (!isArguments(arguments)) { 10 | isArguments = function(obj) { 11 | return has(obj, 'callee'); 12 | }; 13 | } 14 | }()); 15 | 16 | export default isArguments; 17 | -------------------------------------------------------------------------------- /modules/isArray.js: -------------------------------------------------------------------------------- 1 | import { nativeIsArray } from './_setup.js'; 2 | import tagTester from './_tagTester.js'; 3 | 4 | // Is a given value an array? 5 | // Delegates to ECMA5's native `Array.isArray`. 6 | export default nativeIsArray || tagTester('Array'); 7 | -------------------------------------------------------------------------------- /modules/isArrayBuffer.js: -------------------------------------------------------------------------------- 1 | import tagTester from './_tagTester.js'; 2 | 3 | export default tagTester('ArrayBuffer'); 4 | -------------------------------------------------------------------------------- /modules/isBoolean.js: -------------------------------------------------------------------------------- 1 | import { toString } from './_setup.js'; 2 | 3 | // Is a given value a boolean? 4 | export default function isBoolean(obj) { 5 | return obj === true || obj === false || toString.call(obj) === '[object Boolean]'; 6 | } 7 | -------------------------------------------------------------------------------- /modules/isDataView.js: -------------------------------------------------------------------------------- 1 | import tagTester from './_tagTester.js'; 2 | import isFunction from './isFunction.js'; 3 | import isArrayBuffer from './isArrayBuffer.js'; 4 | import { hasDataViewBug } from './_stringTagBug.js'; 5 | 6 | var isDataView = tagTester('DataView'); 7 | 8 | // In IE 10 - Edge 13, we need a different heuristic 9 | // to determine whether an object is a `DataView`. 10 | // Also, in cases where the native `DataView` is 11 | // overridden we can't rely on the tag itself. 12 | function alternateIsDataView(obj) { 13 | return obj != null && isFunction(obj.getInt8) && isArrayBuffer(obj.buffer); 14 | } 15 | 16 | export default (hasDataViewBug ? alternateIsDataView : isDataView); 17 | -------------------------------------------------------------------------------- /modules/isDate.js: -------------------------------------------------------------------------------- 1 | import tagTester from './_tagTester.js'; 2 | 3 | export default tagTester('Date'); 4 | -------------------------------------------------------------------------------- /modules/isElement.js: -------------------------------------------------------------------------------- 1 | // Is a given value a DOM element? 2 | export default function isElement(obj) { 3 | return !!(obj && obj.nodeType === 1); 4 | } 5 | -------------------------------------------------------------------------------- /modules/isEmpty.js: -------------------------------------------------------------------------------- 1 | import getLength from './_getLength.js'; 2 | import isArray from './isArray.js'; 3 | import isString from './isString.js'; 4 | import isArguments from './isArguments.js'; 5 | import keys from './keys.js'; 6 | 7 | // Is a given array, string, or object empty? 8 | // An "empty" object has no enumerable own-properties. 9 | export default function isEmpty(obj) { 10 | if (obj == null) return true; 11 | // Skip the more expensive `toString`-based type checks if `obj` has no 12 | // `.length`. 13 | var length = getLength(obj); 14 | if (typeof length == 'number' && ( 15 | isArray(obj) || isString(obj) || isArguments(obj) 16 | )) return length === 0; 17 | return getLength(keys(obj)) === 0; 18 | } 19 | -------------------------------------------------------------------------------- /modules/isEqual.js: -------------------------------------------------------------------------------- 1 | import _ from './underscore.js'; 2 | import { toString, SymbolProto } from './_setup.js'; 3 | import getByteLength from './_getByteLength.js'; 4 | import isTypedArray from './isTypedArray.js'; 5 | import isFunction from './isFunction.js'; 6 | import { hasDataViewBug } from './_stringTagBug.js'; 7 | import isDataView from './isDataView.js'; 8 | import keys from './keys.js'; 9 | import has from './_has.js'; 10 | import toBufferView from './_toBufferView.js'; 11 | 12 | // We use this string twice, so give it a name for minification. 13 | var tagDataView = '[object DataView]'; 14 | 15 | // Internal recursive comparison function for `_.isEqual`. 16 | function eq(a, b, aStack, bStack) { 17 | // Identical objects are equal. `0 === -0`, but they aren't identical. 18 | // See the [Harmony `egal` proposal](https://wiki.ecmascript.org/doku.php?id=harmony:egal). 19 | if (a === b) return a !== 0 || 1 / a === 1 / b; 20 | // `null` or `undefined` only equal to itself (strict comparison). 21 | if (a == null || b == null) return false; 22 | // `NaN`s are equivalent, but non-reflexive. 23 | if (a !== a) return b !== b; 24 | // Exhaust primitive checks 25 | var type = typeof a; 26 | if (type !== 'function' && type !== 'object' && typeof b != 'object') return false; 27 | return deepEq(a, b, aStack, bStack); 28 | } 29 | 30 | // Internal recursive comparison function for `_.isEqual`. 31 | function deepEq(a, b, aStack, bStack) { 32 | // Unwrap any wrapped objects. 33 | if (a instanceof _) a = a._wrapped; 34 | if (b instanceof _) b = b._wrapped; 35 | // Compare `[[Class]]` names. 36 | var className = toString.call(a); 37 | if (className !== toString.call(b)) return false; 38 | // Work around a bug in IE 10 - Edge 13. 39 | if (hasDataViewBug && className == '[object Object]' && isDataView(a)) { 40 | if (!isDataView(b)) return false; 41 | className = tagDataView; 42 | } 43 | switch (className) { 44 | // These types are compared by value. 45 | case '[object RegExp]': 46 | // RegExps are coerced to strings for comparison (Note: '' + /a/i === '/a/i') 47 | case '[object String]': 48 | // Primitives and their corresponding object wrappers are equivalent; thus, `"5"` is 49 | // equivalent to `new String("5")`. 50 | return '' + a === '' + b; 51 | case '[object Number]': 52 | // `NaN`s are equivalent, but non-reflexive. 53 | // Object(NaN) is equivalent to NaN. 54 | if (+a !== +a) return +b !== +b; 55 | // An `egal` comparison is performed for other numeric values. 56 | return +a === 0 ? 1 / +a === 1 / b : +a === +b; 57 | case '[object Date]': 58 | case '[object Boolean]': 59 | // Coerce dates and booleans to numeric primitive values. Dates are compared by their 60 | // millisecond representations. Note that invalid dates with millisecond representations 61 | // of `NaN` are not equivalent. 62 | return +a === +b; 63 | case '[object Symbol]': 64 | return SymbolProto.valueOf.call(a) === SymbolProto.valueOf.call(b); 65 | case '[object ArrayBuffer]': 66 | case tagDataView: 67 | // Coerce to typed array so we can fall through. 68 | return deepEq(toBufferView(a), toBufferView(b), aStack, bStack); 69 | } 70 | 71 | var areArrays = className === '[object Array]'; 72 | if (!areArrays && isTypedArray(a)) { 73 | var byteLength = getByteLength(a); 74 | if (byteLength !== getByteLength(b)) return false; 75 | if (a.buffer === b.buffer && a.byteOffset === b.byteOffset) return true; 76 | areArrays = true; 77 | } 78 | if (!areArrays) { 79 | if (typeof a != 'object' || typeof b != 'object') return false; 80 | 81 | // Objects with different constructors are not equivalent, but `Object`s or `Array`s 82 | // from different frames are. 83 | var aCtor = a.constructor, bCtor = b.constructor; 84 | if (aCtor !== bCtor && !(isFunction(aCtor) && aCtor instanceof aCtor && 85 | isFunction(bCtor) && bCtor instanceof bCtor) 86 | && ('constructor' in a && 'constructor' in b)) { 87 | return false; 88 | } 89 | } 90 | // Assume equality for cyclic structures. The algorithm for detecting cyclic 91 | // structures is adapted from ES 5.1 section 15.12.3, abstract operation `JO`. 92 | 93 | // Initializing stack of traversed objects. 94 | // It's done here since we only need them for objects and arrays comparison. 95 | aStack = aStack || []; 96 | bStack = bStack || []; 97 | var length = aStack.length; 98 | while (length--) { 99 | // Linear search. Performance is inversely proportional to the number of 100 | // unique nested structures. 101 | if (aStack[length] === a) return bStack[length] === b; 102 | } 103 | 104 | // Add the first object to the stack of traversed objects. 105 | aStack.push(a); 106 | bStack.push(b); 107 | 108 | // Recursively compare objects and arrays. 109 | if (areArrays) { 110 | // Compare array lengths to determine if a deep comparison is necessary. 111 | length = a.length; 112 | if (length !== b.length) return false; 113 | // Deep compare the contents, ignoring non-numeric properties. 114 | while (length--) { 115 | if (!eq(a[length], b[length], aStack, bStack)) return false; 116 | } 117 | } else { 118 | // Deep compare objects. 119 | var _keys = keys(a), key; 120 | length = _keys.length; 121 | // Ensure that both objects contain the same number of properties before comparing deep equality. 122 | if (keys(b).length !== length) return false; 123 | while (length--) { 124 | // Deep compare each member 125 | key = _keys[length]; 126 | if (!(has(b, key) && eq(a[key], b[key], aStack, bStack))) return false; 127 | } 128 | } 129 | // Remove the first object from the stack of traversed objects. 130 | aStack.pop(); 131 | bStack.pop(); 132 | return true; 133 | } 134 | 135 | // Perform a deep comparison to check if two objects are equal. 136 | export default function isEqual(a, b) { 137 | return eq(a, b); 138 | } 139 | -------------------------------------------------------------------------------- /modules/isError.js: -------------------------------------------------------------------------------- 1 | import tagTester from './_tagTester.js'; 2 | 3 | export default tagTester('Error'); 4 | -------------------------------------------------------------------------------- /modules/isFinite.js: -------------------------------------------------------------------------------- 1 | import { _isFinite } from './_setup.js'; 2 | import isSymbol from './isSymbol.js'; 3 | 4 | // Is a given object a finite number? 5 | export default function isFinite(obj) { 6 | return !isSymbol(obj) && _isFinite(obj) && !isNaN(parseFloat(obj)); 7 | } 8 | -------------------------------------------------------------------------------- /modules/isFunction.js: -------------------------------------------------------------------------------- 1 | import tagTester from './_tagTester.js'; 2 | import { root } from './_setup.js'; 3 | 4 | var isFunction = tagTester('Function'); 5 | 6 | // Optimize `isFunction` if appropriate. Work around some `typeof` bugs in old 7 | // v8, IE 11 (#1621), Safari 8 (#1929), and PhantomJS (#2236). 8 | var nodelist = root.document && root.document.childNodes; 9 | if (typeof /./ != 'function' && typeof Int8Array != 'object' && typeof nodelist != 'function') { 10 | isFunction = function(obj) { 11 | return typeof obj == 'function' || false; 12 | }; 13 | } 14 | 15 | export default isFunction; 16 | -------------------------------------------------------------------------------- /modules/isMap.js: -------------------------------------------------------------------------------- 1 | import tagTester from './_tagTester.js'; 2 | import { isIE11 } from './_stringTagBug.js'; 3 | import { ie11fingerprint, mapMethods } from './_methodFingerprint.js'; 4 | 5 | export default isIE11 ? ie11fingerprint(mapMethods) : tagTester('Map'); 6 | -------------------------------------------------------------------------------- /modules/isMatch.js: -------------------------------------------------------------------------------- 1 | import keys from './keys.js'; 2 | 3 | // Returns whether an object has a given set of `key:value` pairs. 4 | export default function isMatch(object, attrs) { 5 | var _keys = keys(attrs), length = _keys.length; 6 | if (object == null) return !length; 7 | var obj = Object(object); 8 | for (var i = 0; i < length; i++) { 9 | var key = _keys[i]; 10 | if (attrs[key] !== obj[key] || !(key in obj)) return false; 11 | } 12 | return true; 13 | } 14 | -------------------------------------------------------------------------------- /modules/isNaN.js: -------------------------------------------------------------------------------- 1 | import { _isNaN } from './_setup.js'; 2 | import isNumber from './isNumber.js'; 3 | 4 | // Is the given value `NaN`? 5 | export default function isNaN(obj) { 6 | return isNumber(obj) && _isNaN(obj); 7 | } 8 | -------------------------------------------------------------------------------- /modules/isNull.js: -------------------------------------------------------------------------------- 1 | // Is a given value equal to null? 2 | export default function isNull(obj) { 3 | return obj === null; 4 | } 5 | -------------------------------------------------------------------------------- /modules/isNumber.js: -------------------------------------------------------------------------------- 1 | import tagTester from './_tagTester.js'; 2 | 3 | export default tagTester('Number'); 4 | -------------------------------------------------------------------------------- /modules/isObject.js: -------------------------------------------------------------------------------- 1 | // Is a given variable an object? 2 | export default function isObject(obj) { 3 | var type = typeof obj; 4 | return type === 'function' || (type === 'object' && !!obj); 5 | } 6 | -------------------------------------------------------------------------------- /modules/isRegExp.js: -------------------------------------------------------------------------------- 1 | import tagTester from './_tagTester.js'; 2 | 3 | export default tagTester('RegExp'); 4 | -------------------------------------------------------------------------------- /modules/isSet.js: -------------------------------------------------------------------------------- 1 | import tagTester from './_tagTester.js'; 2 | import { isIE11 } from './_stringTagBug.js'; 3 | import { ie11fingerprint, setMethods } from './_methodFingerprint.js'; 4 | 5 | export default isIE11 ? ie11fingerprint(setMethods) : tagTester('Set'); 6 | -------------------------------------------------------------------------------- /modules/isString.js: -------------------------------------------------------------------------------- 1 | import tagTester from './_tagTester.js'; 2 | 3 | export default tagTester('String'); 4 | -------------------------------------------------------------------------------- /modules/isSymbol.js: -------------------------------------------------------------------------------- 1 | import tagTester from './_tagTester.js'; 2 | 3 | export default tagTester('Symbol'); 4 | -------------------------------------------------------------------------------- /modules/isTypedArray.js: -------------------------------------------------------------------------------- 1 | import { supportsArrayBuffer, nativeIsView, toString } from './_setup.js'; 2 | import isDataView from './isDataView.js'; 3 | import constant from './constant.js'; 4 | import isBufferLike from './_isBufferLike.js'; 5 | 6 | // Is a given value a typed array? 7 | var typedArrayPattern = /\[object ((I|Ui)nt(8|16|32)|Float(32|64)|Uint8Clamped|Big(I|Ui)nt64)Array\]/; 8 | function isTypedArray(obj) { 9 | // `ArrayBuffer.isView` is the most future-proof, so use it when available. 10 | // Otherwise, fall back on the above regular expression. 11 | return nativeIsView ? (nativeIsView(obj) && !isDataView(obj)) : 12 | isBufferLike(obj) && typedArrayPattern.test(toString.call(obj)); 13 | } 14 | 15 | export default supportsArrayBuffer ? isTypedArray : constant(false); 16 | -------------------------------------------------------------------------------- /modules/isUndefined.js: -------------------------------------------------------------------------------- 1 | // Is a given variable undefined? 2 | export default function isUndefined(obj) { 3 | return obj === void 0; 4 | } 5 | -------------------------------------------------------------------------------- /modules/isWeakMap.js: -------------------------------------------------------------------------------- 1 | import tagTester from './_tagTester.js'; 2 | import { isIE11 } from './_stringTagBug.js'; 3 | import { ie11fingerprint, weakMapMethods } from './_methodFingerprint.js'; 4 | 5 | export default isIE11 ? ie11fingerprint(weakMapMethods) : tagTester('WeakMap'); 6 | -------------------------------------------------------------------------------- /modules/isWeakSet.js: -------------------------------------------------------------------------------- 1 | import tagTester from './_tagTester.js'; 2 | 3 | export default tagTester('WeakSet'); 4 | -------------------------------------------------------------------------------- /modules/iteratee.js: -------------------------------------------------------------------------------- 1 | import _ from './underscore.js'; 2 | import baseIteratee from './_baseIteratee.js'; 3 | 4 | // External wrapper for our callback generator. Users may customize 5 | // `_.iteratee` if they want additional predicate/iteratee shorthand styles. 6 | // This abstraction hides the internal-only `argCount` argument. 7 | export default function iteratee(value, context) { 8 | return baseIteratee(value, context, Infinity); 9 | } 10 | _.iteratee = iteratee; 11 | -------------------------------------------------------------------------------- /modules/keys.js: -------------------------------------------------------------------------------- 1 | import isObject from './isObject.js'; 2 | import { nativeKeys, hasEnumBug } from './_setup.js'; 3 | import has from './_has.js'; 4 | import collectNonEnumProps from './_collectNonEnumProps.js'; 5 | 6 | // Retrieve the names of an object's own properties. 7 | // Delegates to **ECMAScript 5**'s native `Object.keys`. 8 | export default function keys(obj) { 9 | if (!isObject(obj)) return []; 10 | if (nativeKeys) return nativeKeys(obj); 11 | var keys = []; 12 | for (var key in obj) if (has(obj, key)) keys.push(key); 13 | // Ahem, IE < 9. 14 | if (hasEnumBug) collectNonEnumProps(obj, keys); 15 | return keys; 16 | } 17 | -------------------------------------------------------------------------------- /modules/last.js: -------------------------------------------------------------------------------- 1 | import rest from './rest.js'; 2 | 3 | // Get the last element of an array. Passing **n** will return the last N 4 | // values in the array. 5 | export default function last(array, n, guard) { 6 | if (array == null || array.length < 1) return n == null || guard ? void 0 : []; 7 | if (n == null || guard) return array[array.length - 1]; 8 | return rest(array, Math.max(0, array.length - n)); 9 | } 10 | -------------------------------------------------------------------------------- /modules/lastIndexOf.js: -------------------------------------------------------------------------------- 1 | import findLastIndex from './findLastIndex.js'; 2 | import createIndexFinder from './_createIndexFinder.js'; 3 | 4 | // Return the position of the last occurrence of an item in an array, 5 | // or -1 if the item is not included in the array. 6 | export default createIndexFinder(-1, findLastIndex); 7 | -------------------------------------------------------------------------------- /modules/map.js: -------------------------------------------------------------------------------- 1 | import cb from './_cb.js'; 2 | import isArrayLike from './_isArrayLike.js'; 3 | import keys from './keys.js'; 4 | 5 | // Return the results of applying the iteratee to each element. 6 | export default function map(obj, iteratee, context) { 7 | iteratee = cb(iteratee, context); 8 | var _keys = !isArrayLike(obj) && keys(obj), 9 | length = (_keys || obj).length, 10 | results = Array(length); 11 | for (var index = 0; index < length; index++) { 12 | var currentKey = _keys ? _keys[index] : index; 13 | results[index] = iteratee(obj[currentKey], currentKey, obj); 14 | } 15 | return results; 16 | } 17 | -------------------------------------------------------------------------------- /modules/mapObject.js: -------------------------------------------------------------------------------- 1 | import cb from './_cb.js'; 2 | import keys from './keys.js'; 3 | 4 | // Returns the results of applying the `iteratee` to each element of `obj`. 5 | // In contrast to `_.map` it returns an object. 6 | export default function mapObject(obj, iteratee, context) { 7 | iteratee = cb(iteratee, context); 8 | var _keys = keys(obj), 9 | length = _keys.length, 10 | results = {}; 11 | for (var index = 0; index < length; index++) { 12 | var currentKey = _keys[index]; 13 | results[currentKey] = iteratee(obj[currentKey], currentKey, obj); 14 | } 15 | return results; 16 | } 17 | -------------------------------------------------------------------------------- /modules/matcher.js: -------------------------------------------------------------------------------- 1 | import extendOwn from './extendOwn.js'; 2 | import isMatch from './isMatch.js'; 3 | 4 | // Returns a predicate for checking whether an object has a given set of 5 | // `key:value` pairs. 6 | export default function matcher(attrs) { 7 | attrs = extendOwn({}, attrs); 8 | return function(obj) { 9 | return isMatch(obj, attrs); 10 | }; 11 | } 12 | -------------------------------------------------------------------------------- /modules/max.js: -------------------------------------------------------------------------------- 1 | import isArrayLike from './_isArrayLike.js'; 2 | import values from './values.js'; 3 | import cb from './_cb.js'; 4 | import each from './each.js'; 5 | 6 | // Return the maximum element (or element-based computation). 7 | export default function max(obj, iteratee, context) { 8 | var result = -Infinity, lastComputed = -Infinity, 9 | value, computed; 10 | if (iteratee == null || (typeof iteratee == 'number' && typeof obj[0] != 'object' && obj != null)) { 11 | obj = isArrayLike(obj) ? obj : values(obj); 12 | for (var i = 0, length = obj.length; i < length; i++) { 13 | value = obj[i]; 14 | if (value != null && value > result) { 15 | result = value; 16 | } 17 | } 18 | } else { 19 | iteratee = cb(iteratee, context); 20 | each(obj, function(v, index, list) { 21 | computed = iteratee(v, index, list); 22 | if (computed > lastComputed || (computed === -Infinity && result === -Infinity)) { 23 | result = v; 24 | lastComputed = computed; 25 | } 26 | }); 27 | } 28 | return result; 29 | } 30 | -------------------------------------------------------------------------------- /modules/memoize.js: -------------------------------------------------------------------------------- 1 | import has from './_has.js'; 2 | 3 | // Memoize an expensive function by storing its results. 4 | export default function memoize(func, hasher) { 5 | var memoize = function(key) { 6 | var cache = memoize.cache; 7 | var address = '' + (hasher ? hasher.apply(this, arguments) : key); 8 | if (!has(cache, address)) cache[address] = func.apply(this, arguments); 9 | return cache[address]; 10 | }; 11 | memoize.cache = {}; 12 | return memoize; 13 | } 14 | -------------------------------------------------------------------------------- /modules/min.js: -------------------------------------------------------------------------------- 1 | import isArrayLike from './_isArrayLike.js'; 2 | import values from './values.js'; 3 | import cb from './_cb.js'; 4 | import each from './each.js'; 5 | 6 | // Return the minimum element (or element-based computation). 7 | export default function min(obj, iteratee, context) { 8 | var result = Infinity, lastComputed = Infinity, 9 | value, computed; 10 | if (iteratee == null || (typeof iteratee == 'number' && typeof obj[0] != 'object' && obj != null)) { 11 | obj = isArrayLike(obj) ? obj : values(obj); 12 | for (var i = 0, length = obj.length; i < length; i++) { 13 | value = obj[i]; 14 | if (value != null && value < result) { 15 | result = value; 16 | } 17 | } 18 | } else { 19 | iteratee = cb(iteratee, context); 20 | each(obj, function(v, index, list) { 21 | computed = iteratee(v, index, list); 22 | if (computed < lastComputed || (computed === Infinity && result === Infinity)) { 23 | result = v; 24 | lastComputed = computed; 25 | } 26 | }); 27 | } 28 | return result; 29 | } 30 | -------------------------------------------------------------------------------- /modules/mixin.js: -------------------------------------------------------------------------------- 1 | import _ from './underscore.js'; 2 | import each from './each.js'; 3 | import functions from './functions.js'; 4 | import { push } from './_setup.js'; 5 | import chainResult from './_chainResult.js'; 6 | 7 | // Add your own custom functions to the Underscore object. 8 | export default function mixin(obj) { 9 | each(functions(obj), function(name) { 10 | var func = _[name] = obj[name]; 11 | _.prototype[name] = function() { 12 | var args = [this._wrapped]; 13 | push.apply(args, arguments); 14 | return chainResult(this, func.apply(_, args)); 15 | }; 16 | }); 17 | return _; 18 | } 19 | -------------------------------------------------------------------------------- /modules/negate.js: -------------------------------------------------------------------------------- 1 | // Returns a negated version of the passed-in predicate. 2 | export default function negate(predicate) { 3 | return function() { 4 | return !predicate.apply(this, arguments); 5 | }; 6 | } 7 | -------------------------------------------------------------------------------- /modules/noop.js: -------------------------------------------------------------------------------- 1 | // Predicate-generating function. Often useful outside of Underscore. 2 | export default function noop(){} 3 | -------------------------------------------------------------------------------- /modules/now.js: -------------------------------------------------------------------------------- 1 | // A (possibly faster) way to get the current timestamp as an integer. 2 | export default Date.now || function() { 3 | return new Date().getTime(); 4 | }; 5 | -------------------------------------------------------------------------------- /modules/object.js: -------------------------------------------------------------------------------- 1 | import getLength from './_getLength.js'; 2 | 3 | // Converts lists into objects. Pass either a single array of `[key, value]` 4 | // pairs, or two parallel arrays of the same length -- one of keys, and one of 5 | // the corresponding values. Passing by pairs is the reverse of `_.pairs`. 6 | export default function object(list, values) { 7 | var result = {}; 8 | for (var i = 0, length = getLength(list); i < length; i++) { 9 | if (values) { 10 | result[list[i]] = values[i]; 11 | } else { 12 | result[list[i][0]] = list[i][1]; 13 | } 14 | } 15 | return result; 16 | } 17 | -------------------------------------------------------------------------------- /modules/omit.js: -------------------------------------------------------------------------------- 1 | import restArguments from './restArguments.js'; 2 | import isFunction from './isFunction.js'; 3 | import negate from './negate.js'; 4 | import map from './map.js'; 5 | import flatten from './_flatten.js'; 6 | import contains from './contains.js'; 7 | import pick from './pick.js'; 8 | 9 | // Return a copy of the object without the disallowed properties. 10 | export default restArguments(function(obj, keys) { 11 | var iteratee = keys[0], context; 12 | if (isFunction(iteratee)) { 13 | iteratee = negate(iteratee); 14 | if (keys.length > 1) context = keys[1]; 15 | } else { 16 | keys = map(flatten(keys, false, false), String); 17 | iteratee = function(value, key) { 18 | return !contains(keys, key); 19 | }; 20 | } 21 | return pick(obj, iteratee, context); 22 | }); 23 | -------------------------------------------------------------------------------- /modules/once.js: -------------------------------------------------------------------------------- 1 | import partial from './partial.js'; 2 | import before from './before.js'; 3 | 4 | // Returns a function that will be executed at most one time, no matter how 5 | // often you call it. Useful for lazy initialization. 6 | export default partial(before, 2); 7 | -------------------------------------------------------------------------------- /modules/package.json: -------------------------------------------------------------------------------- 1 | {"type":"module","version":"1.13.7"} 2 | -------------------------------------------------------------------------------- /modules/pairs.js: -------------------------------------------------------------------------------- 1 | import keys from './keys.js'; 2 | 3 | // Convert an object into a list of `[key, value]` pairs. 4 | // The opposite of `_.object` with one argument. 5 | export default function pairs(obj) { 6 | var _keys = keys(obj); 7 | var length = _keys.length; 8 | var pairs = Array(length); 9 | for (var i = 0; i < length; i++) { 10 | pairs[i] = [_keys[i], obj[_keys[i]]]; 11 | } 12 | return pairs; 13 | } 14 | -------------------------------------------------------------------------------- /modules/partial.js: -------------------------------------------------------------------------------- 1 | import restArguments from './restArguments.js'; 2 | import executeBound from './_executeBound.js'; 3 | import _ from './underscore.js'; 4 | 5 | // Partially apply a function by creating a version that has had some of its 6 | // arguments pre-filled, without changing its dynamic `this` context. `_` acts 7 | // as a placeholder by default, allowing any combination of arguments to be 8 | // pre-filled. Set `_.partial.placeholder` for a custom placeholder argument. 9 | var partial = restArguments(function(func, boundArgs) { 10 | var placeholder = partial.placeholder; 11 | var bound = function() { 12 | var position = 0, length = boundArgs.length; 13 | var args = Array(length); 14 | for (var i = 0; i < length; i++) { 15 | args[i] = boundArgs[i] === placeholder ? arguments[position++] : boundArgs[i]; 16 | } 17 | while (position < arguments.length) args.push(arguments[position++]); 18 | return executeBound(func, bound, this, this, args); 19 | }; 20 | return bound; 21 | }); 22 | 23 | partial.placeholder = _; 24 | export default partial; 25 | -------------------------------------------------------------------------------- /modules/partition.js: -------------------------------------------------------------------------------- 1 | import group from './_group.js'; 2 | 3 | // Split a collection into two arrays: one whose elements all pass the given 4 | // truth test, and one whose elements all do not pass the truth test. 5 | export default group(function(result, value, pass) { 6 | result[pass ? 0 : 1].push(value); 7 | }, true); 8 | -------------------------------------------------------------------------------- /modules/pick.js: -------------------------------------------------------------------------------- 1 | import restArguments from './restArguments.js'; 2 | import isFunction from './isFunction.js'; 3 | import optimizeCb from './_optimizeCb.js'; 4 | import allKeys from './allKeys.js'; 5 | import keyInObj from './_keyInObj.js'; 6 | import flatten from './_flatten.js'; 7 | 8 | // Return a copy of the object only containing the allowed properties. 9 | export default restArguments(function(obj, keys) { 10 | var result = {}, iteratee = keys[0]; 11 | if (obj == null) return result; 12 | if (isFunction(iteratee)) { 13 | if (keys.length > 1) iteratee = optimizeCb(iteratee, keys[1]); 14 | keys = allKeys(obj); 15 | } else { 16 | iteratee = keyInObj; 17 | keys = flatten(keys, false, false); 18 | obj = Object(obj); 19 | } 20 | for (var i = 0, length = keys.length; i < length; i++) { 21 | var key = keys[i]; 22 | var value = obj[key]; 23 | if (iteratee(value, key, obj)) result[key] = value; 24 | } 25 | return result; 26 | }); 27 | -------------------------------------------------------------------------------- /modules/pluck.js: -------------------------------------------------------------------------------- 1 | import map from './map.js'; 2 | import property from './property.js'; 3 | 4 | // Convenience version of a common use case of `_.map`: fetching a property. 5 | export default function pluck(obj, key) { 6 | return map(obj, property(key)); 7 | } 8 | -------------------------------------------------------------------------------- /modules/property.js: -------------------------------------------------------------------------------- 1 | import deepGet from './_deepGet.js'; 2 | import toPath from './_toPath.js'; 3 | 4 | // Creates a function that, when passed an object, will traverse that object’s 5 | // properties down the given `path`, specified as an array of keys or indices. 6 | export default function property(path) { 7 | path = toPath(path); 8 | return function(obj) { 9 | return deepGet(obj, path); 10 | }; 11 | } 12 | -------------------------------------------------------------------------------- /modules/propertyOf.js: -------------------------------------------------------------------------------- 1 | import noop from './noop.js'; 2 | import get from './get.js'; 3 | 4 | // Generates a function for a given object that returns a given property. 5 | export default function propertyOf(obj) { 6 | if (obj == null) return noop; 7 | return function(path) { 8 | return get(obj, path); 9 | }; 10 | } 11 | -------------------------------------------------------------------------------- /modules/random.js: -------------------------------------------------------------------------------- 1 | // Return a random integer between `min` and `max` (inclusive). 2 | export default function random(min, max) { 3 | if (max == null) { 4 | max = min; 5 | min = 0; 6 | } 7 | return min + Math.floor(Math.random() * (max - min + 1)); 8 | } 9 | -------------------------------------------------------------------------------- /modules/range.js: -------------------------------------------------------------------------------- 1 | // Generate an integer Array containing an arithmetic progression. A port of 2 | // the native Python `range()` function. See 3 | // [the Python documentation](https://docs.python.org/library/functions.html#range). 4 | export default function range(start, stop, step) { 5 | if (stop == null) { 6 | stop = start || 0; 7 | start = 0; 8 | } 9 | if (!step) { 10 | step = stop < start ? -1 : 1; 11 | } 12 | 13 | var length = Math.max(Math.ceil((stop - start) / step), 0); 14 | var range = Array(length); 15 | 16 | for (var idx = 0; idx < length; idx++, start += step) { 17 | range[idx] = start; 18 | } 19 | 20 | return range; 21 | } 22 | -------------------------------------------------------------------------------- /modules/reduce.js: -------------------------------------------------------------------------------- 1 | import createReduce from './_createReduce.js'; 2 | 3 | // **Reduce** builds up a single result from a list of values, aka `inject`, 4 | // or `foldl`. 5 | export default createReduce(1); 6 | -------------------------------------------------------------------------------- /modules/reduceRight.js: -------------------------------------------------------------------------------- 1 | import createReduce from './_createReduce.js'; 2 | 3 | // The right-associative version of reduce, also known as `foldr`. 4 | export default createReduce(-1); 5 | -------------------------------------------------------------------------------- /modules/reject.js: -------------------------------------------------------------------------------- 1 | import filter from './filter.js'; 2 | import negate from './negate.js'; 3 | import cb from './_cb.js'; 4 | 5 | // Return all the elements for which a truth test fails. 6 | export default function reject(obj, predicate, context) { 7 | return filter(obj, negate(cb(predicate)), context); 8 | } 9 | -------------------------------------------------------------------------------- /modules/rest.js: -------------------------------------------------------------------------------- 1 | import { slice } from './_setup.js'; 2 | 3 | // Returns everything but the first entry of the `array`. Especially useful on 4 | // the `arguments` object. Passing an **n** will return the rest N values in the 5 | // `array`. 6 | export default function rest(array, n, guard) { 7 | return slice.call(array, n == null || guard ? 1 : n); 8 | } 9 | -------------------------------------------------------------------------------- /modules/restArguments.js: -------------------------------------------------------------------------------- 1 | // Some functions take a variable number of arguments, or a few expected 2 | // arguments at the beginning and then a variable number of values to operate 3 | // on. This helper accumulates all remaining arguments past the function’s 4 | // argument length (or an explicit `startIndex`), into an array that becomes 5 | // the last argument. Similar to ES6’s "rest parameter". 6 | export default function restArguments(func, startIndex) { 7 | startIndex = startIndex == null ? func.length - 1 : +startIndex; 8 | return function() { 9 | var length = Math.max(arguments.length - startIndex, 0), 10 | rest = Array(length), 11 | index = 0; 12 | for (; index < length; index++) { 13 | rest[index] = arguments[index + startIndex]; 14 | } 15 | switch (startIndex) { 16 | case 0: return func.call(this, rest); 17 | case 1: return func.call(this, arguments[0], rest); 18 | case 2: return func.call(this, arguments[0], arguments[1], rest); 19 | } 20 | var args = Array(startIndex + 1); 21 | for (index = 0; index < startIndex; index++) { 22 | args[index] = arguments[index]; 23 | } 24 | args[startIndex] = rest; 25 | return func.apply(this, args); 26 | }; 27 | } 28 | -------------------------------------------------------------------------------- /modules/result.js: -------------------------------------------------------------------------------- 1 | import isFunction from './isFunction.js'; 2 | import toPath from './_toPath.js'; 3 | 4 | // Traverses the children of `obj` along `path`. If a child is a function, it 5 | // is invoked with its parent as context. Returns the value of the final 6 | // child, or `fallback` if any child is undefined. 7 | export default function result(obj, path, fallback) { 8 | path = toPath(path); 9 | var length = path.length; 10 | if (!length) { 11 | return isFunction(fallback) ? fallback.call(obj) : fallback; 12 | } 13 | for (var i = 0; i < length; i++) { 14 | var prop = obj == null ? void 0 : obj[path[i]]; 15 | if (prop === void 0) { 16 | prop = fallback; 17 | i = length; // Ensure we don't continue iterating. 18 | } 19 | obj = isFunction(prop) ? prop.call(obj) : prop; 20 | } 21 | return obj; 22 | } 23 | -------------------------------------------------------------------------------- /modules/sample.js: -------------------------------------------------------------------------------- 1 | import isArrayLike from './_isArrayLike.js'; 2 | import values from './values.js'; 3 | import getLength from './_getLength.js'; 4 | import random from './random.js'; 5 | import toArray from './toArray.js'; 6 | 7 | // Sample **n** random values from a collection using the modern version of the 8 | // [Fisher-Yates shuffle](https://en.wikipedia.org/wiki/Fisher–Yates_shuffle). 9 | // If **n** is not specified, returns a single random element. 10 | // The internal `guard` argument allows it to work with `_.map`. 11 | export default function sample(obj, n, guard) { 12 | if (n == null || guard) { 13 | if (!isArrayLike(obj)) obj = values(obj); 14 | return obj[random(obj.length - 1)]; 15 | } 16 | var sample = toArray(obj); 17 | var length = getLength(sample); 18 | n = Math.max(Math.min(n, length), 0); 19 | var last = length - 1; 20 | for (var index = 0; index < n; index++) { 21 | var rand = random(index, last); 22 | var temp = sample[index]; 23 | sample[index] = sample[rand]; 24 | sample[rand] = temp; 25 | } 26 | return sample.slice(0, n); 27 | } 28 | -------------------------------------------------------------------------------- /modules/shuffle.js: -------------------------------------------------------------------------------- 1 | import sample from './sample.js'; 2 | 3 | // Shuffle a collection. 4 | export default function shuffle(obj) { 5 | return sample(obj, Infinity); 6 | } 7 | -------------------------------------------------------------------------------- /modules/size.js: -------------------------------------------------------------------------------- 1 | import isArrayLike from './_isArrayLike.js'; 2 | import keys from './keys.js'; 3 | 4 | // Return the number of elements in a collection. 5 | export default function size(obj) { 6 | if (obj == null) return 0; 7 | return isArrayLike(obj) ? obj.length : keys(obj).length; 8 | } 9 | -------------------------------------------------------------------------------- /modules/some.js: -------------------------------------------------------------------------------- 1 | import cb from './_cb.js'; 2 | import isArrayLike from './_isArrayLike.js'; 3 | import keys from './keys.js'; 4 | 5 | // Determine if at least one element in the object passes a truth test. 6 | export default function some(obj, predicate, context) { 7 | predicate = cb(predicate, context); 8 | var _keys = !isArrayLike(obj) && keys(obj), 9 | length = (_keys || obj).length; 10 | for (var index = 0; index < length; index++) { 11 | var currentKey = _keys ? _keys[index] : index; 12 | if (predicate(obj[currentKey], currentKey, obj)) return true; 13 | } 14 | return false; 15 | } 16 | -------------------------------------------------------------------------------- /modules/sortBy.js: -------------------------------------------------------------------------------- 1 | import cb from './_cb.js'; 2 | import pluck from './pluck.js'; 3 | import map from './map.js'; 4 | 5 | // Sort the object's values by a criterion produced by an iteratee. 6 | export default function sortBy(obj, iteratee, context) { 7 | var index = 0; 8 | iteratee = cb(iteratee, context); 9 | return pluck(map(obj, function(value, key, list) { 10 | return { 11 | value: value, 12 | index: index++, 13 | criteria: iteratee(value, key, list) 14 | }; 15 | }).sort(function(left, right) { 16 | var a = left.criteria; 17 | var b = right.criteria; 18 | if (a !== b) { 19 | if (a > b || a === void 0) return 1; 20 | if (a < b || b === void 0) return -1; 21 | } 22 | return left.index - right.index; 23 | }), 'value'); 24 | } 25 | -------------------------------------------------------------------------------- /modules/sortedIndex.js: -------------------------------------------------------------------------------- 1 | import cb from './_cb.js'; 2 | import getLength from './_getLength.js'; 3 | 4 | // Use a comparator function to figure out the smallest index at which 5 | // an object should be inserted so as to maintain order. Uses binary search. 6 | export default function sortedIndex(array, obj, iteratee, context) { 7 | iteratee = cb(iteratee, context, 1); 8 | var value = iteratee(obj); 9 | var low = 0, high = getLength(array); 10 | while (low < high) { 11 | var mid = Math.floor((low + high) / 2); 12 | if (iteratee(array[mid]) < value) low = mid + 1; else high = mid; 13 | } 14 | return low; 15 | } 16 | -------------------------------------------------------------------------------- /modules/tap.js: -------------------------------------------------------------------------------- 1 | // Invokes `interceptor` with the `obj` and then returns `obj`. 2 | // The primary purpose of this method is to "tap into" a method chain, in 3 | // order to perform operations on intermediate results within the chain. 4 | export default function tap(obj, interceptor) { 5 | interceptor(obj); 6 | return obj; 7 | } 8 | -------------------------------------------------------------------------------- /modules/template.js: -------------------------------------------------------------------------------- 1 | import defaults from './defaults.js'; 2 | import _ from './underscore.js'; 3 | import './templateSettings.js'; 4 | 5 | // When customizing `_.templateSettings`, if you don't want to define an 6 | // interpolation, evaluation or escaping regex, we need one that is 7 | // guaranteed not to match. 8 | var noMatch = /(.)^/; 9 | 10 | // Certain characters need to be escaped so that they can be put into a 11 | // string literal. 12 | var escapes = { 13 | "'": "'", 14 | '\\': '\\', 15 | '\r': 'r', 16 | '\n': 'n', 17 | '\u2028': 'u2028', 18 | '\u2029': 'u2029' 19 | }; 20 | 21 | var escapeRegExp = /\\|'|\r|\n|\u2028|\u2029/g; 22 | 23 | function escapeChar(match) { 24 | return '\\' + escapes[match]; 25 | } 26 | 27 | // In order to prevent third-party code injection through 28 | // `_.templateSettings.variable`, we test it against the following regular 29 | // expression. It is intentionally a bit more liberal than just matching valid 30 | // identifiers, but still prevents possible loopholes through defaults or 31 | // destructuring assignment. 32 | var bareIdentifier = /^\s*(\w|\$)+\s*$/; 33 | 34 | // JavaScript micro-templating, similar to John Resig's implementation. 35 | // Underscore templating handles arbitrary delimiters, preserves whitespace, 36 | // and correctly escapes quotes within interpolated code. 37 | // NB: `oldSettings` only exists for backwards compatibility. 38 | export default function template(text, settings, oldSettings) { 39 | if (!settings && oldSettings) settings = oldSettings; 40 | settings = defaults({}, settings, _.templateSettings); 41 | 42 | // Combine delimiters into one regular expression via alternation. 43 | var matcher = RegExp([ 44 | (settings.escape || noMatch).source, 45 | (settings.interpolate || noMatch).source, 46 | (settings.evaluate || noMatch).source 47 | ].join('|') + '|$', 'g'); 48 | 49 | // Compile the template source, escaping string literals appropriately. 50 | var index = 0; 51 | var source = "__p+='"; 52 | text.replace(matcher, function(match, escape, interpolate, evaluate, offset) { 53 | source += text.slice(index, offset).replace(escapeRegExp, escapeChar); 54 | index = offset + match.length; 55 | 56 | if (escape) { 57 | source += "'+\n((__t=(" + escape + "))==null?'':_.escape(__t))+\n'"; 58 | } else if (interpolate) { 59 | source += "'+\n((__t=(" + interpolate + "))==null?'':__t)+\n'"; 60 | } else if (evaluate) { 61 | source += "';\n" + evaluate + "\n__p+='"; 62 | } 63 | 64 | // Adobe VMs need the match returned to produce the correct offset. 65 | return match; 66 | }); 67 | source += "';\n"; 68 | 69 | var argument = settings.variable; 70 | if (argument) { 71 | // Insure against third-party code injection. (CVE-2021-23358) 72 | if (!bareIdentifier.test(argument)) throw new Error( 73 | 'variable is not a bare identifier: ' + argument 74 | ); 75 | } else { 76 | // If a variable is not specified, place data values in local scope. 77 | source = 'with(obj||{}){\n' + source + '}\n'; 78 | argument = 'obj'; 79 | } 80 | 81 | source = "var __t,__p='',__j=Array.prototype.join," + 82 | "print=function(){__p+=__j.call(arguments,'');};\n" + 83 | source + 'return __p;\n'; 84 | 85 | var render; 86 | try { 87 | render = new Function(argument, '_', source); 88 | } catch (e) { 89 | e.source = source; 90 | throw e; 91 | } 92 | 93 | var template = function(data) { 94 | return render.call(this, data, _); 95 | }; 96 | 97 | // Provide the compiled source as a convenience for precompilation. 98 | template.source = 'function(' + argument + '){\n' + source + '}'; 99 | 100 | return template; 101 | } 102 | -------------------------------------------------------------------------------- /modules/templateSettings.js: -------------------------------------------------------------------------------- 1 | import _ from './underscore.js'; 2 | 3 | // By default, Underscore uses ERB-style template delimiters. Change the 4 | // following template settings to use alternative delimiters. 5 | export default _.templateSettings = { 6 | evaluate: /<%([\s\S]+?)%>/g, 7 | interpolate: /<%=([\s\S]+?)%>/g, 8 | escape: /<%-([\s\S]+?)%>/g 9 | }; 10 | -------------------------------------------------------------------------------- /modules/throttle.js: -------------------------------------------------------------------------------- 1 | import now from './now.js'; 2 | 3 | // Returns a function, that, when invoked, will only be triggered at most once 4 | // during a given window of time. Normally, the throttled function will run 5 | // as much as it can, without ever going more than once per `wait` duration; 6 | // but if you'd like to disable the execution on the leading edge, pass 7 | // `{leading: false}`. To disable execution on the trailing edge, ditto. 8 | export default function throttle(func, wait, options) { 9 | var timeout, context, args, result; 10 | var previous = 0; 11 | if (!options) options = {}; 12 | 13 | var later = function() { 14 | previous = options.leading === false ? 0 : now(); 15 | timeout = null; 16 | result = func.apply(context, args); 17 | if (!timeout) context = args = null; 18 | }; 19 | 20 | var throttled = function() { 21 | var _now = now(); 22 | if (!previous && options.leading === false) previous = _now; 23 | var remaining = wait - (_now - previous); 24 | context = this; 25 | args = arguments; 26 | if (remaining <= 0 || remaining > wait) { 27 | if (timeout) { 28 | clearTimeout(timeout); 29 | timeout = null; 30 | } 31 | previous = _now; 32 | result = func.apply(context, args); 33 | if (!timeout) context = args = null; 34 | } else if (!timeout && options.trailing !== false) { 35 | timeout = setTimeout(later, remaining); 36 | } 37 | return result; 38 | }; 39 | 40 | throttled.cancel = function() { 41 | clearTimeout(timeout); 42 | previous = 0; 43 | timeout = context = args = null; 44 | }; 45 | 46 | return throttled; 47 | } 48 | -------------------------------------------------------------------------------- /modules/times.js: -------------------------------------------------------------------------------- 1 | import optimizeCb from './_optimizeCb.js'; 2 | 3 | // Run a function **n** times. 4 | export default function times(n, iteratee, context) { 5 | var accum = Array(Math.max(0, n)); 6 | iteratee = optimizeCb(iteratee, context, 1); 7 | for (var i = 0; i < n; i++) accum[i] = iteratee(i); 8 | return accum; 9 | } 10 | -------------------------------------------------------------------------------- /modules/toArray.js: -------------------------------------------------------------------------------- 1 | import isArray from './isArray.js'; 2 | import { slice } from './_setup.js'; 3 | import isString from './isString.js'; 4 | import isArrayLike from './_isArrayLike.js'; 5 | import map from './map.js'; 6 | import identity from './identity.js'; 7 | import values from './values.js'; 8 | 9 | // Safely create a real, live array from anything iterable. 10 | var reStrSymbol = /[^\ud800-\udfff]|[\ud800-\udbff][\udc00-\udfff]|[\ud800-\udfff]/g; 11 | export default function toArray(obj) { 12 | if (!obj) return []; 13 | if (isArray(obj)) return slice.call(obj); 14 | if (isString(obj)) { 15 | // Keep surrogate pair characters together. 16 | return obj.match(reStrSymbol); 17 | } 18 | if (isArrayLike(obj)) return map(obj, identity); 19 | return values(obj); 20 | } 21 | -------------------------------------------------------------------------------- /modules/toPath.js: -------------------------------------------------------------------------------- 1 | import _ from './underscore.js'; 2 | import isArray from './isArray.js'; 3 | 4 | // Normalize a (deep) property `path` to array. 5 | // Like `_.iteratee`, this function can be customized. 6 | export default function toPath(path) { 7 | return isArray(path) ? path : [path]; 8 | } 9 | _.toPath = toPath; 10 | -------------------------------------------------------------------------------- /modules/underscore-array-methods.js: -------------------------------------------------------------------------------- 1 | import _ from './underscore.js'; 2 | import each from './each.js'; 3 | import { ArrayProto } from './_setup.js'; 4 | import chainResult from './_chainResult.js'; 5 | 6 | // Add all mutator `Array` functions to the wrapper. 7 | each(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function(name) { 8 | var method = ArrayProto[name]; 9 | _.prototype[name] = function() { 10 | var obj = this._wrapped; 11 | if (obj != null) { 12 | method.apply(obj, arguments); 13 | if ((name === 'shift' || name === 'splice') && obj.length === 0) { 14 | delete obj[0]; 15 | } 16 | } 17 | return chainResult(this, obj); 18 | }; 19 | }); 20 | 21 | // Add all accessor `Array` functions to the wrapper. 22 | each(['concat', 'join', 'slice'], function(name) { 23 | var method = ArrayProto[name]; 24 | _.prototype[name] = function() { 25 | var obj = this._wrapped; 26 | if (obj != null) obj = method.apply(obj, arguments); 27 | return chainResult(this, obj); 28 | }; 29 | }); 30 | 31 | export default _; 32 | -------------------------------------------------------------------------------- /modules/underscore.js: -------------------------------------------------------------------------------- 1 | import { VERSION } from './_setup.js'; 2 | 3 | // If Underscore is called as a function, it returns a wrapped object that can 4 | // be used OO-style. This wrapper holds altered versions of all functions added 5 | // through `_.mixin`. Wrapped objects may be chained. 6 | export default function _(obj) { 7 | if (obj instanceof _) return obj; 8 | if (!(this instanceof _)) return new _(obj); 9 | this._wrapped = obj; 10 | } 11 | 12 | _.VERSION = VERSION; 13 | 14 | // Extracts the result from a wrapped and chained object. 15 | _.prototype.value = function() { 16 | return this._wrapped; 17 | }; 18 | 19 | // Provide unwrapping proxies for some methods used in engine operations 20 | // such as arithmetic and JSON stringification. 21 | _.prototype.valueOf = _.prototype.toJSON = _.prototype.value; 22 | 23 | _.prototype.toString = function() { 24 | return String(this._wrapped); 25 | }; 26 | -------------------------------------------------------------------------------- /modules/unescape.js: -------------------------------------------------------------------------------- 1 | import createEscaper from './_createEscaper.js'; 2 | import unescapeMap from './_unescapeMap.js'; 3 | 4 | // Function for unescaping strings from HTML interpolation. 5 | export default createEscaper(unescapeMap); 6 | -------------------------------------------------------------------------------- /modules/union.js: -------------------------------------------------------------------------------- 1 | import restArguments from './restArguments.js'; 2 | import uniq from './uniq.js'; 3 | import flatten from './_flatten.js'; 4 | 5 | // Produce an array that contains the union: each distinct element from all of 6 | // the passed-in arrays. 7 | export default restArguments(function(arrays) { 8 | return uniq(flatten(arrays, true, true)); 9 | }); 10 | -------------------------------------------------------------------------------- /modules/uniq.js: -------------------------------------------------------------------------------- 1 | import isBoolean from './isBoolean.js'; 2 | import cb from './_cb.js'; 3 | import getLength from './_getLength.js'; 4 | import contains from './contains.js'; 5 | 6 | // Produce a duplicate-free version of the array. If the array has already 7 | // been sorted, you have the option of using a faster algorithm. 8 | // The faster algorithm will not work with an iteratee if the iteratee 9 | // is not a one-to-one function, so providing an iteratee will disable 10 | // the faster algorithm. 11 | export default function uniq(array, isSorted, iteratee, context) { 12 | if (!isBoolean(isSorted)) { 13 | context = iteratee; 14 | iteratee = isSorted; 15 | isSorted = false; 16 | } 17 | if (iteratee != null) iteratee = cb(iteratee, context); 18 | var result = []; 19 | var seen = []; 20 | for (var i = 0, length = getLength(array); i < length; i++) { 21 | var value = array[i], 22 | computed = iteratee ? iteratee(value, i, array) : value; 23 | if (isSorted && !iteratee) { 24 | if (!i || seen !== computed) result.push(value); 25 | seen = computed; 26 | } else if (iteratee) { 27 | if (!contains(seen, computed)) { 28 | seen.push(computed); 29 | result.push(value); 30 | } 31 | } else if (!contains(result, value)) { 32 | result.push(value); 33 | } 34 | } 35 | return result; 36 | } 37 | -------------------------------------------------------------------------------- /modules/uniqueId.js: -------------------------------------------------------------------------------- 1 | // Generate a unique integer id (unique within the entire client session). 2 | // Useful for temporary DOM ids. 3 | var idCounter = 0; 4 | export default function uniqueId(prefix) { 5 | var id = ++idCounter + ''; 6 | return prefix ? prefix + id : id; 7 | } 8 | -------------------------------------------------------------------------------- /modules/unzip.js: -------------------------------------------------------------------------------- 1 | import max from './max.js'; 2 | import getLength from './_getLength.js'; 3 | import pluck from './pluck.js'; 4 | 5 | // Complement of zip. Unzip accepts an array of arrays and groups 6 | // each array's elements on shared indices. 7 | export default function unzip(array) { 8 | var length = (array && max(array, getLength).length) || 0; 9 | var result = Array(length); 10 | 11 | for (var index = 0; index < length; index++) { 12 | result[index] = pluck(array, index); 13 | } 14 | return result; 15 | } 16 | -------------------------------------------------------------------------------- /modules/values.js: -------------------------------------------------------------------------------- 1 | import keys from './keys.js'; 2 | 3 | // Retrieve the values of an object's properties. 4 | export default function values(obj) { 5 | var _keys = keys(obj); 6 | var length = _keys.length; 7 | var values = Array(length); 8 | for (var i = 0; i < length; i++) { 9 | values[i] = obj[_keys[i]]; 10 | } 11 | return values; 12 | } 13 | -------------------------------------------------------------------------------- /modules/where.js: -------------------------------------------------------------------------------- 1 | import filter from './filter.js'; 2 | import matcher from './matcher.js'; 3 | 4 | // Convenience version of a common use case of `_.filter`: selecting only 5 | // objects containing specific `key:value` pairs. 6 | export default function where(obj, attrs) { 7 | return filter(obj, matcher(attrs)); 8 | } 9 | -------------------------------------------------------------------------------- /modules/without.js: -------------------------------------------------------------------------------- 1 | import restArguments from './restArguments.js'; 2 | import difference from './difference.js'; 3 | 4 | // Return a version of the array that does not contain the specified value(s). 5 | export default restArguments(function(array, otherArrays) { 6 | return difference(array, otherArrays); 7 | }); 8 | -------------------------------------------------------------------------------- /modules/wrap.js: -------------------------------------------------------------------------------- 1 | import partial from './partial.js'; 2 | 3 | // Returns the first function passed as an argument to the second, 4 | // allowing you to adjust arguments, run code before and after, and 5 | // conditionally execute the original function. 6 | export default function wrap(func, wrapper) { 7 | return partial(wrapper, func); 8 | } 9 | -------------------------------------------------------------------------------- /modules/zip.js: -------------------------------------------------------------------------------- 1 | import restArguments from './restArguments.js'; 2 | import unzip from './unzip.js'; 3 | 4 | // Zip together multiple lists into a single array -- elements that share 5 | // an index go together. 6 | export default restArguments(unzip); 7 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "underscore", 3 | "description": "JavaScript's functional programming helper library.", 4 | "version": "1.13.7", 5 | "author": "Jeremy Ashkenas ", 6 | "license": "MIT", 7 | "homepage": "https://underscorejs.org", 8 | "repository": { 9 | "type": "git", 10 | "url": "git://github.com/jashkenas/underscore.git" 11 | }, 12 | "keywords": [ 13 | "util", 14 | "functional", 15 | "server", 16 | "client", 17 | "browser" 18 | ], 19 | "main": "underscore-umd.js", 20 | "module": "modules/index-all.js", 21 | "type": "commonjs", 22 | "exports": { 23 | ".": { 24 | "import": { 25 | "module": "./modules/index-all.js", 26 | "browser": { 27 | "production": "./underscore-esm-min.js", 28 | "default": "./underscore-esm.js" 29 | }, 30 | "node": "./underscore-node.mjs", 31 | "default": "./underscore-esm.js" 32 | }, 33 | "require": { 34 | "module": "./modules/index-all.js", 35 | "browser": { 36 | "production": "./underscore-umd-min.js", 37 | "default": "./underscore-umd.js" 38 | }, 39 | "node": "./underscore-node.cjs", 40 | "default": "./underscore-umd.js" 41 | }, 42 | "default": "./underscore-umd.js" 43 | }, 44 | "./underscore*": "./underscore*", 45 | "./modules/*": { 46 | "require": "./cjs/*", 47 | "default": "./modules/*" 48 | }, 49 | "./amd/*": "./amd/*", 50 | "./cjs/*": "./cjs/*", 51 | "./package.json": "./package.json" 52 | }, 53 | "devDependencies": { 54 | "coveralls": "^3.1.1", 55 | "cpy-cli": "^3.1.1", 56 | "docco": "^0.8.0", 57 | "eslint": "^6.8.0", 58 | "eslint-plugin-import": "^2.20.1", 59 | "glob": "^7.1.6", 60 | "gzip-size-cli": "^1.0.0", 61 | "husky": "^4.2.3", 62 | "karma": "^4.4.1", 63 | "karma-qunit": "^4.1.2", 64 | "karma-sauce-launcher": "^4.3.6", 65 | "nyc": "^15.1.0", 66 | "patch-package": "^6.4.7", 67 | "pretty-bytes-cli": "^1.0.0", 68 | "qunit": "2.10.1", 69 | "rollup": "^2.40.0", 70 | "terser": "^4.6.13" 71 | }, 72 | "overrides": { 73 | "colors@>1.4.0": "1.4.0" 74 | }, 75 | "scripts": { 76 | "test": "npm run lint && npm run prepare-tests && npm run test-node", 77 | "coverage": "npm run prepare-tests && nyc npm run test-node && nyc report", 78 | "coveralls": "nyc npm run test-node && nyc report --reporter=text-lcov | coveralls", 79 | "lint": "eslint modules/*.js test/*.js", 80 | "test-node": "qunit test/", 81 | "test-browser": "npm i karma-phantomjs-launcher && karma start", 82 | "bundle": "rollup -c && eslint underscore-umd.js && rollup -c rollup.config2.js", 83 | "bundle-treeshake": "cd test-treeshake && rollup --config", 84 | "prepare-tests": "npm run bundle && npm run bundle-treeshake", 85 | "minify-umd": "terser underscore-umd.js -c \"evaluate=false\" --comments \"/ .*/\" -m", 86 | "minify-esm": "terser underscore-esm.js -c \"evaluate=false\" --comments \"/ .*/\" -m", 87 | "module-package-json": "node -e 'console.log(`{\"type\":\"module\",\"version\":\"${process.env.npm_package_version}\"}`)' > modules/package.json", 88 | "build-umd": "npm run minify-umd -- --source-map content=underscore-umd.js.map --source-map-url \" \" -o underscore-umd-min.js", 89 | "build-esm": "npm run module-package-json && npm run minify-esm -- --source-map content=underscore-esm.js.map --source-map-url \" \" -o underscore-esm-min.js", 90 | "alias-bundle": "cpy --rename=underscore.js underscore-umd.js . && cpy --rename=underscore-min.js underscore-umd-min.js . && cpy --rename=underscore-min.js.map underscore-umd-min.js.map .", 91 | "build": "npm run bundle && npm run build-umd && npm run build-esm && npm run alias-bundle", 92 | "doc": "patch-package && docco underscore-esm.js && docco modules/*.js -c docco.css -t docs/linked-esm.jst", 93 | "weight": "npm run bundle && npm run minify-umd | gzip-size | pretty-bytes", 94 | "prepublishOnly": "npm run build && npm run doc" 95 | }, 96 | "files": [ 97 | "underscore-esm.js", 98 | "underscore-esm.js.map", 99 | "underscore-esm-min.js", 100 | "underscore-esm-min.js.map", 101 | "underscore-umd.js", 102 | "underscore-umd.js.map", 103 | "underscore-umd-min.js", 104 | "underscore-umd-min.js.map", 105 | "underscore.js", 106 | "underscore-min.js", 107 | "underscore-min.js.map", 108 | "underscore-node-f.cjs", 109 | "underscore-node-f.cjs.map", 110 | "underscore-node.cjs", 111 | "underscore-node.cjs.map", 112 | "underscore-node.mjs", 113 | "underscore-node.mjs.map", 114 | "modules/", 115 | "amd/", 116 | "cjs/" 117 | ], 118 | "husky": { 119 | "hooks": { 120 | "pre-commit": "npm run bundle && git add underscore-umd.js underscore-umd.js.map underscore-esm.js underscore-esm.js.map underscore-node-f.cjs underscore-node-f.cjs.map underscore-node.cjs underscore-node.cjs.map underscore-node.mjs underscore-node.mjs.map", 121 | "post-commit": "git reset underscore-umd.js underscore-umd.js.map underscore-esm.js underscore-esm.js.map underscore-node-f.cjs underscore-node-f.cjs.map underscore-node.cjs underscore-node.cjs.map underscore-node.mjs underscore-node.mjs.map" 122 | } 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /patches/docco+0.8.0.patch: -------------------------------------------------------------------------------- 1 | diff --git a/node_modules/docco/docco.js b/node_modules/docco/docco.js 2 | index 0bb5a8b..f38f9a5 100644 3 | --- a/node_modules/docco/docco.js 4 | +++ b/node_modules/docco/docco.js 5 | @@ -314,7 +314,7 @@ 6 | 7 | path = require('path'); 8 | 9 | - marked = require('marked'); 10 | + marked = require('marked').marked; 11 | 12 | commander = require('commander'); 13 | 14 | -------------------------------------------------------------------------------- /rollup.common.js: -------------------------------------------------------------------------------- 1 | import { readFileSync } from 'fs'; 2 | import { extend } from './underscore-esm.js'; 3 | 4 | var intro = readFileSync('modules/index.js', 'utf-8').split('\n').slice(3, 7).join('\n'); 5 | 6 | var outputBase = { 7 | strict: false, 8 | externalLiveBindings: false, 9 | freeze: false, 10 | }; 11 | 12 | var sourcemapBase = { 13 | sourcemap: true, 14 | sourcemapExcludeSources: true, 15 | }; 16 | 17 | export function outputConf(particular) { 18 | return extend(particular, outputBase); 19 | } 20 | 21 | export function sourcemapConf(particular) { 22 | return extend(particular, outputBase, sourcemapBase); 23 | } 24 | 25 | export function monolithConf(particular) { 26 | return extend(particular, outputBase, sourcemapBase, {intro}); 27 | } 28 | -------------------------------------------------------------------------------- /rollup.config.js: -------------------------------------------------------------------------------- 1 | import glob from 'glob'; 2 | import { filter } from './underscore-esm.js'; 3 | import { outputConf, sourcemapConf, monolithConf } from './rollup.common.js'; 4 | 5 | export default [ 6 | // Monolithic ESM bundle for browsers and deno. 7 | { 8 | input: 'modules/index-all.js', 9 | treeshake: false, 10 | output: monolithConf({ 11 | file: 'underscore-esm.js', 12 | format: 'esm', 13 | }), 14 | }, 15 | // Monolithic UMD bundle for browsers, AMD and old Node.js. 16 | { 17 | input: 'modules/index-default.js', 18 | treeshake: false, 19 | output: monolithConf({ 20 | file: 'underscore-umd.js', 21 | exports: 'default', 22 | format: 'umd', 23 | name: '_', 24 | amd: { 25 | id: 'underscore', 26 | }, 27 | noConflict: true, 28 | }), 29 | }, 30 | // Custom builds for Node.js, first pass. Second pass in rollup.config2.js. 31 | { 32 | input: { 33 | 'underscore-node-cjs-pre': 'modules/index-default.js', 34 | 'underscore-node-mjs-pre': 'modules/index-all.js', 35 | }, 36 | treeshake: false, 37 | output: sourcemapConf({ 38 | chunkFileNames: 'underscore-node-f-pre.js', 39 | dir: '.', 40 | minifyInternalExports: false, 41 | format: 'esm', 42 | }), 43 | }, 44 | // AMD and CJS versions of the individual modules for development 45 | // and custom bundles. 46 | { 47 | input: filter( 48 | glob.sync('modules/**/*.js'), 49 | function(path) { return path !== 'modules/index-all.js'; } 50 | ), 51 | preserveModules: true, 52 | output: [ 53 | outputConf({ 54 | dir: 'amd', 55 | exports: 'auto', 56 | format: 'amd', 57 | }), 58 | outputConf({ 59 | dir: 'cjs', 60 | exports: 'auto', 61 | format: 'cjs', 62 | }), 63 | ], 64 | } 65 | ]; 66 | -------------------------------------------------------------------------------- /rollup.config2.js: -------------------------------------------------------------------------------- 1 | import { resolve } from 'path'; 2 | import { monolithConf } from './rollup.common.js'; 3 | 4 | var sharedInput = './underscore-node-f-pre.js'; 5 | var sharedOutput = './underscore-node-f.cjs'; 6 | 7 | export default [ 8 | // ESM entry point for Node.js 12+. 9 | { 10 | input: 'underscore-node-mjs-pre.js', 11 | external: sharedInput, 12 | output: monolithConf({ 13 | file: 'underscore-node.mjs', 14 | format: 'esm', 15 | paths: { 16 | [resolve(__dirname, sharedInput)]: sharedOutput, 17 | }, 18 | }), 19 | }, 20 | // CJS entry point for Node.js 12+, plus code shared with the ESM entry. 21 | { 22 | input: { 23 | 'underscore-node-f': sharedInput, 24 | 'underscore-node': 'underscore-node-cjs-pre.js', 25 | }, 26 | preserveModules: true, 27 | output: monolithConf({ 28 | entryFileNames: '[name].cjs', 29 | dir: '.', 30 | exports: 'auto', 31 | format: 'cjs', 32 | }), 33 | }, 34 | ]; 35 | -------------------------------------------------------------------------------- /test-treeshake/map.js: -------------------------------------------------------------------------------- 1 | export { default as map } from '../modules/map.js'; 2 | -------------------------------------------------------------------------------- /test-treeshake/rollup.config.js: -------------------------------------------------------------------------------- 1 | module.exports = [{ 2 | input: 'map.js', 3 | output: { 4 | file: 'map-umd.js', 5 | format: 'umd', 6 | name: 'map', 7 | }, 8 | }, { 9 | input: 'template.js', 10 | output: { 11 | file: 'template-umd.js', 12 | format: 'umd', 13 | name: 'template', 14 | }, 15 | }]; 16 | -------------------------------------------------------------------------------- /test-treeshake/template.js: -------------------------------------------------------------------------------- 1 | export { template } from '../modules/index-all.js'; 2 | -------------------------------------------------------------------------------- /test/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "browser": true 4 | }, 5 | "parserOptions": {}, 6 | "globals": { 7 | "QUnit": false 8 | }, 9 | "rules": { 10 | "brace-style": 0, 11 | "no-new-wrappers": 0, 12 | "no-extend-native": 0 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /test/chaining.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | var _ = typeof require == 'function' ? require('..') : window._; 3 | 4 | QUnit.module('Chaining'); 5 | 6 | QUnit.test('map/flatten/reduce', function(assert) { 7 | var lyrics = [ 8 | 'I\'m a lumberjack and I\'m okay', 9 | 'I sleep all night and I work all day', 10 | 'He\'s a lumberjack and he\'s okay', 11 | 'He sleeps all night and he works all day' 12 | ]; 13 | var counts = _(lyrics).chain() 14 | .map(function(line) { return line.split(''); }) 15 | .flatten() 16 | .reduce(function(hash, l) { 17 | hash[l] = hash[l] || 0; 18 | hash[l]++; 19 | return hash; 20 | }, {}) 21 | .value(); 22 | assert.strictEqual(counts.a, 16, 'counted all the letters in the song'); 23 | assert.strictEqual(counts.e, 10, 'counted all the letters in the song'); 24 | }); 25 | 26 | QUnit.test('select/reject/sortBy', function(assert) { 27 | var numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; 28 | numbers = _(numbers).chain().select(function(n) { 29 | return n % 2 === 0; 30 | }).reject(function(n) { 31 | return n % 4 === 0; 32 | }).sortBy(function(n) { 33 | return -n; 34 | }).value(); 35 | assert.deepEqual(numbers, [10, 6, 2], 'filtered and reversed the numbers'); 36 | }); 37 | 38 | QUnit.test('select/reject/sortBy in functional style', function(assert) { 39 | var numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; 40 | numbers = _.chain(numbers).select(function(n) { 41 | return n % 2 === 0; 42 | }).reject(function(n) { 43 | return n % 4 === 0; 44 | }).sortBy(function(n) { 45 | return -n; 46 | }).value(); 47 | assert.deepEqual(numbers, [10, 6, 2], 'filtered and reversed the numbers'); 48 | }); 49 | 50 | QUnit.test('reverse/concat/unshift/pop/map', function(assert) { 51 | var numbers = [1, 2, 3, 4, 5]; 52 | numbers = _(numbers).chain() 53 | .reverse() 54 | .concat([5, 5, 5]) 55 | .unshift(17) 56 | .pop() 57 | .map(function(n){ return n * 2; }) 58 | .value(); 59 | assert.deepEqual(numbers, [34, 10, 8, 6, 4, 2, 10, 10], 'can chain together array functions.'); 60 | }); 61 | 62 | QUnit.test('splice', function(assert) { 63 | var instance = _([1, 2, 3, 4, 5]).chain(); 64 | assert.deepEqual(instance.splice(1, 3).value(), [1, 5]); 65 | assert.deepEqual(instance.splice(1, 0).value(), [1, 5]); 66 | assert.deepEqual(instance.splice(1, 1).value(), [1]); 67 | assert.deepEqual(instance.splice(0, 1).value(), [], '#397 Can create empty array'); 68 | }); 69 | 70 | QUnit.test('shift', function(assert) { 71 | var instance = _([1, 2, 3]).chain(); 72 | assert.deepEqual(instance.shift().value(), [2, 3]); 73 | assert.deepEqual(instance.shift().value(), [3]); 74 | assert.deepEqual(instance.shift().value(), [], '#397 Can create empty array'); 75 | }); 76 | 77 | QUnit.test('pop', function(assert) { 78 | var instance = _([1, 2, 3]).chain(); 79 | assert.deepEqual(instance.pop().value(), [1, 2]); 80 | assert.deepEqual(instance.pop().value(), [1]); 81 | assert.deepEqual(instance.pop().value(), [], '#397 Can create empty array'); 82 | }); 83 | 84 | QUnit.test('chaining works in small stages', function(assert) { 85 | var o = _([1, 2, 3, 4]).chain(); 86 | assert.deepEqual(o.filter(function(i) { return i < 3; }).value(), [1, 2]); 87 | assert.deepEqual(o.filter(function(i) { return i > 2; }).value(), [3, 4]); 88 | }); 89 | 90 | QUnit.test('#1562: Engine proxies for chained functions', function(assert) { 91 | var wrapped = _(512); 92 | assert.strictEqual(wrapped.toJSON(), 512); 93 | assert.strictEqual(wrapped.valueOf(), 512); 94 | assert.strictEqual(+wrapped, 512); 95 | assert.strictEqual(wrapped.toString(), '512'); 96 | assert.strictEqual('' + wrapped, '512'); 97 | }); 98 | 99 | QUnit.test('wrapper methods handle undefined and null', function(assert) { 100 | var w1 = _(), w2 = _(null); 101 | _.each([w1, w2], function(wrapped) { 102 | assert.equal(wrapped.extend({a: 1}), void 0); 103 | assert.equal(wrapped.first(), void 0); 104 | assert.equal(wrapped.push(1), void 0); 105 | assert.equal(wrapped.concat([1]), void 0); 106 | }); 107 | }); 108 | 109 | }()); 110 | -------------------------------------------------------------------------------- /test/cross-document.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | if (typeof document == 'undefined') return; 3 | 4 | var _ = typeof require == 'function' ? require('..') : window._; 5 | 6 | QUnit.module('Cross Document'); 7 | /* global iObject, iElement, iArguments, iFunction, iArray, iError, iString, iNumber, iBoolean, iDate, iRegExp, iNaN, iNull, iUndefined, ActiveXObject */ 8 | 9 | // Setup remote variables for iFrame tests. 10 | var iframe = document.createElement('iframe'); 11 | iframe.frameBorder = iframe.height = iframe.width = 0; 12 | document.body.appendChild(iframe); 13 | var iframeContent = iframe.contentDocument || iframe.contentWindow; 14 | var iDoc = iframeContent.document || iframeContent; 15 | iDoc.write( 16 | [ 17 | '' 33 | ].join('\n') 34 | ); 35 | iDoc.close(); 36 | 37 | QUnit.test('isEqual', function(assert) { 38 | 39 | assert.ok(!_.isEqual(iNumber, 101)); 40 | assert.ok(_.isEqual(iNumber, 100)); 41 | 42 | // Objects from another frame. 43 | assert.ok(_.isEqual({}, iObject), 'Objects with equivalent members created in different documents are equal'); 44 | 45 | // Array from another frame. 46 | assert.ok(_.isEqual([1, 2, 3], iArray), 'Arrays with equivalent elements created in different documents are equal'); 47 | }); 48 | 49 | QUnit.test('isEmpty', function(assert) { 50 | assert.ok(!_([iNumber]).isEmpty(), '[1] is not empty'); 51 | assert.ok(!_.isEmpty(iArray), '[] is empty'); 52 | assert.ok(_.isEmpty(iObject), '{} is empty'); 53 | }); 54 | 55 | QUnit.test('isElement', function(assert) { 56 | assert.ok(!_.isElement('div'), 'strings are not dom elements'); 57 | assert.ok(_.isElement(document.body), 'the body tag is a DOM element'); 58 | assert.ok(_.isElement(iElement), 'even from another frame'); 59 | }); 60 | 61 | QUnit.test('isArguments', function(assert) { 62 | assert.ok(_.isArguments(iArguments), 'even from another frame'); 63 | }); 64 | 65 | QUnit.test('isObject', function(assert) { 66 | assert.ok(_.isObject(iElement), 'even from another frame'); 67 | assert.ok(_.isObject(iFunction), 'even from another frame'); 68 | }); 69 | 70 | QUnit.test('isArray', function(assert) { 71 | assert.ok(_.isArray(iArray), 'even from another frame'); 72 | }); 73 | 74 | QUnit.test('isString', function(assert) { 75 | assert.ok(_.isString(iString), 'even from another frame'); 76 | }); 77 | 78 | QUnit.test('isNumber', function(assert) { 79 | assert.ok(_.isNumber(iNumber), 'even from another frame'); 80 | }); 81 | 82 | QUnit.test('isBoolean', function(assert) { 83 | assert.ok(_.isBoolean(iBoolean), 'even from another frame'); 84 | }); 85 | 86 | QUnit.test('isFunction', function(assert) { 87 | assert.ok(_.isFunction(iFunction), 'even from another frame'); 88 | }); 89 | 90 | QUnit.test('isDate', function(assert) { 91 | assert.ok(_.isDate(iDate), 'even from another frame'); 92 | }); 93 | 94 | QUnit.test('isRegExp', function(assert) { 95 | assert.ok(_.isRegExp(iRegExp), 'even from another frame'); 96 | }); 97 | 98 | QUnit.test('isNaN', function(assert) { 99 | assert.ok(_.isNaN(iNaN), 'even from another frame'); 100 | }); 101 | 102 | QUnit.test('isNull', function(assert) { 103 | assert.ok(_.isNull(iNull), 'even from another frame'); 104 | }); 105 | 106 | QUnit.test('isUndefined', function(assert) { 107 | assert.ok(_.isUndefined(iUndefined), 'even from another frame'); 108 | }); 109 | 110 | QUnit.test('isError', function(assert) { 111 | assert.ok(_.isError(iError), 'even from another frame'); 112 | }); 113 | 114 | if (typeof ActiveXObject != 'undefined') { 115 | QUnit.test('IE host objects', function(assert) { 116 | var xml = new ActiveXObject('Msxml2.DOMDocument.3.0'); 117 | assert.ok(!_.isNumber(xml)); 118 | assert.ok(!_.isBoolean(xml)); 119 | assert.ok(!_.isNaN(xml)); 120 | assert.ok(!_.isFunction(xml)); 121 | assert.ok(!_.isNull(xml)); 122 | assert.ok(!_.isUndefined(xml)); 123 | }); 124 | 125 | QUnit.test('#1621 IE 11 compat mode DOM elements are not functions', function(assert) { 126 | var fn = function() {}; 127 | var xml = new ActiveXObject('Msxml2.DOMDocument.3.0'); 128 | var div = document.createElement('div'); 129 | 130 | // JIT the function 131 | var count = 200; 132 | while (count--) { 133 | _.isFunction(fn); 134 | } 135 | 136 | assert.strictEqual(_.isFunction(xml), false); 137 | assert.strictEqual(_.isFunction(div), false); 138 | assert.strictEqual(_.isFunction(fn), true); 139 | }); 140 | } 141 | 142 | }()); 143 | -------------------------------------------------------------------------------- /test/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Underscore Test Suite 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /test/overrides.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | function overrideDataView() { 3 | NativeDataView = DataView; 4 | DataView = {}; 5 | } 6 | 7 | // Only override browser functions roughly 1/3rd of the time 8 | var runOverrides = Math.floor(Math.random() * 3) === 0; 9 | if (runOverrides) { 10 | overrideDataView(); 11 | } 12 | })(); 13 | -------------------------------------------------------------------------------- /test/qunit-setup.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | QUnit.config.noglobals = true; 3 | }()); 4 | -------------------------------------------------------------------------------- /test/treeshake.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | // Tests in this module only work in the node.js environment. 3 | if (typeof require !== 'function') return; 4 | 5 | var fixturePrefix = __dirname + '/../test-treeshake/'; 6 | var moduleName = __dirname + '/../underscore-umd.js'; 7 | var fs = require('fs'); 8 | 9 | QUnit.module('Tree-shaking'); 10 | 11 | QUnit.test('should have an effect', function(assert) { 12 | var done = assert.async(); 13 | var fixtureName = fixturePrefix + 'map-umd.js'; 14 | fs.stat(moduleName, function(error, moduleStats) { 15 | assert.equal(error, null); 16 | if (error) return done(); 17 | fs.stat(fixtureName, function(error, fixtureStats) { 18 | assert.equal(error, null); 19 | if (error) return done(); 20 | // _.template depends on the entire underscore object, so all of the 21 | // source code should be included. 22 | assert.ok(fixtureStats.size < moduleStats.size); 23 | done(); 24 | }); 25 | }); 26 | }); 27 | 28 | QUnit.test('should not be overzealous', function(assert) { 29 | var done = assert.async(); 30 | var fixtureName = fixturePrefix + 'template-umd.js'; 31 | fs.readFile(moduleName, {encoding: 'utf8'}, function(error, moduleData) { 32 | assert.equal(error, null); 33 | if (error) return done(); 34 | fs.readFile(fixtureName, {encoding: 'utf8'}, function(error, fixtureData) { 35 | assert.equal(error, null); 36 | if (error) return done(); 37 | var moduleLines = moduleData.split('\n').length, 38 | fixtureLines = fixtureData.split('\n').length; 39 | // _.template depends on the entire underscore object, so all of the 40 | // source code should be included. Allowing for up to 9 lines of 41 | // difference; this is the size of the noConflict logic plus the 42 | // copyright intro, both of which are present in the official module but 43 | // not in the fixture. 44 | assert.ok(moduleLines - fixtureLines <= 9); 45 | done(); 46 | }); 47 | }); 48 | }); 49 | }()); 50 | -------------------------------------------------------------------------------- /test/vendor/qunit.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * QUnit 2.10.1 3 | * https://qunitjs.com/ 4 | * 5 | * Copyright jQuery Foundation and other contributors 6 | * Released under the MIT license 7 | * https://jquery.org/license 8 | * 9 | * Date: 2020-07-04T23:21Z 10 | */ 11 | 12 | /** Font Family and Sizes */ 13 | 14 | /* Style our buttons in a simple way, uninfluenced by the styles 15 | the tested app might load. Don't affect buttons in #qunit-fixture! 16 | https://github.com/qunitjs/qunit/pull/1395 17 | https://github.com/qunitjs/qunit/issues/1437 */ 18 | #qunit-testrunner-toolbar button, 19 | #qunit-testresult button { 20 | font-size: initial; 21 | border: initial; 22 | background-color: buttonface; 23 | } 24 | 25 | #qunit-tests, #qunit-header, #qunit-banner, #qunit-testrunner-toolbar, #qunit-filteredTest, #qunit-userAgent, #qunit-testresult { 26 | font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial, sans-serif; 27 | } 28 | 29 | #qunit-testrunner-toolbar, #qunit-filteredTest, #qunit-userAgent, #qunit-testresult, #qunit-tests li { font-size: small; } 30 | #qunit-tests { font-size: smaller; } 31 | 32 | 33 | /** Resets */ 34 | 35 | #qunit-tests, #qunit-header, #qunit-banner, #qunit-filteredTest, #qunit-userAgent, #qunit-testresult, #qunit-modulefilter { 36 | margin: 0; 37 | padding: 0; 38 | } 39 | 40 | 41 | /** Header (excluding toolbar) */ 42 | 43 | #qunit-header { 44 | padding: 0.5em 0 0.5em 1em; 45 | 46 | color: #8699A4; 47 | background-color: #0D3349; 48 | 49 | font-size: 1.5em; 50 | line-height: 1em; 51 | font-weight: 400; 52 | 53 | border-radius: 5px 5px 0 0; 54 | } 55 | 56 | #qunit-header a { 57 | text-decoration: none; 58 | color: #C2CCD1; 59 | } 60 | 61 | #qunit-header a:hover, 62 | #qunit-header a:focus { 63 | color: #FFF; 64 | } 65 | 66 | #qunit-banner { 67 | height: 5px; 68 | } 69 | 70 | #qunit-filteredTest { 71 | padding: 0.5em 1em 0.5em 1em; 72 | color: #366097; 73 | background-color: #F4FF77; 74 | } 75 | 76 | #qunit-userAgent { 77 | padding: 0.5em 1em 0.5em 1em; 78 | color: #FFF; 79 | background-color: #2B81AF; 80 | text-shadow: rgba(0, 0, 0, 0.5) 2px 2px 1px; 81 | } 82 | 83 | 84 | /** Toolbar */ 85 | 86 | #qunit-testrunner-toolbar { 87 | padding: 0.5em 1em 0.5em 1em; 88 | color: #5E740B; 89 | background-color: #EEE; 90 | } 91 | 92 | #qunit-testrunner-toolbar .clearfix { 93 | height: 0; 94 | clear: both; 95 | } 96 | 97 | #qunit-testrunner-toolbar label { 98 | display: inline-block; 99 | } 100 | 101 | #qunit-testrunner-toolbar input[type=checkbox], 102 | #qunit-testrunner-toolbar input[type=radio] { 103 | margin: 3px; 104 | vertical-align: -2px; 105 | } 106 | 107 | #qunit-testrunner-toolbar input[type=text] { 108 | box-sizing: border-box; 109 | height: 1.6em; 110 | } 111 | 112 | #qunit-toolbar-filters { 113 | float: right; 114 | } 115 | 116 | .qunit-url-config, 117 | .qunit-filter, 118 | #qunit-modulefilter { 119 | display: inline-block; 120 | line-height: 2.1em; 121 | } 122 | 123 | .qunit-filter, 124 | #qunit-modulefilter { 125 | position: relative; 126 | margin-left: 1em; 127 | } 128 | 129 | .qunit-url-config label { 130 | margin-right: 0.5em; 131 | } 132 | 133 | #qunit-modulefilter-search { 134 | box-sizing: border-box; 135 | min-width: 400px; 136 | } 137 | 138 | #qunit-modulefilter-search-container:after { 139 | position: absolute; 140 | right: 0.3em; 141 | content: "\25bc"; 142 | color: black; 143 | } 144 | 145 | #qunit-modulefilter-dropdown { 146 | /* align with #qunit-modulefilter-search */ 147 | box-sizing: border-box; 148 | min-width: 400px; 149 | position: absolute; 150 | right: 0; 151 | top: 50%; 152 | margin-top: 0.8em; 153 | 154 | border: 1px solid #D3D3D3; 155 | border-top: none; 156 | border-radius: 0 0 .25em .25em; 157 | color: #000; 158 | background-color: #F5F5F5; 159 | z-index: 99; 160 | } 161 | 162 | #qunit-modulefilter-dropdown a { 163 | color: inherit; 164 | text-decoration: none; 165 | } 166 | 167 | #qunit-modulefilter-dropdown .clickable.checked { 168 | font-weight: bold; 169 | color: #000; 170 | background-color: #D2E0E6; 171 | } 172 | 173 | #qunit-modulefilter-dropdown .clickable:hover { 174 | color: #FFF; 175 | background-color: #0D3349; 176 | } 177 | 178 | #qunit-modulefilter-actions { 179 | display: block; 180 | overflow: auto; 181 | 182 | /* align with #qunit-modulefilter-dropdown-list */ 183 | font: smaller/1.5em sans-serif; 184 | } 185 | 186 | #qunit-modulefilter-dropdown #qunit-modulefilter-actions > * { 187 | box-sizing: border-box; 188 | max-height: 2.8em; 189 | display: block; 190 | padding: 0.4em; 191 | } 192 | 193 | #qunit-modulefilter-dropdown #qunit-modulefilter-actions > button { 194 | float: right; 195 | font: inherit; 196 | } 197 | 198 | #qunit-modulefilter-dropdown #qunit-modulefilter-actions > :last-child { 199 | /* insert padding to align with checkbox margins */ 200 | padding-left: 3px; 201 | } 202 | 203 | #qunit-modulefilter-dropdown-list { 204 | max-height: 200px; 205 | overflow-y: auto; 206 | margin: 0; 207 | border-top: 2px groove threedhighlight; 208 | padding: 0.4em 0 0; 209 | font: smaller/1.5em sans-serif; 210 | } 211 | 212 | #qunit-modulefilter-dropdown-list li { 213 | white-space: nowrap; 214 | overflow: hidden; 215 | text-overflow: ellipsis; 216 | } 217 | 218 | #qunit-modulefilter-dropdown-list .clickable { 219 | display: block; 220 | padding-left: 0.15em; 221 | padding-right: 0.5em; 222 | } 223 | 224 | 225 | /** Tests: Pass/Fail */ 226 | 227 | #qunit-tests { 228 | list-style-position: inside; 229 | } 230 | 231 | #qunit-tests li { 232 | padding: 0.4em 1em 0.4em 1em; 233 | border-bottom: 1px solid #FFF; 234 | list-style-position: inside; 235 | } 236 | 237 | #qunit-tests > li { 238 | display: none; 239 | } 240 | 241 | #qunit-tests li.running, 242 | #qunit-tests li.pass, 243 | #qunit-tests li.fail, 244 | #qunit-tests li.skipped, 245 | #qunit-tests li.aborted { 246 | display: list-item; 247 | } 248 | 249 | #qunit-tests.hidepass { 250 | position: relative; 251 | } 252 | 253 | #qunit-tests.hidepass li.running, 254 | #qunit-tests.hidepass li.pass:not(.todo) { 255 | visibility: hidden; 256 | position: absolute; 257 | width: 0; 258 | height: 0; 259 | padding: 0; 260 | border: 0; 261 | margin: 0; 262 | } 263 | 264 | #qunit-tests li strong { 265 | cursor: pointer; 266 | } 267 | 268 | #qunit-tests li.skipped strong { 269 | cursor: default; 270 | } 271 | 272 | #qunit-tests li a { 273 | padding: 0.5em; 274 | color: #C2CCD1; 275 | text-decoration: none; 276 | } 277 | 278 | #qunit-tests li p a { 279 | padding: 0.25em; 280 | color: #6B6464; 281 | } 282 | #qunit-tests li a:hover, 283 | #qunit-tests li a:focus { 284 | color: #000; 285 | } 286 | 287 | #qunit-tests li .runtime { 288 | float: right; 289 | font-size: smaller; 290 | } 291 | 292 | .qunit-assert-list { 293 | margin-top: 0.5em; 294 | padding: 0.5em; 295 | 296 | background-color: #FFF; 297 | 298 | border-radius: 5px; 299 | } 300 | 301 | .qunit-source { 302 | margin: 0.6em 0 0.3em; 303 | } 304 | 305 | .qunit-collapsed { 306 | display: none; 307 | } 308 | 309 | #qunit-tests table { 310 | border-collapse: collapse; 311 | margin-top: 0.2em; 312 | } 313 | 314 | #qunit-tests th { 315 | text-align: right; 316 | vertical-align: top; 317 | padding: 0 0.5em 0 0; 318 | } 319 | 320 | #qunit-tests td { 321 | vertical-align: top; 322 | } 323 | 324 | #qunit-tests pre { 325 | margin: 0; 326 | white-space: pre-wrap; 327 | word-wrap: break-word; 328 | } 329 | 330 | #qunit-tests del { 331 | color: #374E0C; 332 | background-color: #E0F2BE; 333 | text-decoration: none; 334 | } 335 | 336 | #qunit-tests ins { 337 | color: #500; 338 | background-color: #FFCACA; 339 | text-decoration: none; 340 | } 341 | 342 | /*** Test Counts */ 343 | 344 | #qunit-tests b.counts { color: #000; } 345 | #qunit-tests b.passed { color: #5E740B; } 346 | #qunit-tests b.failed { color: #710909; } 347 | 348 | #qunit-tests li li { 349 | padding: 5px; 350 | background-color: #FFF; 351 | border-bottom: none; 352 | list-style-position: inside; 353 | } 354 | 355 | /*** Passing Styles */ 356 | 357 | #qunit-tests li li.pass { 358 | color: #3C510C; 359 | background-color: #FFF; 360 | border-left: 10px solid #C6E746; 361 | } 362 | 363 | #qunit-tests .pass { color: #528CE0; background-color: #D2E0E6; } 364 | #qunit-tests .pass .test-name { color: #366097; } 365 | 366 | #qunit-tests .pass .test-actual, 367 | #qunit-tests .pass .test-expected { color: #999; } 368 | 369 | #qunit-banner.qunit-pass { background-color: #C6E746; } 370 | 371 | /*** Failing Styles */ 372 | 373 | #qunit-tests li li.fail { 374 | color: #710909; 375 | background-color: #FFF; 376 | border-left: 10px solid #EE5757; 377 | white-space: pre; 378 | } 379 | 380 | #qunit-tests > li:last-child { 381 | border-radius: 0 0 5px 5px; 382 | } 383 | 384 | #qunit-tests .fail { color: #000; background-color: #EE5757; } 385 | #qunit-tests .fail .test-name, 386 | #qunit-tests .fail .module-name { color: #000; } 387 | 388 | #qunit-tests .fail .test-actual { color: #EE5757; } 389 | #qunit-tests .fail .test-expected { color: #008000; } 390 | 391 | #qunit-banner.qunit-fail { background-color: #EE5757; } 392 | 393 | 394 | /*** Aborted tests */ 395 | #qunit-tests .aborted { color: #000; background-color: orange; } 396 | /*** Skipped tests */ 397 | 398 | #qunit-tests .skipped { 399 | background-color: #EBECE9; 400 | } 401 | 402 | #qunit-tests .qunit-todo-label, 403 | #qunit-tests .qunit-skipped-label { 404 | background-color: #F4FF77; 405 | display: inline-block; 406 | font-style: normal; 407 | color: #366097; 408 | line-height: 1.8em; 409 | padding: 0 0.5em; 410 | margin: -0.4em 0.4em -0.4em 0; 411 | } 412 | 413 | #qunit-tests .qunit-todo-label { 414 | background-color: #EEE; 415 | } 416 | 417 | /** Result */ 418 | 419 | #qunit-testresult { 420 | color: #2B81AF; 421 | background-color: #D2E0E6; 422 | 423 | border-bottom: 1px solid #FFF; 424 | } 425 | #qunit-testresult .clearfix { 426 | height: 0; 427 | clear: both; 428 | } 429 | #qunit-testresult .module-name { 430 | font-weight: 700; 431 | } 432 | #qunit-testresult-display { 433 | padding: 0.5em 1em 0.5em 1em; 434 | width: 85%; 435 | float:left; 436 | } 437 | #qunit-testresult-controls { 438 | padding: 0.5em 1em 0.5em 1em; 439 | width: 10%; 440 | float:left; 441 | } 442 | 443 | /** Fixture */ 444 | 445 | #qunit-fixture { 446 | position: absolute; 447 | top: -10000px; 448 | left: -10000px; 449 | width: 1000px; 450 | height: 1000px; 451 | } 452 | -------------------------------------------------------------------------------- /underscore-min.js: -------------------------------------------------------------------------------- 1 | !function(n,r){"object"==typeof exports&&"undefined"!=typeof module?module.exports=r():"function"==typeof define&&define.amd?define("underscore",r):(n="undefined"!=typeof globalThis?globalThis:n||self,function(){var t=n._,e=n._=r();e.noConflict=function(){return n._=t,e}}())}(this,(function(){ 2 | // Underscore.js 1.13.7 3 | // https://underscorejs.org 4 | // (c) 2009-2024 Jeremy Ashkenas, Julian Gonggrijp, and DocumentCloud and Investigative Reporters & Editors 5 | // Underscore may be freely distributed under the MIT license. 6 | var n="1.13.7",r="object"==typeof self&&self.self===self&&self||"object"==typeof global&&global.global===global&&global||Function("return this")()||{},t=Array.prototype,e=Object.prototype,u="undefined"!=typeof Symbol?Symbol.prototype:null,i=t.push,o=t.slice,a=e.toString,f=e.hasOwnProperty,c="undefined"!=typeof ArrayBuffer,l="undefined"!=typeof DataView,s=Array.isArray,p=Object.keys,v=Object.create,h=c&&ArrayBuffer.isView,y=isNaN,d=isFinite,g=!{toString:null}.propertyIsEnumerable("toString"),b=["valueOf","isPrototypeOf","toString","propertyIsEnumerable","hasOwnProperty","toLocaleString"],m=Math.pow(2,53)-1;function j(n,r){return r=null==r?n.length-1:+r,function(){for(var t=Math.max(arguments.length-r,0),e=Array(t),u=0;u=0&&t<=m}}function J(n){return function(r){return null==r?void 0:r[n]}}var G=J("byteLength"),H=K(G),Q=/\[object ((I|Ui)nt(8|16|32)|Float(32|64)|Uint8Clamped|Big(I|Ui)nt64)Array\]/;var X=c?function(n){return h?h(n)&&!q(n):H(n)&&Q.test(a.call(n))}:C(!1),Y=J("length");function Z(n,r){r=function(n){for(var r={},t=n.length,e=0;e":">",'"':""","'":"'","`":"`"},$n=zn(Ln),Cn=zn(wn(Ln)),Kn=tn.templateSettings={evaluate:/<%([\s\S]+?)%>/g,interpolate:/<%=([\s\S]+?)%>/g,escape:/<%-([\s\S]+?)%>/g},Jn=/(.)^/,Gn={"'":"'","\\":"\\","\r":"r","\n":"n","\u2028":"u2028","\u2029":"u2029"},Hn=/\\|'|\r|\n|\u2028|\u2029/g;function Qn(n){return"\\"+Gn[n]}var Xn=/^\s*(\w|\$)+\s*$/;var Yn=0;function Zn(n,r,t,e,u){if(!(e instanceof r))return n.apply(t,u);var i=Mn(n.prototype),o=n.apply(i,u);return w(o)?o:i}var nr=j((function(n,r){var t=nr.placeholder,e=function(){for(var u=0,i=r.length,o=Array(i),a=0;a1)er(a,r-1,t,e),u=e.length;else for(var f=0,c=a.length;f0&&(t=r.apply(this,arguments)),n<=1&&(r=null),t}}var cr=nr(fr,2);function lr(n,r,t){r=Pn(r,t);for(var e,u=nn(n),i=0,o=u.length;i0?0:u-1;i>=0&&i0?a=i>=0?i:Math.max(i+f,a):f=i>=0?Math.min(i+1,f):i+f+1;else if(t&&i&&f)return e[i=t(e,u)]===u?i:-1;if(u!=u)return(i=r(o.call(e,a,f),$))>=0?i+a:-1;for(i=n>0?a:f-1;i>=0&&i0?0:o-1;for(u||(e=r[i?i[a]:a],a+=n);a>=0&&a=3;return r(n,Rn(t,u,4),e,i)}}var _r=wr(1),Ar=wr(-1);function xr(n,r,t){var e=[];return r=Pn(r,t),mr(n,(function(n,t,u){r(n,t,u)&&e.push(n)})),e}function Sr(n,r,t){r=Pn(r,t);for(var e=!tr(n)&&nn(n),u=(e||n).length,i=0;i=0}var Er=j((function(n,r,t){var e,u;return D(r)?u=r:(r=Bn(r),e=r.slice(0,-1),r=r[r.length-1]),jr(n,(function(n){var i=u;if(!i){if(e&&e.length&&(n=Nn(n,e)),null==n)return;i=n[r]}return null==i?i:i.apply(n,t)}))}));function Br(n,r){return jr(n,Dn(r))}function Nr(n,r,t){var e,u,i=-1/0,o=-1/0;if(null==r||"number"==typeof r&&"object"!=typeof n[0]&&null!=n)for(var a=0,f=(n=tr(n)?n:jn(n)).length;ai&&(i=e);else r=Pn(r,t),mr(n,(function(n,t,e){((u=r(n,t,e))>o||u===-1/0&&i===-1/0)&&(i=n,o=u)}));return i}var Ir=/[^\ud800-\udfff]|[\ud800-\udbff][\udc00-\udfff]|[\ud800-\udfff]/g;function Tr(n){return n?U(n)?o.call(n):S(n)?n.match(Ir):tr(n)?jr(n,Tn):jn(n):[]}function kr(n,r,t){if(null==r||t)return tr(n)||(n=jn(n)),n[Un(n.length-1)];var e=Tr(n),u=Y(e);r=Math.max(Math.min(r,u),0);for(var i=u-1,o=0;o1&&(e=Rn(e,r[1])),r=an(n)):(e=qr,r=er(r,!1,!1),n=Object(n));for(var u=0,i=r.length;u1&&(t=r[1])):(r=jr(er(r,!1,!1),String),e=function(n,t){return!Mr(r,t)}),Ur(n,e,t)}));function zr(n,r,t){return o.call(n,0,Math.max(0,n.length-(null==r||t?1:r)))}function Lr(n,r,t){return null==n||n.length<1?null==r||t?void 0:[]:null==r||t?n[0]:zr(n,n.length-r)}function $r(n,r,t){return o.call(n,null==r||t?1:r)}var Cr=j((function(n,r){return r=er(r,!0,!0),xr(n,(function(n){return!Mr(r,n)}))})),Kr=j((function(n,r){return Cr(n,r)}));function Jr(n,r,t,e){A(r)||(e=t,t=r,r=!1),null!=t&&(t=Pn(t,e));for(var u=[],i=[],o=0,a=Y(n);or?(e&&(clearTimeout(e),e=null),a=c,o=n.apply(u,i),e||(u=i=null)):e||!1===t.trailing||(e=setTimeout(f,l)),o};return c.cancel=function(){clearTimeout(e),a=0,e=u=i=null},c},debounce:function(n,r,t){var e,u,i,o,a,f=function(){var c=Wn()-u;r>c?e=setTimeout(f,r-c):(e=null,t||(o=n.apply(a,i)),e||(i=a=null))},c=j((function(c){return a=this,i=c,u=Wn(),e||(e=setTimeout(f,r),t&&(o=n.apply(a,i))),o}));return c.cancel=function(){clearTimeout(e),e=i=a=null},c},wrap:function(n,r){return nr(r,n)},negate:ar,compose:function(){var n=arguments,r=n.length-1;return function(){for(var t=r,e=n[r].apply(this,arguments);t--;)e=n[t].call(this,e);return e}},after:function(n,r){return function(){if(--n<1)return r.apply(this,arguments)}},before:fr,once:cr,findKey:lr,findIndex:pr,findLastIndex:vr,sortedIndex:hr,indexOf:dr,lastIndexOf:gr,find:br,detect:br,findWhere:function(n,r){return br(n,kn(r))},each:mr,forEach:mr,map:jr,collect:jr,reduce:_r,foldl:_r,inject:_r,reduceRight:Ar,foldr:Ar,filter:xr,select:xr,reject:function(n,r,t){return xr(n,ar(Pn(r)),t)},every:Sr,all:Sr,some:Or,any:Or,contains:Mr,includes:Mr,include:Mr,invoke:Er,pluck:Br,where:function(n,r){return xr(n,kn(r))},max:Nr,min:function(n,r,t){var e,u,i=1/0,o=1/0;if(null==r||"number"==typeof r&&"object"!=typeof n[0]&&null!=n)for(var a=0,f=(n=tr(n)?n:jn(n)).length;ae||void 0===t)return 1;if(t